- name: dist-x86_64-linux
os: ubuntu-latest-xl
env: {}
- - name: dist-x86_64-linux-alt
- env:
- IMAGE: dist-x86_64-linux
- os: ubuntu-latest-xl
timeout-minutes: 600
runs-on: "${{ matrix.os }}"
steps:
env:
DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
os: ubuntu-latest-xl
- - name: dist-x86_64-apple
- env:
- SCRIPT: "./x.py dist"
- RUST_CONFIGURE_ARGS: "--target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc"
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- DIST_REQUIRE_ALL_TOOLS: 1
- os: macos-latest
- - name: dist-x86_64-apple-alt
- env:
- SCRIPT: "./x.py dist"
- RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc"
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- os: macos-latest
- - name: x86_64-apple
- env:
- SCRIPT: "./x.py test"
- RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc"
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.8
- MACOSX_STD_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- os: macos-latest
- name: x86_64-msvc-1
env:
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
+ auto-fallible:
+ name: auto-fallible
+ env:
+ CI_JOB_NAME: "${{ matrix.name }}"
+ SCCACHE_BUCKET: rust-lang-gha-caches
+ DEPLOY_BUCKET: rust-lang-gha
+ TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
+ TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues"
+ TOOLSTATE_PUBLISH: 1
+ CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
+ ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
+ CACHE_DOMAIN: ci-caches-gha.rust-lang.org
+ if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'"
+ strategy:
+ matrix:
+ include:
+ - name: dist-x86_64-apple
+ env:
+ SCRIPT: "./x.py dist"
+ RUST_CONFIGURE_ARGS: "--target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ DIST_REQUIRE_ALL_TOOLS: 1
+ os: macos-latest
+ - name: dist-x86_64-apple-alt
+ env:
+ SCRIPT: "./x.py dist"
+ RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ os: macos-latest
+ - name: x86_64-apple
+ env:
+ SCRIPT: "./x.py test"
+ RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.8
+ MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ os: macos-latest
+ timeout-minutes: 600
+ runs-on: "${{ matrix.os }}"
+ steps:
+ - name: disable git crlf conversion
+ run: git config --global core.autocrlf false
+ shell: bash
+ - name: checkout the source code
+ uses: actions/checkout@v1
+ with:
+ fetch-depth: 2
+ - name: configure GitHub Actions to kill the build when outdated
+ uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
+ with:
+ github_token: "${{ secrets.github_token }}"
+ if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+ - name: add extra environment variables
+ run: src/ci/scripts/setup-environment.sh
+ env:
+ EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
+ if: success() && !env.SKIP_JOB
+ - name: decide whether to skip this job
+ run: src/ci/scripts/should-skip-this.sh
+ if: success() && !env.SKIP_JOB
+ - name: collect CPU statistics
+ run: src/ci/scripts/collect-cpu-stats.sh
+ if: success() && !env.SKIP_JOB
+ - name: show the current environment
+ run: src/ci/scripts/dump-environment.sh
+ if: success() && !env.SKIP_JOB
+ - name: install awscli
+ run: src/ci/scripts/install-awscli.sh
+ if: success() && !env.SKIP_JOB
+ - name: install sccache
+ run: src/ci/scripts/install-sccache.sh
+ if: success() && !env.SKIP_JOB
+ - name: install clang
+ run: src/ci/scripts/install-clang.sh
+ if: success() && !env.SKIP_JOB
+ - name: install WIX
+ run: src/ci/scripts/install-wix.sh
+ if: success() && !env.SKIP_JOB
+ - name: install InnoSetup
+ run: src/ci/scripts/install-innosetup.sh
+ if: success() && !env.SKIP_JOB
+ - name: ensure the build happens on a partition with enough space
+ run: src/ci/scripts/symlink-build-dir.sh
+ if: success() && !env.SKIP_JOB
+ - name: disable git crlf conversion
+ run: src/ci/scripts/disable-git-crlf-conversion.sh
+ if: success() && !env.SKIP_JOB
+ - name: install MSYS2
+ run: src/ci/scripts/install-msys2.sh
+ if: success() && !env.SKIP_JOB
+ - name: install MinGW
+ run: src/ci/scripts/install-mingw.sh
+ if: success() && !env.SKIP_JOB
+ - name: install ninja
+ run: src/ci/scripts/install-ninja.sh
+ if: success() && !env.SKIP_JOB
+ - name: enable ipv6 on Docker
+ run: src/ci/scripts/enable-docker-ipv6.sh
+ if: success() && !env.SKIP_JOB
+ - name: disable git crlf conversion
+ run: src/ci/scripts/disable-git-crlf-conversion.sh
+ if: success() && !env.SKIP_JOB
+ - name: checkout submodules
+ run: src/ci/scripts/checkout-submodules.sh
+ if: success() && !env.SKIP_JOB
+ - name: ensure line endings are correct
+ run: src/ci/scripts/verify-line-endings.sh
+ if: success() && !env.SKIP_JOB
+ - name: run the build
+ run: src/ci/scripts/run-build-from-ci.sh
+ env:
+ AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}"
+ AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
+ TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}"
+ if: success() && !env.SKIP_JOB
+ - name: upload artifacts to S3
+ run: src/ci/scripts/upload-artifacts.sh
+ env:
+ AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
+ AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
+ if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
master:
name: master
runs-on: ubuntu-latest
[[package]]
name = "anyhow"
-version = "1.0.26"
+version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c"
+checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f"
[[package]]
name = "arc-swap"
"rustc-std-workspace-core",
]
-[[package]]
-name = "base64"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
-dependencies = [
- "byteorder",
-]
-
[[package]]
name = "bitflags"
version = "1.2.1"
checksum = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
dependencies = [
"byteorder",
- "either",
"iovec",
]
"cargo-test-macro",
"cargo-test-support",
"clap",
- "core-foundation 0.7.0",
+ "core-foundation",
"crates-io",
"crossbeam-utils 0.7.2",
"crypto-hash",
[[package]]
name = "chalk-derive"
-version = "0.10.0"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d4620afad4d4d9e63f915cfa10c930b7a3c9c3ca5cd88dd771ff8e5bf04ea10"
+checksum = "d463e01905d607e181de72e8608721d3269f29176c9a14ce037011316ae7131d"
dependencies = [
"proc-macro2 1.0.3",
"quote 1.0.2",
[[package]]
name = "chalk-engine"
-version = "0.10.0"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ca6e5cef10197789da0b4ec310eda58da4c55530613b2323432642a97372735"
+checksum = "efaf428f5398d36284f79690cf988762b7c091249f50a6c11db613a46c057000"
dependencies = [
- "chalk-macros",
+ "chalk-derive",
+ "chalk-ir",
"rustc-hash",
+ "tracing",
]
[[package]]
name = "chalk-ir"
-version = "0.10.0"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d45df5fb6328527f976e8a32c9e1c9970084d937ebe93d0d34f5bbf4231cb956"
+checksum = "fd3fdc1e9f68498ffe80f4a23b0b95f1ca6fb21d5a4c9b0c085fab3ca712bdbe"
dependencies = [
"chalk-derive",
- "chalk-engine",
- "chalk-macros",
-]
-
-[[package]]
-name = "chalk-macros"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e4782d108e420a1fcf94d8a919cf248db33c5071678e87d9c2d4f20ed1feb32"
-dependencies = [
"lazy_static",
]
-[[package]]
-name = "chalk-rust-ir"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0ec96dbe0ab5fdbadfca4179ec2e1d35f0439c3b53a74988b1aec239c63eb08"
-dependencies = [
- "chalk-derive",
- "chalk-engine",
- "chalk-ir",
- "chalk-macros",
-]
-
[[package]]
name = "chalk-solve"
-version = "0.10.0"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfb99fa9530f0e101475fb60adc931f51bdea05b4642a48928b814d7f0141a6b"
+checksum = "5b9fd4102807b7ebe8fb034fa0f488c5656e1966d3261b558b81a08d519cdb29"
dependencies = [
"chalk-derive",
"chalk-engine",
"chalk-ir",
- "chalk-macros",
- "chalk-rust-ir",
- "ena 0.13.1",
+ "ena",
"itertools 0.9.0",
"petgraph",
"rustc-hash",
+ "tracing",
]
[[package]]
"if_chain",
"itertools 0.9.0",
"lazy_static",
- "pulldown-cmark 0.7.1",
+ "pulldown-cmark",
"quine-mc_cluskey",
"quote 1.0.2",
"regex-syntax",
"cc",
]
-[[package]]
-name = "codespan"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de67bdcd653002a6dba3eb53850ce3a485547225d81cb6c2bbdbc5a0cba5d15d"
-dependencies = [
- "unicode-segmentation",
-]
-
-[[package]]
-name = "codespan-reporting"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efd1d915d9e2b2ad696b2cd73215a84823ef3f0e3084d90304204415921b62c6"
-dependencies = [
- "codespan",
- "termcolor",
- "unicode-width",
-]
-
[[package]]
name = "colored"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
-[[package]]
-name = "cookie"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5"
-dependencies = [
- "time",
- "url 1.7.2",
-]
-
-[[package]]
-name = "cookie_store"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c"
-dependencies = [
- "cookie",
- "failure",
- "idna 0.1.5",
- "log",
- "publicsuffix",
- "serde",
- "serde_json",
- "time",
- "try_from",
- "url 1.7.2",
-]
-
[[package]]
name = "core"
version = "0.0.0"
"rand 0.7.3",
]
-[[package]]
-name = "core-foundation"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e2640d6d0bf22e82bed1b73c6aef8d5dd31e5abe6666c57e6d45e2649f4f887"
-dependencies = [
- "core-foundation-sys 0.6.2",
- "libc",
-]
-
[[package]]
name = "core-foundation"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171"
dependencies = [
- "core-foundation-sys 0.7.0",
+ "core-foundation-sys",
"libc",
]
-[[package]]
-name = "core-foundation-sys"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
-
[[package]]
name = "core-foundation-sys"
version = "0.7.0"
"winapi 0.3.8",
]
-[[package]]
-name = "darling"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9158d690bc62a3a57c3e45b85e4d50de2008b39345592c64efd79345c7e24be0"
-dependencies = [
- "darling_core",
- "darling_macro",
-]
-
-[[package]]
-name = "darling_core"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2a368589465391e127e10c9e3a08efc8df66fd49b87dc8524c764bbe7f2ef82"
-dependencies = [
- "fnv",
- "ident_case",
- "proc-macro2 0.4.30",
- "quote 0.6.12",
- "syn 0.15.35",
-]
-
-[[package]]
-name = "darling_macro"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "244e8987bd4e174385240cde20a3657f607fb0797563c28255c353b5819a07b1"
-dependencies = [
- "darling_core",
- "quote 0.6.12",
- "syn 0.15.35",
-]
-
[[package]]
name = "datafrog"
version = "2.0.1"
"rustc-std-workspace-core",
]
-[[package]]
-name = "dtoa"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e"
-
-[[package]]
-name = "dunce"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0ad6bf6a88548d1126045c413548df1453d9be094a8ab9fd59bf1fdd338da4f"
-
[[package]]
name = "either"
version = "1.5.0"
"strum_macros",
]
-[[package]]
-name = "ena"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8944dc8fa28ce4a38f778bd46bf7d923fe73eed5a439398507246c8e017e6f36"
-dependencies = [
- "log",
-]
-
[[package]]
name = "ena"
version = "0.14.0"
"log",
]
-[[package]]
-name = "encoding_rs"
-version = "0.8.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed"
-dependencies = [
- "cfg-if",
-]
-
[[package]]
name = "env_logger"
version = "0.6.2"
"termcolor",
]
-[[package]]
-name = "error-chain"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02"
-dependencies = [
- "backtrace",
-]
-
[[package]]
name = "error_index_generator"
version = "0.0.0"
[[package]]
name = "fixedbitset"
-version = "0.1.9"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
+checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]]
name = "flate2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869"
-[[package]]
-name = "futures-cpupool"
-version = "0.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
-dependencies = [
- "futures",
- "num_cpus",
-]
-
[[package]]
name = "fwdansi"
version = "1.0.1"
"regex",
]
-[[package]]
-name = "h2"
-version = "0.1.25"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a539b63339fbbb00e081e84b6e11bd1d9634a82d91da2984a18ac74a8823f392"
-dependencies = [
- "byteorder",
- "bytes",
- "fnv",
- "futures",
- "http",
- "indexmap",
- "log",
- "slab",
- "string",
- "tokio-io",
-]
-
[[package]]
name = "handlebars"
version = "3.0.1"
"syn 1.0.11",
]
-[[package]]
-name = "http"
-version = "0.1.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7e06e336150b178206af098a055e3621e8336027e2b4d126bda0bc64824baaf"
-dependencies = [
- "bytes",
- "fnv",
- "itoa",
-]
-
-[[package]]
-name = "http-body"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d"
-dependencies = [
- "bytes",
- "futures",
- "http",
- "tokio-buf",
-]
-
-[[package]]
-name = "httparse"
-version = "1.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
-
[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9b6c53306532d3c8e8087b44e6580e10db51a023cf9b433cea2ac38066b92da"
-[[package]]
-name = "hyper"
-version = "0.12.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6481fff8269772d4463253ca83c788104a7305cb3fb9136bc651a6211e46e03f"
-dependencies = [
- "bytes",
- "futures",
- "futures-cpupool",
- "h2",
- "http",
- "http-body",
- "httparse",
- "iovec",
- "itoa",
- "log",
- "net2",
- "rustc_version",
- "time",
- "tokio",
- "tokio-buf",
- "tokio-executor",
- "tokio-io",
- "tokio-reactor",
- "tokio-tcp",
- "tokio-threadpool",
- "tokio-timer",
- "want",
-]
-
-[[package]]
-name = "hyper-tls"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f"
-dependencies = [
- "bytes",
- "futures",
- "hyper",
- "native-tls",
- "tokio-io",
-]
-
-[[package]]
-name = "ident_case"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
-
[[package]]
name = "idna"
version = "0.1.5"
"libc",
]
-[[package]]
-name = "is-match"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053"
-
[[package]]
name = "itertools"
version = "0.8.0"
[[package]]
name = "mdbook"
-version = "0.3.7"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7ec525f7ebccc2dd935c263717250cd37f9a4b264a77c5dbc950ea2734d8159"
+checksum = "2567ffadc0fd26fe15d6f6e0a80639f19f6a50082fdb460d0ae5d1f7298181be"
dependencies = [
"ammonia",
+ "anyhow",
"chrono",
"clap",
"elasticlunr-rs",
- "env_logger 0.6.2",
- "error-chain",
+ "env_logger 0.7.1",
"handlebars",
- "itertools 0.8.0",
"lazy_static",
"log",
"memchr",
"open",
- "pulldown-cmark 0.6.1",
+ "pulldown-cmark",
"regex",
"serde",
"serde_derive",
"shlex",
"tempfile",
"toml",
- "toml-query",
-]
-
-[[package]]
-name = "mdbook-linkcheck"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0a04db564ca37c47771f8455c825dc941ea851ff0deffcf55a04c512406b409"
-dependencies = [
- "codespan",
- "codespan-reporting",
- "dunce",
- "either",
- "env_logger 0.7.1",
- "failure",
- "http",
- "log",
- "mdbook",
- "percent-encoding 2.1.0",
- "pulldown-cmark 0.6.1",
- "rayon",
- "regex",
- "reqwest",
- "semver 0.9.0",
- "serde",
- "serde_derive",
- "serde_json",
- "structopt",
]
[[package]]
"rustc_version",
]
-[[package]]
-name = "mime"
-version = "0.3.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425"
-dependencies = [
- "unicase",
-]
-
-[[package]]
-name = "mime_guess"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a0ed03949aef72dbdf3116a383d7b38b4768e6f960528cd6a6044aa9ed68599"
-dependencies = [
- "mime",
- "unicase",
-]
-
[[package]]
name = "minifier"
version = "0.0.33"
"shell-escape",
]
-[[package]]
-name = "native-tls"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e"
-dependencies = [
- "lazy_static",
- "libc",
- "log",
- "openssl",
- "openssl-probe",
- "openssl-sys",
- "schannel",
- "security-framework",
- "security-framework-sys",
- "tempfile",
-]
-
[[package]]
name = "net2"
version = "0.2.33"
"vcpkg",
]
-[[package]]
-name = "ordermap"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
-
[[package]]
name = "ordslice"
version = "0.3.0"
[[package]]
name = "petgraph"
-version = "0.4.13"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f"
+checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
dependencies = [
"fixedbitset",
- "ordermap",
+ "indexmap",
]
[[package]]
"cc",
]
-[[package]]
-name = "publicsuffix"
-version = "1.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bf259a81de2b2eb9850ec990ec78e6a25319715584fd7652b9b26f96fcb1510"
-dependencies = [
- "error-chain",
- "idna 0.2.0",
- "lazy_static",
- "regex",
- "url 2.1.0",
-]
-
-[[package]]
-name = "pulldown-cmark"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c205cc82214f3594e2d50686730314f817c67ffa80fe800cf0db78c3c2b9d9e"
-dependencies = [
- "bitflags",
- "getopts",
- "memchr",
- "unicase",
-]
-
[[package]]
name = "pulldown-cmark"
version = "0.7.1"
checksum = "3e142c3b8f49d2200605ee6ba0b1d757310e9e7a72afe78c36ee2ef67300ee00"
dependencies = [
"bitflags",
+ "getopts",
"memchr",
"unicase",
]
[[package]]
name = "racer"
-version = "2.1.34"
+version = "2.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc9caecf1286a3ed28d3ae35207a178ba12e58de95540781e5c6cba05e0f0833"
+checksum = "421174f19211ba9e5fda34aa0cbc292188aae8e0cfbff4aebbae23f1a416bfb3"
dependencies = [
"bitflags",
"clap",
"winapi 0.3.8",
]
-[[package]]
-name = "reqwest"
-version = "0.9.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c2064233e442ce85c77231ebd67d9eca395207dec2127fe0bbedde4bd29a650"
-dependencies = [
- "base64",
- "bytes",
- "cookie",
- "cookie_store",
- "encoding_rs",
- "flate2",
- "futures",
- "http",
- "hyper",
- "hyper-tls",
- "log",
- "mime",
- "mime_guess",
- "native-tls",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "time",
- "tokio",
- "tokio-executor",
- "tokio-io",
- "tokio-threadpool",
- "tokio-timer",
- "url 1.7.2",
- "uuid",
- "winreg",
-]
-
[[package]]
name = "rls"
version = "1.41.0"
version = "0.1.0"
dependencies = [
"clap",
- "codespan",
- "codespan-reporting",
- "failure",
"mdbook",
- "mdbook-linkcheck",
- "rustc-workspace-hack",
]
[[package]]
-name = "rustc-ap-arena"
-version = "659.0.0"
+name = "rustc-ap-rustc_arena"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdaf0295fc40b10ec1091aad1a1760b4bb3b4e7c4f77d543d1a2e9d50a01e6b1"
+checksum = "0c6683b49209f8b132bec33dc6b6c8f9958c8c94eb3586d4cb495e092b61c1da"
dependencies = [
"rustc-ap-rustc_data_structures",
"smallvec 1.4.0",
]
-[[package]]
-name = "rustc-ap-graphviz"
-version = "659.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8028e8cdb4eb71810d0c22a5a5e1e3106c81123be63ce7f044b6d4ac100d8941"
-
[[package]]
name = "rustc-ap-rustc_ast"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16e9e502bb3a5568433db1cf2fb1f1e1074934636069cf744ad7c77b58e1428e"
+checksum = "5b21784d92fb2d584800f528866f00fe814f73abda794f406bfd1fbb2f1ca7f7"
dependencies = [
+ "bitflags",
"log",
"rustc-ap-rustc_data_structures",
"rustc-ap-rustc_index",
"rustc-ap-rustc_lexer",
"rustc-ap-rustc_macros",
+ "rustc-ap-rustc_serialize",
"rustc-ap-rustc_span",
- "rustc-ap-serialize",
"scoped-tls",
"smallvec 1.4.0",
]
[[package]]
name = "rustc-ap-rustc_ast_passes"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "faf35ffecab28f97f7ac01cf6a13afaca6408529d15eb95f317a43b2ffb88933"
+checksum = "820c46fde7ef1df0432073090d775f097b7279ca75ea34ba954081ce4b884d4c"
dependencies = [
"itertools 0.8.0",
"log",
[[package]]
name = "rustc-ap-rustc_ast_pretty"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3684ed43dc552f1e030e3f7a5a300a7a834bdda4e9e00ab80284be4220d8c603"
+checksum = "013db7dd198fe95962d2cefa5bd0b350cf2028af77c169b17b4baa9c3bbf77d1"
dependencies = [
"log",
"rustc-ap-rustc_ast",
"rustc-ap-rustc_span",
+ "rustc-ap-rustc_target",
]
[[package]]
name = "rustc-ap-rustc_attr"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31b413927daa666983b3b49227f9ac218aa29254546abdb585f20cd71c391870"
+checksum = "35b5a85c90eb341eec543600ffdd9e262da5ea72a73a23ae4ca2f4ab8cd1a188"
dependencies = [
"rustc-ap-rustc_ast",
"rustc-ap-rustc_ast_pretty",
"rustc-ap-rustc_errors",
"rustc-ap-rustc_feature",
"rustc-ap-rustc_macros",
+ "rustc-ap-rustc_serialize",
"rustc-ap-rustc_session",
"rustc-ap-rustc_span",
- "rustc-ap-serialize",
"version_check",
]
[[package]]
name = "rustc-ap-rustc_data_structures"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b1c6069e5c522657f1c6f5ab33074e097092f48e804cc896d337e319aacbd60"
+checksum = "b92e4c6cb6c43ee9031a71709dc12853b358253c2b41d12a26379994fab625e0"
dependencies = [
"bitflags",
"cfg-if",
"crossbeam-utils 0.7.2",
- "ena 0.14.0",
+ "ena",
"indexmap",
"jobserver",
"lazy_static",
"libc",
"log",
"measureme",
+ "once_cell",
"parking_lot 0.10.2",
- "rustc-ap-graphviz",
+ "rustc-ap-rustc_graphviz",
"rustc-ap-rustc_index",
- "rustc-ap-serialize",
+ "rustc-ap-rustc_serialize",
"rustc-hash",
"rustc-rayon",
"rustc-rayon-core",
[[package]]
name = "rustc-ap-rustc_errors"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c374e89b3c9714869ef86076942155383804ba6778c26be2169d324563c31f9"
+checksum = "6b0aa79423260c1b9e2f856e144e040f606b0f5d43644408375becf9d7bcdf86"
dependencies = [
- "annotate-snippets 0.6.1",
+ "annotate-snippets 0.8.0",
"atty",
"log",
"rustc-ap-rustc_data_structures",
+ "rustc-ap-rustc_serialize",
"rustc-ap-rustc_span",
- "rustc-ap-serialize",
"termcolor",
"termize",
"unicode-width",
[[package]]
name = "rustc-ap-rustc_expand"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "259d2a7aa7a12f3c99a4ce4123643ec065f1a26f8e89be1f9bedd9757ea53fdc"
+checksum = "c07d76ba2a1b7d4325a2ed21d6345ccebd89ddc6666a1535a6edd489fb4cbc11"
dependencies = [
"log",
"rustc-ap-rustc_ast",
"rustc-ap-rustc_feature",
"rustc-ap-rustc_lexer",
"rustc-ap-rustc_parse",
+ "rustc-ap-rustc_serialize",
"rustc-ap-rustc_session",
"rustc-ap-rustc_span",
- "rustc-ap-serialize",
"smallvec 1.4.0",
]
[[package]]
name = "rustc-ap-rustc_feature"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0296fbc29b629d5ae2ebee1bbf0407bb22de04d26d87216c20899b79579ccb3"
+checksum = "1bbd625705c1db42a0c7503736292813d7b76ada5da20578fb55c63228c80ab5"
dependencies = [
"lazy_static",
"rustc-ap-rustc_data_structures",
[[package]]
name = "rustc-ap-rustc_fs_util"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34734f6cc681399630acd836a14207c6b5b9671a290cc7cad0354b0a4d71b3c9"
+checksum = "34cca6e2942fa0b059c582437ead666d5bcf20fa7c242599e2bbea9b609f29ae"
+
+[[package]]
+name = "rustc-ap-rustc_graphviz"
+version = "664.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13d6a029b81f5e02da85763f82c135507f278a4a0c776432c728520563059529"
[[package]]
name = "rustc-ap-rustc_index"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1e4508753d71d3523209c2ca5086db15a1413e71ebf17ad5412bb7ced5e44c2"
+checksum = "bae50852d303e230b2781c994513788136dc6c2fe4ebe032959f0b990a425767"
dependencies = [
- "rustc-ap-serialize",
+ "rustc-ap-rustc_serialize",
"smallvec 1.4.0",
]
[[package]]
name = "rustc-ap-rustc_lexer"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42b9fcd8407e322908a721262fbc0b35b5f3c35bb173a26dd1e0070bde336e33"
+checksum = "b7186e74aa2d31bf0e2454325fefcdf0a3da77d9344134592144b9e40d45b15d"
dependencies = [
"unicode-xid 0.2.0",
]
[[package]]
name = "rustc-ap-rustc_macros"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d104115a689367d2e0bcd99f37e0ebd6b9c8c78bab0d9cbea5bae86323601b5"
+checksum = "4fc1add04e9d2301164118660ee0bc3266e9a7b1973fc2303fdbe002a12e5401"
dependencies = [
"proc-macro2 1.0.3",
"quote 1.0.2",
[[package]]
name = "rustc-ap-rustc_parse"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afaaab91853fc5a3916785ccae727a4433359d9787c260d42b96a2265fe5b287"
+checksum = "9cd7fc4968bd60084f2fa4f280fa450b0cf98660a7983d6b93a7ae41b6d1d322"
dependencies = [
"bitflags",
"log",
"unicode-normalization",
]
+[[package]]
+name = "rustc-ap-rustc_serialize"
+version = "664.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00bf4c110271d9a2b7dfd2c6eb82e56fd80606a8bad6c102e158c54e44044046"
+dependencies = [
+ "indexmap",
+ "smallvec 1.4.0",
+]
+
[[package]]
name = "rustc-ap-rustc_session"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86e756a57ce6ce1b868e35e64a7e10ab28d49ece80d7c661b07aff5afc6e5d2d"
+checksum = "431cf962de71d4c03fb877d54f331ec36eca77350b0539017abc40a4410d6501"
dependencies = [
"getopts",
"log",
"rustc-ap-rustc_errors",
"rustc-ap-rustc_feature",
"rustc-ap-rustc_fs_util",
- "rustc-ap-rustc_index",
+ "rustc-ap-rustc_serialize",
"rustc-ap-rustc_span",
"rustc-ap-rustc_target",
- "rustc-ap-serialize",
]
[[package]]
name = "rustc-ap-rustc_span"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21031c3396ee452f4c6e994b67513a633055c57c86d00336afd9d63149518f34"
+checksum = "b912039640597624f4bcb75f1e1fcfa5710267d715a7f73a6336baef341b23d1"
dependencies = [
"cfg-if",
"log",
"md-5",
- "rustc-ap-arena",
+ "rustc-ap-rustc_arena",
"rustc-ap-rustc_data_structures",
"rustc-ap-rustc_index",
"rustc-ap-rustc_macros",
- "rustc-ap-serialize",
+ "rustc-ap-rustc_serialize",
"scoped-tls",
"sha-1",
"unicode-width",
[[package]]
name = "rustc-ap-rustc_target"
-version = "659.0.0"
+version = "664.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff21badfbead5b0050391eaad8840f2e4fcb03b6b0fc6006f447443529e9ae6e"
+checksum = "51347a9dadc5ad0b5916cc12d42624b31955285ad13745dbe72f0140038b84e9"
dependencies = [
"bitflags",
"log",
"rustc-ap-rustc_data_structures",
"rustc-ap-rustc_index",
"rustc-ap-rustc_macros",
+ "rustc-ap-rustc_serialize",
"rustc-ap-rustc_span",
- "rustc-ap-serialize",
-]
-
-[[package]]
-name = "rustc-ap-serialize"
-version = "659.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "768b5a305669d934522712bc13502962edfde5128ea63b9e7db4000410be1dc6"
-dependencies = [
- "indexmap",
- "smallvec 1.4.0",
]
[[package]]
[[package]]
name = "rustc-hash"
-version = "1.0.1"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
-dependencies = [
- "byteorder",
-]
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc-main"
"serde_json",
"smallvec 0.6.10",
"smallvec 1.4.0",
- "syn 0.15.35",
"syn 1.0.11",
"url 2.1.0",
"winapi 0.3.8",
"bitflags",
"cfg-if",
"crossbeam-utils 0.7.2",
- "ena 0.14.0",
+ "ena",
"indexmap",
"jobserver",
"lazy_static",
"rustc_expand",
"rustc_feature",
"rustc_hir",
+ "rustc_index",
"rustc_metadata",
"rustc_middle",
"rustc_session",
name = "rustc_session"
version = "0.0.0"
dependencies = [
+ "bitflags",
"getopts",
"log",
"num_cpus",
version = "0.0.0"
dependencies = [
"chalk-ir",
- "chalk-rust-ir",
"chalk-solve",
"log",
"rustc_ast",
dependencies = [
"itertools 0.8.0",
"minifier",
- "pulldown-cmark 0.7.1",
+ "pulldown-cmark",
"rustc-rayon",
"serde",
"serde_json",
[[package]]
name = "rustfmt-nightly"
-version = "1.4.15"
+version = "1.4.18"
dependencies = [
"annotate-snippets 0.6.1",
+ "anyhow",
"bytecount",
"cargo_metadata 0.8.0",
"derive-new",
"diff",
"dirs",
"env_logger 0.6.2",
- "failure",
"getopts",
"ignore",
"itertools 0.8.0",
"serde_json",
"structopt",
"term 0.6.0",
+ "thiserror",
"toml",
"unicode-segmentation",
"unicode-width",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
-[[package]]
-name = "security-framework"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2"
-dependencies = [
- "core-foundation 0.6.3",
- "core-foundation-sys 0.6.2",
- "libc",
- "security-framework-sys",
-]
-
-[[package]]
-name = "security-framework-sys"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56"
-dependencies = [
- "core-foundation-sys 0.6.2",
-]
-
[[package]]
name = "semver"
version = "0.9.0"
"syn 1.0.11",
]
-[[package]]
-name = "serde_urlencoded"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a"
-dependencies = [
- "dtoa",
- "itoa",
- "serde",
- "url 1.7.2",
-]
-
[[package]]
name = "sha-1"
version = "0.8.2"
"wasi",
]
-[[package]]
-name = "string"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d"
-dependencies = [
- "bytes",
-]
-
[[package]]
name = "string_cache"
version = "0.7.3"
"tokio-uds",
]
-[[package]]
-name = "tokio-buf"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46"
-dependencies = [
- "bytes",
- "either",
- "futures",
-]
-
[[package]]
name = "tokio-codec"
version = "0.1.1"
]
[[package]]
-name = "toml-query"
-version = "0.9.0"
+name = "tracing"
+version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a24369a1894ac8224efcfd567c3d141aea360292f49888e7ec7dcc316527aebb"
+checksum = "a41f40ed0e162c911ac6fcb53ecdc8134c46905fdbbae8c50add462a538b495f"
dependencies = [
- "failure",
- "failure_derive",
- "is-match",
- "lazy_static",
- "regex",
- "toml",
- "toml-query_derive",
+ "cfg-if",
+ "tracing-attributes",
+ "tracing-core",
]
[[package]]
-name = "toml-query_derive"
-version = "0.9.0"
+name = "tracing-attributes"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c99ca245ec273c7e75c8ee58f47b882d0146f3c2c8495158082c6671e8b5335"
+checksum = "99bbad0de3fd923c9c3232ead88510b783e5a4d16a6154adffa3d53308de984c"
dependencies = [
- "darling",
- "quote 0.6.12",
- "syn 0.15.35",
+ "proc-macro2 1.0.3",
+ "quote 1.0.2",
+ "syn 1.0.11",
]
[[package]]
-name = "try-lock"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
-
-[[package]]
-name = "try_from"
-version = "0.3.2"
+name = "tracing-core"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b"
+checksum = "0aa83a9a47081cd522c09c81b31aec2c9273424976f922ad61c053b58350b715"
dependencies = [
- "cfg-if",
+ "lazy_static",
]
[[package]]
[[package]]
name = "unicode-script"
-version = "0.4.0"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b2c5c29e805da6817f5af6a627d65adb045cebf05cccd5a3493d6109454391c"
+checksum = "58b33414ea8db4b7ea0343548dbdc31d27aef06beacf7044a87e564d9b0feb7d"
[[package]]
name = "unicode-security"
-version = "0.0.3"
+version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5f9011bbed9c13372bc8df618b55a38138445199caf3b61d432c6859c36dee0"
+checksum = "5d87c28edc5b263377e448d6cdcb935c06b95413d8013ba6fae470558ccab18f"
dependencies = [
"unicode-normalization",
"unicode-script",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
-[[package]]
-name = "uuid"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a"
-dependencies = [
- "rand 0.6.1",
-]
-
[[package]]
name = "vcpkg"
version = "0.2.8"
"winapi-util",
]
-[[package]]
-name = "want"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230"
-dependencies = [
- "futures",
- "log",
- "try-lock",
-]
-
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
"winapi-util",
]
-[[package]]
-name = "winreg"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9"
-dependencies = [
- "winapi 0.3.8",
-]
-
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
"obj",
]
-# These options are controlled from our rustc wrapper script, so turn them off
-# here and have them controlled elsewhere.
-[profile.dev]
-debug = false
-debug-assertions = false
-[profile.test]
-debug = false
+[profile.release.package.compiler_builtins]
+# The compiler-builtins crate cannot reference libcore, and it's own CI will
+# verify that this is the case. This requires, however, that the crate is built
+# without overflow checks and debug assertions. Forcefully disable debug
+# assertions and overflow checks here which should ensure that even if these
+# assertions are enabled for libstd we won't enable then for compiler_builtins
+# which should ensure we still link everything correctly.
debug-assertions = false
+overflow-checks = false
+
+# For compiler-builtins we always use a high number of codegen units.
+# The goal here is to place every single intrinsic into its own object
+# file to avoid symbol clashes with the system libgcc if possible. Note
+# that this number doesn't actually produce this many object files, we
+# just don't create more than this number of object files.
+#
+# It's a bit of a bummer that we have to pass this here, unfortunately.
+# Ideally this would be specified through an env var to Cargo so Cargo
+# knows how many CGUs are for this specific crate, but for now
+# per-crate configuration isn't specifiable in the environment.
+codegen-units = 10000
# We want the RLS to use the version of Cargo that we've got vendored in this
# repository to ensure that the same exact version of Cargo is used by both the
# nightlies are already produced for. The current platform must be able to run
# binaries of this build triple and the nightly will be used to bootstrap the
# first compiler.
-#build = "x86_64-unknown-linux-gnu" # defaults to your host platform
+#
+# Defaults to host platform
+#build = "x86_64-unknown-linux-gnu"
# In addition to the build triple, other triples to produce full compiler
# toolchains for. Each of these triples will be bootstrapped from the build
# triple and then will continue to bootstrap themselves. This platform must
# currently be able to run all of the triples provided here.
-#host = ["x86_64-unknown-linux-gnu"] # defaults to just the build triple
+#
+# Defaults to just the build triple
+#host = ["x86_64-unknown-linux-gnu"]
# In addition to all host triples, other triples to produce the standard library
# for. Each host triple will be used to produce a copy of the standard library
# for each target triple.
-#target = ["x86_64-unknown-linux-gnu"] # defaults to just the build triple
+#
+# Defaults to just the build triple
+#target = ["x86_64-unknown-linux-gnu"]
# Use this directory to store build artifacts.
# You can use "$ROOT" to indicate the root of the git repository.
# Python interpreter to use for various tasks throughout the build, notably
# rustdoc tests, the lldb python interpreter, and some dist bits and pieces.
#
-# Defaults to the Python interpreter used to execute x.py.
+# Defaults to the Python interpreter used to execute x.py
#python = "python"
# Force Cargo to check that Cargo.lock describes the precise dependency
# Build the sanitizer runtimes
#sanitizers = false
-# Build the profiler runtime
+# Build the profiler runtime (required when compiling with options that depend
+# on this runtime, such as `-C profile-generate` or `-Z instrument-coverage`).
#profiler = false
# Indicates whether the native libraries linked into Cargo will be statically
# Whether or not debug assertions are enabled for the compiler and standard
# library.
-#debug-assertions = debug
+#
+# Defaults to rust.debug value
+#debug-assertions = false
# Whether or not debug assertions are enabled for the standard library.
# Overrides the `debug-assertions` option, if defined.
-#debug-assertions-std = debug-assertions
+#
+# Defaults to rust.debug-assertions value
+#debug-assertions-std = false
# Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`.
# `0` - no debug info
# Can be overridden for specific subsets of Rust code (rustc, std or tools).
# Debuginfo for tests run with compiletest is not controlled by this option
# and needs to be enabled separately with `debuginfo-level-tests`.
-#debuginfo-level = if debug { 2 } else { 0 }
+#
+# Defaults to 2 if debug is true
+#debuginfo-level = 0
# Debuginfo level for the compiler.
-#debuginfo-level-rustc = debuginfo-level
+#
+# Defaults to rust.debuginfo-level value
+#debuginfo-level-rustc = 0
# Debuginfo level for the standard library.
-#debuginfo-level-std = debuginfo-level
+#
+# Defaults to rust.debuginfo-level value
+#debuginfo-level-std = 0
# Debuginfo level for the tools.
-#debuginfo-level-tools = debuginfo-level
+#
+# Defaults to rust.debuginfo-level value
+#debuginfo-level-tools = 0
# Debuginfo level for the test suites run with compiletest.
# FIXME(#61117): Some tests fail when this option is enabled.
{
cmd.arg("-C").arg("panic=abort");
}
-
- // Set various options from config.toml to configure how we're building
- // code.
- let debug_assertions = match env::var("RUSTC_DEBUG_ASSERTIONS") {
- Ok(s) => {
- if s == "true" {
- "y"
- } else {
- "n"
- }
- }
- Err(..) => "n",
- };
-
- // The compiler builtins are pretty sensitive to symbols referenced in
- // libcore and such, so we never compile them with debug assertions.
- //
- // FIXME(rust-lang/cargo#7253) we should be doing this in `builder.rs`
- // with env vars instead of doing it here in this script.
- if crate_name == Some("compiler_builtins") {
- cmd.arg("-C").arg("debug-assertions=no");
- } else {
- cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions));
- }
} else {
// FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars
// here, but rather Cargo should know what flags to pass rustc itself.
ostype = require(["uname", "-s"], exit=required)
cputype = require(['uname', '-m'], exit=required)
+ # If we do not have `uname`, assume Windows.
if ostype is None or cputype is None:
return 'x86_64-pc-windows-msvc'
if ostype.endswith('WOW64'):
cputype = 'x86_64'
ostype = 'pc-windows-gnu'
+ elif sys.platform == 'win32':
+ # Some Windows platforms might have a `uname` command that returns a
+ # non-standard string (e.g. gnuwin32 tools returns `windows32`). In
+ # these cases, fall back to using sys.platform.
+ return 'x86_64-pc-windows-msvc'
else:
err = "unknown OS type: {}".format(ostype)
sys.exit(err)
build.verbose = args.verbose
build.clean = args.clean
- try:
- toml_path = args.config or 'config.toml'
+ # Read from `RUST_BOOTSTRAP_CONFIG`, then `--config`, then fallback to `config.toml` (if it
+ # exists).
+ toml_path = os.getenv('RUST_BOOTSTRAP_CONFIG') or args.config
+ if not toml_path and os.path.exists('config.toml'):
+ toml_path = 'config.toml'
+
+ if toml_path:
if not os.path.exists(toml_path):
toml_path = os.path.join(build.rust_root, toml_path)
with open(toml_path) as config:
build.config_toml = config.read()
- except (OSError, IOError):
- pass
config_verbose = build.get_toml('verbose', 'build')
if config_verbose is not None:
env["RUSTC_BOOTSTRAP"] = '1'
env["CARGO"] = build.cargo()
env["RUSTC"] = build.rustc()
+ if toml_path:
+ env["BOOTSTRAP_CONFIG"] = toml_path
if build.rustfmt():
env["RUSTFMT"] = build.rustfmt()
run(args, env=env, verbose=build.verbose)
use crate::native;
use crate::run;
use crate::test;
-use crate::tool;
+use crate::tool::{self, SourceType};
use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir};
use crate::{Build, DocTests, GitRepo, Mode};
name: &'static str,
}
+/// Collection of paths used to match a task rule.
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub enum PathSet {
+ /// A collection of individual paths.
+ ///
+ /// These are generally matched as a path suffix. For example, a
+ /// command-line value of `libstd` will match if `src/libstd` is in the
+ /// set.
Set(BTreeSet<PathBuf>),
+ /// A "suite" of paths.
+ ///
+ /// These can match as a path suffix (like `Set`), or as a prefix. For
+ /// example, a command-line value of `src/test/ui/abi/variadic-ffi.rs`
+ /// will match `src/test/ui`. A command-line value of `ui` would also
+ /// match `src/test/ui`.
Suite(PathBuf),
}
self
}
- // Unlike `krate` this will create just one pathset. As such, it probably shouldn't actually
- // ever be used, but as we transition to having all rules properly handle passing krate(...) by
- // actually doing something different for every crate passed.
+ /// Indicates it should run if the command-line selects the given crate or
+ /// any of its (local) dependencies.
+ ///
+ /// Compared to `krate`, this treats the dependencies as aliases for the
+ /// same job. Generally it is preferred to use `krate`, and treat each
+ /// individual path separately. For example `./x.py test src/liballoc`
+ /// (which uses `krate`) will test just `liballoc`. However, `./x.py check
+ /// src/liballoc` (which uses `all_krates`) will check all of `libtest`.
+ /// `all_krates` should probably be removed at some point.
pub fn all_krates(mut self, name: &str) -> Self {
let mut set = BTreeSet::new();
for krate in self.builder.in_tree_crates(name) {
- set.insert(PathBuf::from(&krate.path));
+ let path = krate.local_path(self.builder);
+ set.insert(path);
}
self.paths.insert(PathSet::Set(set));
self
}
+ /// Indicates it should run if the command-line selects the given crate or
+ /// any of its (local) dependencies.
+ ///
+ /// `make_run` will be called separately for each matching command-line path.
pub fn krate(mut self, name: &str) -> Self {
for krate in self.builder.in_tree_crates(name) {
- self.paths.insert(PathSet::one(&krate.path));
+ let path = krate.local_path(self.builder);
+ self.paths.insert(PathSet::one(path));
}
self
}
should_run = (desc.should_run)(should_run);
}
let mut help = String::from("Available paths:\n");
+ let mut add_path = |path: &Path| {
+ help.push_str(&format!(" ./x.py {} {}\n", subcommand, path.display()));
+ };
for pathset in should_run.paths {
- if let PathSet::Set(set) = pathset {
- set.iter().for_each(|path| {
- help.push_str(
- format!(" ./x.py {} {}\n", subcommand, path.display()).as_str(),
- )
- })
+ match pathset {
+ PathSet::Set(set) => {
+ for path in set {
+ add_path(&path);
+ }
+ }
+ PathSet::Suite(path) => {
+ add_path(&path.join("..."));
+ }
}
}
Some(help)
&self,
compiler: Compiler,
mode: Mode,
+ source_type: SourceType,
target: Interned<String>,
cmd: &str,
) -> Cargo {
.env("RUSTC", self.out.join("bootstrap/debug/rustc"))
.env("RUSTC_REAL", self.rustc(compiler))
.env("RUSTC_STAGE", stage.to_string())
- .env(
- "RUSTC_DEBUG_ASSERTIONS",
- if mode == Mode::Std {
- self.config.rust_debug_assertions_std.to_string()
- } else {
- self.config.rust_debug_assertions.to_string()
- },
- )
.env("RUSTC_SYSROOT", &sysroot)
.env("RUSTC_LIBDIR", &libdir)
.env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
}
};
cargo.env(profile_var("DEBUG"), debuginfo_level.to_string());
+ cargo.env(
+ profile_var("DEBUG_ASSERTIONS"),
+ if mode == Mode::Std {
+ self.config.rust_debug_assertions_std.to_string()
+ } else {
+ self.config.rust_debug_assertions.to_string()
+ },
+ );
if !mode.is_tool() {
cargo.env("RUSTC_FORCE_UNSTABLE", "1");
cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
- if !mode.is_tool() {
+ if source_type == SourceType::InTree {
// When extending this list, add the new lints to the RUSTFLAGS of the
// build_bootstrap function of src/bootstrap/bootstrap.py as well as
// some code doesn't go through this `rustc` wrapper.
);
}
- // If Control Flow Guard is enabled, pass the `control_flow_guard=checks` flag to rustc
+ // If Control Flow Guard is enabled, pass the `control-flow-guard` flag to rustc
// when compiling the standard library, since this might be linked into the final outputs
// produced by rustc. Since this mitigation is only available on Windows, only enable it
// for the standard library in case the compiler is run on a non-Windows platform.
&& self.config.control_flow_guard
&& compiler.stage >= 1
{
- rustflags.arg("-Zcontrol_flow_guard=checks");
+ rustflags.arg("-Zcontrol-flow-guard");
}
// For `cargo doc` invocations, make rustdoc print the Rust version into the docs
let target = self.target;
let compiler = builder.compiler(0, builder.config.build);
- let mut cargo = builder.cargo(compiler, Mode::Std, target, cargo_subcommand(builder.kind));
+ let mut cargo = builder.cargo(
+ compiler,
+ Mode::Std,
+ SourceType::InTree,
+ target,
+ cargo_subcommand(builder.kind),
+ );
std_cargo(builder, target, compiler.stage, &mut cargo);
builder.info(&format!("Checking std artifacts ({} -> {})", &compiler.host, target));
builder.ensure(Std { target });
- let mut cargo =
- builder.cargo(compiler, Mode::Rustc, target, cargo_subcommand(builder.kind));
+ let mut cargo = builder.cargo(
+ compiler,
+ Mode::Rustc,
+ SourceType::InTree,
+ target,
+ cargo_subcommand(builder.kind),
+ );
rustc_cargo(builder, &mut cargo, target);
builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target));
}
macro_rules! tool_check_step {
- ($name:ident, $path:expr) => {
+ ($name:ident, $path:expr, $source_type:expr) => {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct $name {
pub target: Interned<String>,
target,
cargo_subcommand(builder.kind),
$path,
- SourceType::InTree,
+ $source_type,
&[],
);
};
}
-tool_check_step!(Rustdoc, "src/tools/rustdoc");
-tool_check_step!(Clippy, "src/tools/clippy");
+tool_check_step!(Rustdoc, "src/tools/rustdoc", SourceType::InTree);
+// Clippy is a hybrid. It is an external tool, but uses a git subtree instead
+// of a submodule. Since the SourceType only drives the deny-warnings
+// behavior, treat it as in-tree so that any new warnings in clippy will be
+// rejected.
+tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
use serde::Deserialize;
use crate::builder::Cargo;
+use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
+use crate::cache::{Interned, INTERNER};
use crate::dist;
use crate::native;
+use crate::tool::SourceType;
use crate::util::{exe, is_dylib, symlink_dir};
-use crate::{Compiler, GitRepo, Mode};
-
-use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
-use crate::cache::{Interned, INTERNER};
+use crate::{Compiler, DependencyType, GitRepo, Mode};
#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Std {
// Even if we're not building std this stage, the new sysroot must
// still contain the third party objects needed by various targets.
copy_third_party_objects(builder, &compiler, target);
+ copy_self_contained_objects(builder, &compiler, target);
builder.ensure(StdLink {
compiler: compiler_to_use,
return;
}
- target_deps.extend(copy_third_party_objects(builder, &compiler, target).into_iter());
+ target_deps.extend(copy_third_party_objects(builder, &compiler, target));
+ target_deps.extend(copy_self_contained_objects(builder, &compiler, target));
- let mut cargo = builder.cargo(compiler, Mode::Std, target, "build");
+ let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "build");
std_cargo(builder, target, compiler.stage, &mut cargo);
builder.info(&format!(
}
}
+fn copy_and_stamp(
+ builder: &Builder<'_>,
+ libdir: &Path,
+ sourcedir: &Path,
+ name: &str,
+ target_deps: &mut Vec<(PathBuf, DependencyType)>,
+ dependency_type: DependencyType,
+) {
+ let target = libdir.join(name);
+ builder.copy(&sourcedir.join(name), &target);
+
+ target_deps.push((target, dependency_type));
+}
+
/// Copies third party objects needed by various targets.
fn copy_third_party_objects(
builder: &Builder<'_>,
compiler: &Compiler,
target: Interned<String>,
-) -> Vec<PathBuf> {
- let libdir = builder.sysroot_libdir(*compiler, target);
-
+) -> Vec<(PathBuf, DependencyType)> {
let mut target_deps = vec![];
- let mut copy_and_stamp = |sourcedir: &Path, name: &str| {
- let target = libdir.join(name);
- builder.copy(&sourcedir.join(name), &target);
- target_deps.push(target);
+ // FIXME: remove this in 2021
+ if target == "x86_64-fortanix-unknown-sgx" {
+ if env::var_os("X86_FORTANIX_SGX_LIBS").is_some() {
+ builder.info("Warning: X86_FORTANIX_SGX_LIBS environment variable is ignored, libunwind is now compiled as part of rustbuild");
+ }
+ }
+
+ if builder.config.sanitizers && compiler.stage != 0 {
+ // The sanitizers are only copied in stage1 or above,
+ // to avoid creating dependency on LLVM.
+ target_deps.extend(
+ copy_sanitizers(builder, &compiler, target)
+ .into_iter()
+ .map(|d| (d, DependencyType::Target)),
+ );
+ }
+
+ target_deps
+}
+
+/// Copies third party objects needed by various targets for self-contained linkage.
+fn copy_self_contained_objects(
+ builder: &Builder<'_>,
+ compiler: &Compiler,
+ target: Interned<String>,
+) -> Vec<(PathBuf, DependencyType)> {
+ // cfg(bootstrap)
+ // Remove when upgrading bootstrap compiler.
+ let libdir_self_contained = if compiler.stage == 0 {
+ builder.sysroot_libdir(*compiler, target).to_path_buf()
+ } else {
+ builder.sysroot_libdir(*compiler, target).join("self-contained")
};
+ t!(fs::create_dir_all(&libdir_self_contained));
+ let mut target_deps = vec![];
// Copies the CRT objects.
//
if target.contains("musl") {
let srcdir = builder.musl_libdir(target).unwrap();
for &obj in &["crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
- copy_and_stamp(&srcdir, obj);
+ copy_and_stamp(
+ builder,
+ &libdir_self_contained,
+ &srcdir,
+ obj,
+ &mut target_deps,
+ DependencyType::TargetSelfContained,
+ );
}
} else if target.ends_with("-wasi") {
let srcdir = builder.wasi_root(target).unwrap().join("lib/wasm32-wasi");
- copy_and_stamp(&srcdir, "crt1.o");
- }
-
- // Copies libunwind.a compiled to be linked with x86_64-fortanix-unknown-sgx.
- //
- // This target needs to be linked to Fortanix's port of llvm's libunwind.
- // libunwind requires support for rwlock and printing to stderr,
- // which is provided by std for this target.
- if target == "x86_64-fortanix-unknown-sgx" {
- let src_path_env = "X86_FORTANIX_SGX_LIBS";
- let src =
- env::var(src_path_env).unwrap_or_else(|_| panic!("{} not found in env", src_path_env));
- copy_and_stamp(Path::new(&src), "libunwind.a");
- }
-
- if builder.config.sanitizers && compiler.stage != 0 {
- // The sanitizers are only copied in stage1 or above,
- // to avoid creating dependency on LLVM.
- target_deps.extend(copy_sanitizers(builder, &compiler, target));
+ copy_and_stamp(
+ builder,
+ &libdir_self_contained,
+ &srcdir,
+ "crt1.o",
+ &mut target_deps,
+ DependencyType::TargetSelfContained,
+ );
+ } else if target.contains("windows-gnu") {
+ for obj in ["crt2.o", "dllcrt2.o"].iter() {
+ let src = compiler_file(builder, builder.cc(target), target, obj);
+ let target = libdir_self_contained.join(obj);
+ builder.copy(&src, &target);
+ target_deps.push((target, DependencyType::TargetSelfContained));
+ }
}
target_deps
}
impl Step for StartupObjects {
- type Output = Vec<PathBuf>;
+ type Output = Vec<(PathBuf, DependencyType)>;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/rtstartup")
/// They don't require any library support as they're just plain old object
/// files, so we just use the nightly snapshot compiler to always build them (as
/// no other compilers are guaranteed to be available).
- fn run(self, builder: &Builder<'_>) -> Vec<PathBuf> {
+ fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {
let for_compiler = self.compiler;
let target = self.target;
if !target.contains("windows-gnu") {
let target = sysroot_dir.join((*file).to_string() + ".o");
builder.copy(dst_file, &target);
- target_deps.push(target);
- }
-
- for obj in ["crt2.o", "dllcrt2.o"].iter() {
- let src = compiler_file(builder, builder.cc(target), target, obj);
- let target = sysroot_dir.join(obj);
- builder.copy(&src, &target);
- target_deps.push(target);
+ target_deps.push((target, DependencyType::Target));
}
target_deps
target: builder.config.build,
});
- let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "build");
+ let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build");
rustc_cargo(builder, &mut cargo, target);
builder.info(&format!(
sysroot_host_dst: &Path,
stamp: &Path,
) {
+ let self_contained_dst = &sysroot_dst.join("self-contained");
t!(fs::create_dir_all(&sysroot_dst));
t!(fs::create_dir_all(&sysroot_host_dst));
- for (path, host) in builder.read_stamp_file(stamp) {
- if host {
- builder.copy(&path, &sysroot_host_dst.join(path.file_name().unwrap()));
- } else {
- builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
- }
+ t!(fs::create_dir_all(&self_contained_dst));
+ for (path, dependency_type) in builder.read_stamp_file(stamp) {
+ let dst = match dependency_type {
+ DependencyType::Host => sysroot_host_dst,
+ DependencyType::Target => sysroot_dst,
+ DependencyType::TargetSelfContained => self_contained_dst,
+ };
+ builder.copy(&path, &dst.join(path.file_name().unwrap()));
}
}
cargo: Cargo,
tail_args: Vec<String>,
stamp: &Path,
- additional_target_deps: Vec<PathBuf>,
+ additional_target_deps: Vec<(PathBuf, DependencyType)>,
is_check: bool,
) -> Vec<PathBuf> {
if builder.config.dry_run {
if filename.starts_with(&host_root_dir) {
// Unless it's a proc macro used in the compiler
if crate_types.iter().any(|t| t == "proc-macro") {
- deps.push((filename.to_path_buf(), true));
+ deps.push((filename.to_path_buf(), DependencyType::Host));
}
continue;
}
// If this was output in the `deps` dir then this is a precise file
// name (hash included) so we start tracking it.
if filename.starts_with(&target_deps_dir) {
- deps.push((filename.to_path_buf(), false));
+ deps.push((filename.to_path_buf(), DependencyType::Target));
continue;
}
let candidate = format!("{}.lib", path_to_add);
let candidate = PathBuf::from(candidate);
if candidate.exists() {
- deps.push((candidate, false));
+ deps.push((candidate, DependencyType::Target));
}
}
- deps.push((path_to_add.into(), false));
+ deps.push((path_to_add.into(), DependencyType::Target));
}
- deps.extend(additional_target_deps.into_iter().map(|d| (d, false)));
+ deps.extend(additional_target_deps);
deps.sort();
let mut new_contents = Vec::new();
- for (dep, proc_macro) in deps.iter() {
- new_contents.extend(if *proc_macro { b"h" } else { b"t" });
+ for (dep, dependency_type) in deps.iter() {
+ new_contents.extend(match *dependency_type {
+ DependencyType::Host => b"h",
+ DependencyType::Target => b"t",
+ DependencyType::TargetSelfContained => b"s",
+ });
new_contents.extend(dep.to_str().unwrap().as_bytes());
new_contents.extend(b"\0");
}
"rootfs in qemu testing, you probably don't want to use this")
v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs",
"rootfs in qemu testing, you probably don't want to use this")
+v("qemu-riscv64-rootfs", "target.riscv64gc-unknown-linux-gnu.qemu-rootfs",
+ "rootfs in qemu testing, you probably don't want to use this")
v("experimental-targets", "llvm.experimental-targets",
"experimental LLVM targets to build")
v("release-channel", "rust.channel", "the name of the release channel to build")
use crate::compile;
use crate::tool::{self, Tool};
use crate::util::{exe, is_dylib, timeit};
-use crate::{Compiler, Mode, LLVM_TOOLS};
+use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
use time::{self, Timespec};
pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
}
//Copy platform tools to platform-specific bin directory
- let target_bin_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("bin");
+ let target_bin_dir = plat_root
+ .join("lib")
+ .join("rustlib")
+ .join(target_triple)
+ .join("bin")
+ .join("self-contained");
fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
for src in target_tools {
builder.copy_to_folder(&src, &target_bin_dir);
);
//Copy platform libs to platform-specific lib directory
- let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib");
+ let target_lib_dir = plat_root
+ .join("lib")
+ .join("rustlib")
+ .join(target_triple)
+ .join("lib")
+ .join("self-contained");
fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
for src in target_libs {
builder.copy_to_folder(&src, &target_lib_dir);
/// Copy stamped files into an image's `target/lib` directory.
fn copy_target_libs(builder: &Builder<'_>, target: &str, image: &Path, stamp: &Path) {
let dst = image.join("lib/rustlib").join(target).join("lib");
+ let self_contained_dst = dst.join("self-contained");
t!(fs::create_dir_all(&dst));
- for (path, host) in builder.read_stamp_file(stamp) {
- if !host || builder.config.build == target {
+ t!(fs::create_dir_all(&self_contained_dst));
+ for (path, dependency_type) in builder.read_stamp_file(stamp) {
+ if dependency_type == DependencyType::TargetSelfContained {
+ builder.copy(&path, &self_contained_dst.join(path.file_name().unwrap()));
+ } else if dependency_type == DependencyType::Target || builder.config.build == target {
builder.copy(&path, &dst.join(path.file_name().unwrap()));
}
}
t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css")));
let run_cargo_rustdoc_for = |package: &str| {
- let mut cargo = builder.cargo(compiler, Mode::Std, target, "rustdoc");
+ let mut cargo =
+ builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustdoc");
compile::std_cargo(builder, target, compiler.stage, &mut cargo);
// Keep a whitelist so we do not build internal stdlib crates, these will be
t!(symlink_dir_force(&builder.config, &out, &out_dir));
// Build cargo command.
- let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc");
+ let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc");
cargo.env(
"RUSTDOCFLAGS",
"--document-private-items \
// Find dependencies for top level crates.
let mut compiler_crates = HashSet::new();
for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] {
- let interned_root_crate = INTERNER.intern_str(root_crate);
- find_compiler_crates(builder, &interned_root_crate, &mut compiler_crates);
+ compiler_crates
+ .extend(builder.in_tree_crates(root_crate).into_iter().map(|krate| krate.name));
}
for krate in &compiler_crates {
}
}
-fn find_compiler_crates(
- builder: &Builder<'_>,
- name: &Interned<String>,
- crates: &mut HashSet<Interned<String>>,
-) {
- // Add current crate.
- crates.insert(*name);
-
- // Look for dependencies.
- for dep in builder.crates.get(name).unwrap().deps.iter() {
- if builder.crates.get(dep).unwrap().is_local(builder) {
- find_compiler_crates(builder, dep, crates);
- }
- }
-}
-
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Rustdoc {
stage: u32,
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.
-use std::fs;
+use std::env;
use std::path::PathBuf;
use std::process;
use getopts::Options;
use crate::builder::Builder;
+use crate::cache::{Interned, INTERNER};
use crate::config::Config;
-use crate::metadata;
use crate::{Build, DocTests};
-use crate::cache::{Interned, INTERNER};
-
/// Deserialized version of all flags for this compile.
pub struct Flags {
pub verbose: usize, // number of -v args; each extra -v after the first is passed to Cargo
// Get any optional paths which occur after the subcommand
let paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
- let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| {
- if fs::metadata("config.toml").is_ok() {
- Some(PathBuf::from("config.toml"))
- } else {
- None
- }
- });
+ let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
// All subcommands except `clean` can have an optional "Available paths" section
if matches.opt_present("verbose") {
let config = Config::parse(&["build".to_string()]);
- let mut build = Build::new(config);
- metadata::build(&mut build);
+ let build = Build::new(config);
let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
let libdir_default = PathBuf::from("lib");
let mandir_default = datadir_default.join("man");
let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
- fs::canonicalize(p).unwrap_or_else(|_| panic!("could not canonicalize {}", p.display()))
+ fs::create_dir_all(p)
+ .unwrap_or_else(|err| panic!("could not create {}: {}", p.display(), err));
+ fs::canonicalize(p)
+ .unwrap_or_else(|err| panic!("could not canonicalize {}: {}", p.display(), err))
});
let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
}
impl Crate {
- fn is_local(&self, build: &Build) -> bool {
- self.path.starts_with(&build.config.src) && !self.path.to_string_lossy().ends_with("_shim")
- }
-
fn local_path(&self, build: &Build) -> PathBuf {
- assert!(self.is_local(build));
self.path.strip_prefix(&build.config.src).unwrap().into()
}
}
+/// When building Rust various objects are handled differently.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub enum DependencyType {
+ /// Libraries originating from proc-macros.
+ Host,
+ /// Typical Rust libraries.
+ Target,
+ /// Non Rust libraries and objects shipped to ease usage of certain targets.
+ TargetSelfContained,
+}
+
/// The various "modes" of invoking Cargo.
///
/// These entries currently correspond to the various output directories of the
/// Build codegen libraries, placing output in the "stageN-codegen" directory
Codegen,
- /// Build some tools, placing output in the "stageN-tools" directory. The
- /// "other" here is for miscellaneous sets of tools that are built using the
- /// bootstrap compiler in its entirety (target libraries and all).
- /// Typically these tools compile with stable Rust.
+ /// Build a tool, placing output in the "stage0-bootstrap-tools"
+ /// directory. This is for miscellaneous sets of tools that are built
+ /// using the bootstrap stage0 compiler in its entirety (target libraries
+ /// and all). Typically these tools compile with stable Rust.
ToolBootstrap,
- /// Compile a tool which uses all libraries we compile (up to rustc).
- /// Doesn't use the stage0 compiler libraries like "other", and includes
- /// tools like rustdoc, cargo, rls, etc.
+ /// Build a tool which uses the locally built std, placing output in the
+ /// "stageN-tools" directory. Its usage is quite rare, mainly used by
+ /// compiletest which needs libtest.
ToolStd,
+
+ /// Build a tool which uses the locally built rustc and the target std,
+ /// placing the output in the "stageN-tools" directory. This is used for
+ /// anything that needs a fully functional rustc, such as rustdoc, clippy,
+ /// cargo, rls, rustfmt, miri, etc.
ToolRustc,
}
}
}
+ /// Returns a Vec of all the dependencies of the given root crate,
+ /// including transitive dependencies and the root itself. Only includes
+ /// "local" crates (those in the local source tree, not from a registry).
fn in_tree_crates(&self, root: &str) -> Vec<&Crate> {
let mut ret = Vec::new();
let mut list = vec![INTERNER.intern_str(root)];
let mut visited = HashSet::new();
while let Some(krate) = list.pop() {
let krate = &self.crates[&krate];
- if krate.is_local(self) {
- ret.push(krate);
- }
+ ret.push(krate);
for dep in &krate.deps {
- if visited.insert(dep) && dep != "build_helper" {
+ // Don't include optional deps if their features are not
+ // enabled. Ideally this would be computed from `cargo
+ // metadata --features …`, but that is somewhat slow. Just
+ // skip `build_helper` since there aren't any operations we
+ // want to perform on it. In the future, we may want to
+ // consider just filtering all build and dev dependencies in
+ // metadata::build.
+ if visited.insert(dep)
+ && dep != "build_helper"
+ && (dep != "profiler_builtins" || self.config.profiler)
+ && (dep != "rustc_codegen_llvm" || self.config.llvm_enabled())
+ {
list.push(*dep);
}
}
ret
}
- fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, bool)> {
+ fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, DependencyType)> {
if self.config.dry_run {
return Vec::new();
}
if part.is_empty() {
continue;
}
- let host = part[0] as char == 'h';
+ let dependency_type = match part[0] as char {
+ 'h' => DependencyType::Host,
+ 's' => DependencyType::TargetSelfContained,
+ 't' => DependencyType::Target,
+ _ => unreachable!(),
+ };
let path = PathBuf::from(t!(str::from_utf8(&part[1..])));
- paths.push((path, host));
+ paths.push((path, dependency_type));
}
paths
}
-use std::collections::HashMap;
-use std::collections::HashSet;
use std::path::PathBuf;
use std::process::Command;
#[derive(Deserialize)]
struct Output {
packages: Vec<Package>,
- resolve: Resolve,
}
#[derive(Deserialize)]
name: String,
source: Option<String>,
manifest_path: String,
+ dependencies: Vec<Dependency>,
}
#[derive(Deserialize)]
-struct Resolve {
- nodes: Vec<ResolveNode>,
-}
-
-#[derive(Deserialize)]
-struct ResolveNode {
- id: String,
- dependencies: Vec<String>,
+struct Dependency {
+ name: String,
+ source: Option<String>,
}
pub fn build(build: &mut Build) {
- let mut resolves = Vec::new();
- build_krate(&build.std_features(), build, &mut resolves, "src/libstd");
- build_krate("", build, &mut resolves, "src/libtest");
- build_krate(&build.rustc_features(), build, &mut resolves, "src/rustc");
-
- let mut id2name = HashMap::with_capacity(build.crates.len());
- for (name, krate) in build.crates.iter() {
- id2name.insert(krate.id.clone(), name.clone());
- }
-
- for node in resolves {
- let name = match id2name.get(&node.id) {
- Some(name) => name,
- None => continue,
- };
-
- let krate = build.crates.get_mut(name).unwrap();
- for dep in node.dependencies.iter() {
- let dep = match id2name.get(dep) {
- Some(dep) => dep,
- None => continue,
- };
- krate.deps.insert(*dep);
- }
- }
-}
-
-fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec<ResolveNode>, krate: &str) {
// Run `cargo metadata` to figure out what crates we're testing.
- //
- // Down below we're going to call `cargo test`, but to test the right set
- // of packages we're going to have to know what `-p` arguments to pass it
- // to know what crates to test. Here we run `cargo metadata` to learn about
- // the dependency graph and what `-p` arguments there are.
let mut cargo = Command::new(&build.initial_cargo);
cargo
.arg("metadata")
.arg("--format-version")
.arg("1")
- .arg("--features")
- .arg(features)
+ .arg("--no-deps")
.arg("--manifest-path")
- .arg(build.src.join(krate).join("Cargo.toml"));
+ .arg(build.src.join("Cargo.toml"));
let output = output(&mut cargo);
let output: Output = serde_json::from_str(&output).unwrap();
for package in output.packages {
let name = INTERNER.intern_string(package.name);
let mut path = PathBuf::from(package.manifest_path);
path.pop();
- build.crates.insert(name, Crate { name, id: package.id, deps: HashSet::new(), path });
+ let deps = package
+ .dependencies
+ .into_iter()
+ .filter(|dep| dep.source.is_none())
+ .map(|dep| INTERNER.intern_string(dep.name))
+ .collect();
+ build.crates.insert(name, Crate { name, id: package.id, deps, path });
}
}
- resolves.extend(output.resolve.nodes);
}
.define("LLVM_INCLUDE_TESTS", "OFF")
.define("LLVM_INCLUDE_DOCS", "OFF")
.define("LLVM_INCLUDE_BENCHMARKS", "OFF")
- .define("LLVM_ENABLE_ZLIB", "OFF")
.define("WITH_POLLY", "OFF")
.define("LLVM_ENABLE_TERMINFO", "OFF")
.define("LLVM_ENABLE_LIBEDIT", "OFF")
.define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
.define("LLVM_DEFAULT_TARGET_TRIPLE", target);
+ if !target.contains("netbsd") {
+ cfg.define("LLVM_ENABLE_ZLIB", "ON");
+ } else {
+ // FIXME: Enable zlib on NetBSD too
+ // https://github.com/rust-lang/rust/pull/72696#issuecomment-641517185
+ cfg.define("LLVM_ENABLE_ZLIB", "OFF");
+ }
+
if builder.config.llvm_thin_lto {
cfg.define("LLVM_ENABLE_LTO", "Thin");
if !target.contains("apple") {
target: Interned<String>,
channel: &str,
) -> Vec<SanitizerRuntime> {
- let mut result = Vec::new();
+ let darwin_libs = |os: &str, components: &[&str]| -> Vec<SanitizerRuntime> {
+ components
+ .into_iter()
+ .map(move |c| SanitizerRuntime {
+ cmake_target: format!("clang_rt.{}_{}_dynamic", c, os),
+ path: out_dir
+ .join(&format!("build/lib/darwin/libclang_rt.{}_{}_dynamic.dylib", c, os)),
+ name: format!("librustc-{}_rt.{}.dylib", channel, c),
+ })
+ .collect()
+ };
+
+ let common_libs = |os: &str, arch: &str, components: &[&str]| -> Vec<SanitizerRuntime> {
+ components
+ .into_iter()
+ .map(move |c| SanitizerRuntime {
+ cmake_target: format!("clang_rt.{}-{}", c, arch),
+ path: out_dir.join(&format!("build/lib/{}/libclang_rt.{}-{}.a", os, c, arch)),
+ name: format!("librustc-{}_rt.{}.a", channel, c),
+ })
+ .collect()
+ };
+
match &*target {
- "x86_64-apple-darwin" => {
- for s in &["asan", "lsan", "tsan"] {
- result.push(SanitizerRuntime {
- cmake_target: format!("clang_rt.{}_osx_dynamic", s),
- path: out_dir
- .join(&format!("build/lib/darwin/libclang_rt.{}_osx_dynamic.dylib", s)),
- name: format!("librustc-{}_rt.{}.dylib", channel, s),
- });
- }
+ "aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
+ "aarch64-unknown-linux-gnu" => {
+ common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan"])
}
+ "x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
+ "x86_64-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
"x86_64-unknown-linux-gnu" => {
- for s in &["asan", "lsan", "msan", "tsan"] {
- result.push(SanitizerRuntime {
- cmake_target: format!("clang_rt.{}-x86_64", s),
- path: out_dir.join(&format!("build/lib/linux/libclang_rt.{}-x86_64.a", s)),
- name: format!("librustc-{}_rt.{}.a", channel, s),
- });
- }
- }
- "x86_64-fuchsia" => {
- for s in &["asan"] {
- result.push(SanitizerRuntime {
- cmake_target: format!("clang_rt.{}-x86_64", s),
- path: out_dir.join(&format!("build/lib/fuchsia/libclang_rt.{}-x86_64.a", s)),
- name: format!("librustc-{}_rt.{}.a", channel, s),
- });
- }
- }
- "aarch64-fuchsia" => {
- for s in &["asan"] {
- result.push(SanitizerRuntime {
- cmake_target: format!("clang_rt.{}-aarch64", s),
- path: out_dir.join(&format!("build/lib/fuchsia/libclang_rt.{}-aarch64.a", s)),
- name: format!("librustc-{}_rt.{}.a", channel, s),
- });
- }
+ common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
}
- _ => {}
+ _ => Vec::new(),
}
- result
}
struct HashStamp {
extra_features: Vec::new(),
});
if let (Some(miri), Some(_cargo_miri)) = (miri, cargo_miri) {
- let mut cargo = builder.cargo(compiler, Mode::ToolRustc, host, "install");
+ let mut cargo =
+ builder.cargo(compiler, Mode::ToolRustc, SourceType::Submodule, host, "install");
cargo.arg("xargo");
// Configure `cargo install` path. cargo adds a `bin/`.
cargo.env("CARGO_INSTALL_ROOT", &builder.out);
builder.add_rustc_lib_path(compiler, &mut cargo);
- // FIXME: Disable clippy tests for now, they're failing on master
- // (generally this would mean a toolstate failure but we don't have
- // toolstate for clippy anymore).
- // builder.run(&mut cargo.into());
+ builder.run(&mut cargo.into());
}
}
type Output = ();
const DEFAULT: bool = true;
- fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
- let builder = run.builder;
- for krate in run.builder.in_tree_crates("test") {
- if !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) {
- run = run.path(krate.local_path(&builder).to_str().unwrap());
- }
- }
- run
+ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+ run.krate("test")
}
fn make_run(run: RunConfig<'_>) {
// we're working with automatically.
let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
- let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand());
+ let mut cargo =
+ builder.cargo(compiler, mode, SourceType::InTree, target, test_kind.subcommand());
match mode {
Mode::Std => {
compile::std_cargo(builder, target, compiler.stage, &mut cargo);
use crate::channel::GitInfo;
use crate::compile;
use crate::toolstate::ToolState;
-use crate::util::{add_dylib_path, exe, CiEnv};
+use crate::util::{add_dylib_path, exe};
use crate::Compiler;
use crate::Mode;
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum SourceType {
InTree,
Submodule,
source_type: SourceType,
extra_features: &[String],
) -> CargoCommand {
- let mut cargo = builder.cargo(compiler, mode, target, command);
+ let mut cargo = builder.cargo(compiler, mode, source_type, target, command);
let dir = builder.src.join(path);
cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
- if source_type == SourceType::Submodule {
- cargo.env("RUSTC_EXTERNAL_TOOL", "1");
- }
-
let mut features = extra_features.to_vec();
if builder.build.config.cargo_native_static {
if path.ends_with("cargo")
|| path.ends_with("rls")
|| path.ends_with("clippy")
|| path.ends_with("miri")
- || path.ends_with("rustbook")
|| path.ends_with("rustfmt")
{
cargo.env("LIBZ_SYS_STATIC", "1");
cargo
}
-fn rustbook_features() -> Vec<String> {
- let mut features = Vec::new();
-
- // Due to CI budged and risk of spurious failures we want to limit jobs running this check.
- // At same time local builds should run it regardless of the platform.
- // `CiEnv::None` means it's local build and `CHECK_LINKS` is defined in x86_64-gnu-tools to
- // explicitly enable it on single job
- if CiEnv::current() == CiEnv::None || env::var("CHECK_LINKS").is_ok() {
- features.push("linkcheck".to_string());
- }
-
- features
-}
-
macro_rules! bootstrap_tool {
($(
$name:ident, $path:expr, $tool_name:expr
}
bootstrap_tool!(
- Rustbook, "src/tools/rustbook", "rustbook", features = rustbook_features();
+ Rustbook, "src/tools/rustbook", "rustbook";
UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen";
Tidy, "src/tools/tidy", "tidy";
Linkchecker, "src/tools/linkchecker", "linkchecker";
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/tools/rustdoc")
+ run.path("src/tools/rustdoc").path("src/librustdoc")
}
fn make_run(run: RunConfig<'_>) {
$path:expr,
$tool_name:expr,
stable = $stable:expr,
+ $(in_tree = $in_tree:expr,)*
$extra_deps:block;)+) => {
$(
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
path: $path,
extra_features: $sel.extra_features,
is_optional_tool: true,
- source_type: SourceType::Submodule,
+ source_type: if false $(|| $in_tree)* {
+ SourceType::InTree
+ } else {
+ SourceType::Submodule
+ },
})
}
}
// to make `./x.py build <tool>` work.
tool_extended!((self, builder),
Cargofmt, rustfmt, "src/tools/rustfmt", "cargo-fmt", stable=true, {};
- CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", stable=true, {};
- Clippy, clippy, "src/tools/clippy", "clippy-driver", stable=true, {};
+ CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", stable=true, in_tree=true, {};
+ Clippy, clippy, "src/tools/clippy", "clippy-driver", stable=true, in_tree=true, {};
Miri, miri, "src/tools/miri", "miri", stable=false, {};
CargoMiri, miri, "src/tools/miri/cargo-miri", "cargo-miri", stable=false, {};
Rls, rls, "src/tools/rls", "rls", stable=true, {
strategy:
matrix:
dist-x86_64-linux: {}
- dist-x86_64-linux-alt:
- IMAGE: dist-x86_64-linux
# The macOS and Windows builds here are currently disabled due to them not being
# overly necessary on `try` builds. We also don't actually have anything that
--- /dev/null
+From c820da85c65c7f3aa9e9cb3ed71ada69bf9b783e Mon Sep 17 00:00:00 2001
+From: Alistair Francis <alistair.francis@wdc.com>
+Date: Tue, 19 Nov 2019 13:06:40 +0100
+Subject: [PATCH] Remove stime() function calls
+
+stime() has been deprecated in glibc 2.31 and replaced with
+clock_settime(). Let's replace the stime() function calls with
+clock_settime() in preperation.
+
+function old new delta
+rdate_main 197 224 +27
+clock_settime - 27 +27
+date_main 926 941 +15
+stime 37 - -37
+------------------------------------------------------------------------------
+(add/remove: 2/2 grow/shrink: 2/0 up/down: 69/-37) Total: 32 bytes
+
+Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
+Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
+
+[Tom Eccles: adjust patch context to apply on top of 1.31.1-stable]
+Signed-off-by: Tom Eccles <tom.eccles@codethink.co.uk>
+---
+ coreutils/date.c | 6 +++++-
+ libbb/missing_syscalls.c | 8 --------
+ util-linux/rdate.c | 8 ++++++--
+ 3 files changed, 11 insertions(+), 11 deletions(-)
+
+diff --git a/coreutils/date.c b/coreutils/date.c
+index 3414d38ae..4ade6abb4 100644
+--- a/coreutils/date.c
++++ b/coreutils/date.c
+@@ -279,6 +279,9 @@ int date_main(int argc UNUSED_PARAM, char **argv)
+ time(&ts.tv_sec);
+ #endif
+ }
++#if !ENABLE_FEATURE_DATE_NANO
++ ts.tv_nsec = 0;
++#endif
+ localtime_r(&ts.tv_sec, &tm_time);
+
+ /* If date string is given, update tm_time, and maybe set date */
+@@ -301,9 +304,10 @@ int date_main(int argc UNUSED_PARAM, char **argv)
+ if (date_str[0] != '@')
+ tm_time.tm_isdst = -1;
+ ts.tv_sec = validate_tm_time(date_str, &tm_time);
++ ts.tv_nsec = 0;
+
+ /* if setting time, set it */
+- if ((opt & OPT_SET) && stime(&ts.tv_sec) < 0) {
++ if ((opt & OPT_SET) && clock_settime(CLOCK_REALTIME, &ts) < 0) {
+ bb_perror_msg("can't set date");
+ }
+ }
+diff --git a/libbb/missing_syscalls.c b/libbb/missing_syscalls.c
+index 87cf59b3d..dc40d9155 100644
+--- a/libbb/missing_syscalls.c
++++ b/libbb/missing_syscalls.c
+@@ -15,14 +15,6 @@ pid_t getsid(pid_t pid)
+ return syscall(__NR_getsid, pid);
+ }
+
+-int stime(const time_t *t)
+-{
+- struct timeval tv;
+- tv.tv_sec = *t;
+- tv.tv_usec = 0;
+- return settimeofday(&tv, NULL);
+-}
+-
+ int sethostname(const char *name, size_t len)
+ {
+ return syscall(__NR_sethostname, name, len);
+diff --git a/util-linux/rdate.c b/util-linux/rdate.c
+index 70f829e7f..878375d78 100644
+--- a/util-linux/rdate.c
++++ b/util-linux/rdate.c
+@@ -95,9 +95,13 @@ int rdate_main(int argc UNUSED_PARAM, char **argv)
+ if (!(flags & 2)) { /* no -p (-s may be present) */
+ if (time(NULL) == remote_time)
+ bb_error_msg("current time matches remote time");
+- else
+- if (stime(&remote_time) < 0)
++ else {
++ struct timespec ts;
++ ts.tv_sec = remote_time;
++ ts.tv_nsec = 0;
++ if (clock_settime(CLOCK_REALTIME, &ts) < 0)
+ bb_perror_msg_and_die("can't set time of day");
++ }
+ }
+
+ if (flags != 1) /* not lone -s */
+--
+2.25.1
+
--- /dev/null
+# based on armhf-gnu/Dockerfile
+FROM ubuntu:20.04
+
+RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
+RUN apt-get update -y && apt-get install -y --no-install-recommends \
+ bc \
+ bison \
+ ca-certificates \
+ cmake \
+ cpio \
+ curl \
+ debian-ports-archive-keyring \
+ debootstrap \
+ flex \
+ gcc \
+ gcc-riscv64-linux-gnu \
+ git \
+ g++-riscv64-linux-gnu \
+ g++ \
+ libc6-dev \
+ libc6-dev-riscv64-cross \
+ make \
+ patch \
+ python3 \
+ qemu-system-misc \
+ xz-utils
+
+ENV ARCH=riscv
+ENV CROSS_COMPILE=riscv64-linux-gnu-
+
+WORKDIR /build
+
+# From https://github.com/michaeljclark/busybear-linux/blob/master/conf/linux.config
+COPY riscv64gc-linux/linux.config /build
+
+# Compile the kernel that we're going to be emulating with. This is
+# basically just done to be compatible with the QEMU target that we're going
+# to be using when running tests.
+RUN curl https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.6.16.tar.xz | tar xJf - && \
+ cp linux.config linux-5.6.16/.config && \
+ cd /build/linux-5.6.16 && \
+ make olddefconfig && \
+ make -j$(nproc) vmlinux
+RUN cp linux-5.6.16/vmlinux /tmp
+RUN rm -rf linux-5.6.16
+
+# Compile an instance of busybox as this provides a lightweight system and init
+# binary which we will boot into. Only trick here is configuring busybox to
+# build static binaries.
+RUN curl https://busybox.net/downloads/busybox-1.31.1.tar.bz2 | tar xjf -
+COPY riscv64gc-linux/0001-Remove-stime-function-calls.patch /build/busybox-1.31.1/
+RUN cd /build/busybox-1.31.1 && \
+ patch -p1 -i 0001-Remove-stime-function-calls.patch && \
+ make defconfig && \
+ sed -i 's/.*CONFIG_STATIC.*/CONFIG_STATIC=y/' .config && \
+ make -j$(nproc) && \
+ make install && \
+ mv _install /tmp/rootfs && \
+ cd /build && \
+ rm -rf busybox-1.31.1
+
+# Download the ubuntu rootfs, which we'll use as a chroot for all our tests
+# This is only needed to provide /lib/* and /usr/lib/*
+WORKDIR /tmp
+RUN debootstrap --variant=minbase --arch=riscv64 --foreign focal /tmp/rootfs/ubuntu
+RUN cd rootfs && mkdir proc sys dev etc etc/init.d
+# rootfs/ubuntu/proc is in a weird state (access fails with ELOOP) until
+# rootfs/ubuntu/debootstrap/debootstrap --second-stage is run (under emulation),
+# but this takes ages. Instead hack it into a good enough state.
+# /proc is used by std::env::current_exe() (which is roughly
+# `readlink /proc/self/exe`)
+RUN cd rootfs/ubuntu && rm -rf proc && mkdir proc
+
+# Copy over our init script, which starts up our test server and also a few other
+# misc tasks
+COPY scripts/qemu-bare-bones-rcS rootfs/etc/init.d/rcS
+RUN chmod +x rootfs/etc/init.d/rcS
+
+# Helper to quickly fill the entropy pool in the kernel
+COPY scripts/qemu-bare-bones-addentropy.c /tmp/addentropy.c
+RUN riscv64-linux-gnu-gcc addentropy.c -o rootfs/addentropy -static
+
+# download and build the riscv bootloader
+RUN git clone https://github.com/riscv/riscv-pk
+WORKDIR /tmp/riscv-pk
+# nothing special about this revision: it is just master at the time of writing
+# v1.0.0 doesn't build
+RUN git checkout 5d9ed238e1cabfbca3c47f50d32894ce94bfc304
+RUN mkdir build && cd build && \
+ ../configure --with-payload=/tmp/vmlinux --host=riscv64-linux-gnu && \
+ make -j$(nproc) && \
+ cp bbl /tmp
+WORKDIR /tmp
+RUN rm -rf /tmp/riscv-pk
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV RUST_CONFIGURE_ARGS --qemu-riscv64-rootfs=/tmp/rootfs
+ENV SCRIPT python3 ../x.py test --target riscv64gc-unknown-linux-gnu
+
+ENV NO_CHANGE_USER=1
--- /dev/null
+CONFIG_DEFAULT_HOSTNAME="busybear"
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_CGROUP_BPF=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_CHECKPOINT_RESTORE=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EXPERT=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_SMP=y
+CONFIG_MODULES=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_PACKET_DIAG=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_NETLINK_DIAG=y
+# CONFIG_WIRELESS is not set
+CONFIG_PCI=y
+CONFIG_DEVTMPFS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_NETDEVICES=y
+CONFIG_VIRTIO_NET=y
+# CONFIG_ETHERNET is not set
+# CONFIG_WLAN is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_HVC_RISCV_SBI=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_VIRTIO_MMIO=y
+CONFIG_SIFIVE_PLIC=y
+CONFIG_RAS=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+# CONFIG_CRYPTO_ECHAINIV is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_PRINTK_TIME=y
ENV RUST_CONFIGURE_ARGS \
--enable-full-tools \
--enable-profiler \
+ --enable-sanitizers \
--disable-docs
ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
COPY dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
COPY dist-various-2/x86_64-fortanix-unknown-sgx-clang-wrap.sh /usr/bin/x86_64-fortanix-unknown-sgx-clang-11
RUN ln -s /usr/bin/x86_64-fortanix-unknown-sgx-clang-11 /usr/bin/x86_64-fortanix-unknown-sgx-clang++-11
-# We pass the commit id of the port of LLVM's libunwind to the build script.
-# Any update to the commit id here, should cause the container image to be re-built from this point on.
-RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "800f95131fe6acd20b96b6f4723ca3c820f3d379"
+RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh
COPY dist-various-2/build-wasi-toolchain.sh /tmp/
RUN /tmp/build-wasi-toolchain.sh
ENV TARGETS=$TARGETS,armv7-unknown-linux-gnueabi
ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabi
-ENV X86_FORTANIX_SGX_LIBS="/x86_64-fortanix-unknown-sgx/lib/"
-
# As per https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1300211
# we need asm in the search path for gcc-7 (for gnux32) but not in the search path of the
# cross compilers.
set -eu
source shared.sh
-if [ -z "$1" ]; then
- echo "Usage: ${0} <commit_id>"
- exit -1
-fi
-
target="x86_64-fortanix-unknown-sgx"
-url="https://github.com/fortanix/llvm-project/archive/${1}.tar.gz"
-repo_name="llvm-project"
install_prereq() {
curl https://apt.llvm.org/llvm-snapshot.gpg.key|apt-key add -
clang-11
}
-build_unwind() {
- set -x
- dir_name="${target}_temp"
- rm -rf ${dir_name}
- mkdir -p ${dir_name}
- pushd ${dir_name}
-
- # Clone Fortanix's fork of llvm-project which has a port of libunwind
- fetch_github_commit_archive "$repo_name" "$url"
- cd "${repo_name}/libunwind"
-
- # Build libunwind
- mkdir -p build
- cd build
- target_CC="CC_${target//-/_}"
- target_CXX="CXX_${target//-/_}"
- target_CFLAGS="CFLAGS_${target//-/_}"
- target_CXXFLAGS="CXXFLAGS_${target//-/_}"
- cmake -DCMAKE_BUILD_TYPE="RELEASE" -DRUST_SGX=1 -G "Unix Makefiles" \
- -DCMAKE_C_COMPILER="${!target_CC}" -DCMAKE_CXX_COMPILER="${!target_CXX}" \
- -DCMAKE_C_FLAGS="${!target_CFLAGS}" -DCMAKE_CXX_FLAGS="${!target_CXXFLAGS}" \
- -DCMAKE_C_COMPILER_TARGET=$target -DCMAKE_CXX_COMPILER_TARGET=$target \
- -DLLVM_ENABLE_WARNINGS=1 -DLIBUNWIND_ENABLE_WERROR=1 -DLIBUNWIND_ENABLE_PEDANTIC=0 \
- -DLLVM_PATH=../../llvm/ ../
- make unwind_static
- install -D "lib/libunwind.a" "/${target}/lib/libunwind.a"
-
- popd
- rm -rf ${dir_name}
-
- { set +x; } 2>/dev/null
-}
-
-set -x
hide_output install_prereq
-build_unwind
COPY x86_64-gnu-tools/checktools.sh /tmp/
-# Run rustbook with `linkcheck` feature enabled
-ENV CHECK_LINKS 1
-
ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
--save-toolstates=/tmp/toolstate/toolstates.json
- name: dist-x86_64-linux
<<: *job-linux-xl
- - name: dist-x86_64-linux-alt
- env:
- IMAGE: dist-x86_64-linux
- <<: *job-linux-xl
-
auto:
<<: *base-ci-job
name: auto
DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
<<: *job-linux-xl
- ####################
- # macOS Builders #
- ####################
-
- - name: dist-x86_64-apple
- env:
- SCRIPT: ./x.py dist
- RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- DIST_REQUIRE_ALL_TOOLS: 1
- <<: *job-macos-xl
-
- - name: dist-x86_64-apple-alt
- env:
- SCRIPT: ./x.py dist
- RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- <<: *job-macos-xl
-
- - name: x86_64-apple
- env:
- SCRIPT: ./x.py test
- RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.8
- MACOSX_STD_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- <<: *job-macos-xl
-
######################
# Windows Builders #
######################
SCRIPT: python x.py dist
<<: *job-windows-xl
+ auto-fallible:
+ <<: *base-ci-job
+ name: auto-fallible
+ env:
+ <<: [*shared-ci-variables, *prod-variables]
+ if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'
+ strategy:
+ matrix:
+ include:
+ ####################
+ # macOS Builders #
+ ####################
+
+ - name: dist-x86_64-apple
+ env:
+ SCRIPT: ./x.py dist
+ RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ DIST_REQUIRE_ALL_TOOLS: 1
+ <<: *job-macos-xl
+
+ - name: dist-x86_64-apple-alt
+ env:
+ SCRIPT: ./x.py dist
+ RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ <<: *job-macos-xl
+
+ - name: x86_64-apple
+ env:
+ SCRIPT: ./x.py test
+ RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.8
+ MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ <<: *job-macos-xl
+
master:
name: master
runs-on: ubuntu-latest
-Subproject commit 30cd9dfe71c446de63826bb4472627af45acc9db
+Subproject commit 4e7c00bece1544d409312ec93467beb62b5bd0cb
-Subproject commit 5555a97f04ad7974ac6fb8fb47c267c4274adf4a
+Subproject commit 616962ad0dd80f34d8b802da038d0aed9dd691bb
-Subproject commit 5d40ba5c2515caffa7790cda621239dc21ef5a72
+Subproject commit 04d5d5d7ba624b6f5016298451f3a63d557f3260
-Subproject commit 7aa82129aa23e7e181efbeb8da03a2a897ef6afc
+Subproject commit 6f94ccb48da6fa4ed0031290f21411cf789f7d5e
This flag allows you to pass the name and location for an external crate of a
direct dependency. Indirect dependencies (dependencies of dependencies) are
located using the [`-L` flag](#option-l-search-path). The given crate name is
-added to the [extern prelude], which is the same as specifying `extern crate`
-within the root module. The given crate name does not need to match the name
+added to the [extern prelude], similar to specifying `extern crate` within the
+root module. The given crate name does not need to match the name
the library was built with.
+Specifying `--extern` has one behavior difference from `extern crate`:
+`--extern` merely makes the crate a _candidate_ for being linked; it does not
+actually link it unless it's actively used. In rare occasions you may wish
+to ensure a crate is linked even if you don't actively use it from your
+code: for example, if it changes the global allocator or if it contains
+`#[no_mangle]` symbols for use by other programming languages. In such
+cases you'll need to use `extern crate`.
+
This flag may be specified multiple times. This flag takes an argument with
either of the following formats:
-# `control_flow_guard`
+# `control-flow-guard`
The tracking issue for this feature is: [#68793](https://github.com/rust-lang/rust/issues/68793).
------------------------
-The rustc flag `-Z control_flow_guard=checks` enables the Windows [Control Flow Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) (CFG) platform security feature.
+The rustc flag `-Z control-flow-guard` enables the Windows [Control Flow Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) (CFG) platform security feature.
CFG is an exploit mitigation designed to enforce control-flow integrity for software running on supported Windows platforms (Windows 8.1 onwards). Specifically, CFG uses runtime checks to validate the target address of every indirect call/jump before allowing the call to complete.
## Testing Control Flow Guard
-The rustc flag `-Z control_flow_guard=nochecks` instructs LLVM to emit the list of valid call targets without inserting runtime checks. This flag should only be used for testing purposes as it does not provide security enforcement.
+The rustc flag `-Z control-flow-guard=nochecks` instructs LLVM to emit the list of valid call targets without inserting runtime checks. This flag should only be used for testing purposes as it does not provide security enforcement.
## Control Flow Guard in libraries
```cmd
rustup toolchain install --force nightly
rustup component add rust-src
-SET RUSTFLAGS=-Z control_flow_guard=checks
+SET RUSTFLAGS=-Z control-flow-guard
cargo +nightly build -Z build-std --target x86_64-pc-windows-msvc
```
```PowerShell
rustup toolchain install --force nightly
rustup component add rust-src
-$Env:RUSTFLAGS = "-Z control_flow_guard=checks"
+$Env:RUSTFLAGS = "-Z control-flow-guard"
cargo +nightly build -Z build-std --target x86_64-pc-windows-msvc
```
* [ThreadSanitizer][clang-tsan] a fast data race detector.
To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=leak`,
-`-Zsanitizer=memory` or `-Zsanitizer=thread`. Only a single sanitizer can be
-enabled at a time.
+`-Zsanitizer=memory` or `-Zsanitizer=thread`.
# AddressSanitizer
First, run a compilation session and provide the `-Zself-profile` flag:
```console
-$ rustc --crate-name foo -Zself-profile`
+$ rustc --crate-name foo -Zself-profile
```
This will generate three files in the working directory such as:
+++ /dev/null
-# `const_if_match`
-
-The tracking issue for this feature is: [#49146]
-
-[#49146]: https://github.com/rust-lang/rust/issues/49146
-
-------------------------
-
-Allows for the use of conditionals (`if` and `match`) in a const context.
-Const contexts include `static`, `static mut`, `const`, `const fn`, const
-generics, and array initializers. Enabling this feature flag will also make
-`&&` and `||` function normally in a const-context by removing the hack that
-replaces them with their non-short-circuiting equivalents, `&` and `|`, in a
-`const` or `static`.
let i: u64 = 3;
let o: u64;
unsafe {
- asm!("
- mov {0}, {1}
- add {0}, {number}
- ", out(reg) o, in(reg) i, number = const 5);
+ asm!(
+ "mov {0}, {1}",
+ "add {0}, {number}",
+ out(reg) o,
+ in(reg) i,
+ number = const 5,
+ );
}
assert_eq!(o, 8);
```
The example shows a few things:
-First we can see that inputs are declared by writing `in` instead of `out`.
+First, we can see that `asm!` allows multiple template string arguments; each
+one is treated as a separate line of assembly code, as if they were all joined
+together with newlines between them. This makes it easy to format assembly
+code.
+
+Second, we can see that inputs are declared by writing `in` instead of `out`.
-Second one of our operands has a type we haven't seen yet, `const`.
+Third, one of our operands has a type we haven't seen yet, `const`.
This tells the compiler to expand this argument to value directly inside the assembly template.
This is only possible for constants and literals.
-Third we can see that we can specify an argument number, or name as in any format string.
+Fourth, we can see that we can specify an argument number, or name as in any format string.
For inline assembly templates this is particularly useful as arguments are often used more than once.
For more complex inline assembly using this facility is generally recommended, as it improves
readability, and allows reordering instructions without changing the argument order.
let b: u64 = 4;
let c: u64 = 4;
unsafe {
- asm!("
- add {0}, {1}
- add {0}, {2}
- ", inout(reg) a, in(reg) b, in(reg) c);
+ asm!(
+ "add {0}, {1}",
+ "add {0}, {2}",
+ inout(reg) a,
+ in(reg) b,
+ in(reg) c,
+ );
}
assert_eq!(a, 12);
```
// ECX 0 selects the L0 cache information.
inout("ecx") 0 => ecx,
lateout("ebx") ebx,
- lateout("edx") _
+ lateout("edx") _,
);
}
// Multiply x by 6 using shifts and adds
let mut x: u64 = 4;
unsafe {
- asm!("
- mov {tmp}, {x}
- shl {tmp}, 1
- shl {x}, 2
- add {x}, {tmp}
- ", x = inout(reg) x, tmp = out(reg) _);
+ asm!(
+ "mov {tmp}, {x}",
+ "shl {tmp}, 1",
+ "shl {x}, 2",
+ "add {x}, {tmp}",
+ x = inout(reg) x,
+ tmp = out(reg) _,
+ );
}
assert_eq!(x, 4 * 6);
```
asm!(
"add {0}, {1}",
inlateout(reg) a, in(reg) b,
- options(pure, nomem, nostack)
+ options(pure, nomem, nostack),
);
}
assert_eq!(a, 8);
operand := reg_operand / "const" const_expr / "sym" path
option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "att_syntax"
options := "options(" option *["," option] [","] ")"
-asm := "asm!(" format_string *("," [ident "="] operand) ["," options] [","] ")"
+asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")"
```
-The macro will initially be supported only on ARM, AArch64, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
+The macro will initially be supported only on ARM, AArch64, Hexagon, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
[format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax
-## Template string
+## Template string arguments
The assembler template uses the same syntax as [format strings][format-syntax] (i.e. placeholders are specified by curly braces). The corresponding arguments are accessed in order, by index, or by name. However, implicit named arguments (introduced by [RFC #2795][rfc-2795]) are not supported.
+An `asm!` invocation may have one or more template string arguments; an `asm!` with multiple template string arguments is treated as if all the strings were concatenated with a `\n` between them. The expected usage is for each template string argument to correspond to a line of assembly code. All template string arguments must appear before any other arguments.
+
As with format strings, named arguments must appear after positional arguments. Explicit register operands must appear at the end of the operand list, after named arguments if any.
Explicit register operands cannot be used by placeholders in the template string. All other named and positional operands must appear at least once in the template string, otherwise a compiler error is generated.
The exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler.
-The 4 targets specified in this RFC (x86, ARM, AArch64, RISC-V) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior.
+The 5 targets specified in this RFC (x86, ARM, AArch64, RISC-V, Hexagon) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior.
[rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795
| AArch64 | `reg` | `x[0-28]`, `x30` | `r` |
| AArch64 | `vreg` | `v[0-31]` | `w` |
| AArch64 | `vreg_low16` | `v[0-15]` | `x` |
-| ARM | `reg` | `r[0-r10]`, `r12`, `r14` | `r` |
+| ARM | `reg` | `r[0-5]` `r7`\*, `r[8-10]`, `r11`\*, `r12`, `r14` | `r` |
| ARM (Thumb) | `reg_thumb` | `r[0-r7]` | `l` |
| ARM (ARM) | `reg_thumb` | `r[0-r10]`, `r12`, `r14` | `l` |
| ARM | `sreg` | `s[0-31]` | `t` |
| NVPTX | `reg64` | None\* | `l` |
| RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |
| RISC-V | `freg` | `f[0-31]` | `f` |
+| Hexagon | `reg` | `r[0-28]` | `r` |
> **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
>
> Note #2: On x86-64 the high byte registers (e.g. `ah`) are only available when used as an explicit register. Specifying the `reg_byte` register class for an operand will always allocate a low byte register.
>
> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
+>
+> Note #4: On ARM the frame pointer is either `r7` or `r11` depending on the platform.
Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
| RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
| RISC-V | `freg` | `f` | `f32` |
| RISC-V | `freg` | `d` | `f64` |
+| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |
> **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target).
| RISC-V | `f[10-17]` | `fa[0-7]` |
| RISC-V | `f[18-27]` | `fs[2-11]` |
| RISC-V | `f[28-31]` | `ft[8-11]` |
+| Hexagon | `r29` | `sp` |
+| Hexagon | `r30` | `fr` |
+| Hexagon | `r31` | `lr` |
Some registers cannot be used for input or output operands:
| Architecture | Unsupported register | Reason |
| ------------ | -------------------- | ------ |
| All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
-| All | `bp` (x86), `r11` (ARM), `x29` (AArch64), `x8` (RISC-V) | The frame pointer cannot be used as an input or output. |
+| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. |
+| ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. |
+| ARM | `r6` | `r6` is used internally by LLVM as a base pointer and therefore cannot be used as an input or output. |
| x86 | `k0` | This is a constant zero register which can't be modified. |
| x86 | `ip` | This is the program counter, not a real register. |
| x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). |
| ARM | `pc` | This is the program counter, not a real register. |
| RISC-V | `x0` | This is a constant zero register which can't be modified. |
| RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
+| Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
## Template modifiers
| NVPTX | `reg64` | None | `rd0` | None |
| RISC-V | `reg` | None | `x1` | None |
| RISC-V | `freg` | None | `f0` | None |
+| Hexagon | `reg` | None | `r0` | None |
> Notes:
> - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register.
[[bench]]
name = "collectionsbenches"
path = "../liballoc/benches/lib.rs"
+test = true
[[bench]]
name = "vec_deque_append_bench"
#[stable(feature = "global_alloc", since = "1.28.0")]
#[inline]
pub unsafe fn alloc(layout: Layout) -> *mut u8 {
- __rust_alloc(layout.size(), layout.align())
+ unsafe { __rust_alloc(layout.size(), layout.align()) }
}
/// Deallocate memory with the global allocator.
#[stable(feature = "global_alloc", since = "1.28.0")]
#[inline]
pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
- __rust_dealloc(ptr, layout.size(), layout.align())
+ unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
}
/// Reallocate memory with the global allocator.
#[stable(feature = "global_alloc", since = "1.28.0")]
#[inline]
pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
- __rust_realloc(ptr, layout.size(), layout.align(), new_size)
+ unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) }
}
/// Allocate zero-initialized memory with the global allocator.
#[stable(feature = "global_alloc", since = "1.28.0")]
#[inline]
pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
- __rust_alloc_zeroed(layout.size(), layout.align())
+ unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) }
}
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline]
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
if layout.size() != 0 {
- dealloc(ptr.as_ptr(), layout)
+ unsafe { dealloc(ptr.as_ptr(), layout) }
}
}
match placement {
ReallocPlacement::InPlace => Err(AllocErr),
ReallocPlacement::MayMove if layout.size() == 0 => {
- let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
+ let new_layout =
+ unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
self.alloc(new_layout, init)
}
ReallocPlacement::MayMove => {
// `realloc` probably checks for `new_size > size` or something similar.
- intrinsics::assume(new_size > size);
- let ptr = realloc(ptr.as_ptr(), layout, new_size);
+ let ptr = unsafe {
+ intrinsics::assume(new_size > size);
+ realloc(ptr.as_ptr(), layout, new_size)
+ };
let memory =
MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size };
- init.init_offset(memory, size);
+ unsafe {
+ init.init_offset(memory, size);
+ }
Ok(memory)
}
}
match placement {
ReallocPlacement::InPlace => Err(AllocErr),
ReallocPlacement::MayMove if new_size == 0 => {
- self.dealloc(ptr, layout);
+ unsafe {
+ self.dealloc(ptr, layout);
+ }
Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
}
ReallocPlacement::MayMove => {
// `realloc` probably checks for `new_size < size` or something similar.
- intrinsics::assume(new_size < size);
- let ptr = realloc(ptr.as_ptr(), layout, new_size);
+ let ptr = unsafe {
+ intrinsics::assume(new_size < size);
+ realloc(ptr.as_ptr(), layout, new_size)
+ };
Ok(MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size })
}
}
#[lang = "exchange_malloc"]
#[inline]
unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
- let layout = Layout::from_size_align_unchecked(size, align);
+ let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
match Global.alloc(layout, AllocInit::Uninitialized) {
Ok(memory) => memory.ptr.as_ptr(),
Err(_) => handle_alloc_error(layout),
// For example if `Box` is changed to `struct Box<T: ?Sized, A: AllocRef>(Unique<T>, A)`,
// this function has to be changed to `fn box_free<T: ?Sized, A: AllocRef>(Unique<T>, A)` as well.
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
- let size = size_of_val(ptr.as_ref());
- let align = min_align_of_val(ptr.as_ref());
- let layout = Layout::from_size_align_unchecked(size, align);
- Global.dealloc(ptr.cast().into(), layout)
+ unsafe {
+ let size = size_of_val(ptr.as_ref());
+ let align = min_align_of_val(ptr.as_ref());
+ let layout = Layout::from_size_align_unchecked(size, align);
+ Global.dealloc(ptr.cast().into(), layout)
+ }
}
/// Abort on memory allocation error or failure.
+// Disabling on android for the time being
+// See https://github.com/rust-lang/rust/issues/73535#event-3477699747
+#![cfg(not(target_os = "android"))]
#![feature(btree_drain_filter)]
#![feature(map_first_last)]
#![feature(repr_simd)]
//! pub struct Foo;
//!
//! #[no_mangle]
+//! #[allow(improper_ctypes_definitions)]
//! pub extern "C" fn foo_new() -> Box<Foo> {
//! Box::new(Foo)
//! }
//!
//! #[no_mangle]
+//! #[allow(improper_ctypes_definitions)]
//! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
//! ```
//!
#[unstable(feature = "box_into_boxed_slice", issue = "71582")]
pub fn into_boxed_slice(boxed: Box<T>) -> Box<[T]> {
// *mut T and *mut [T; 1] have the same size and alignment
- unsafe { Box::from_raw(Box::into_raw(boxed) as *mut [T; 1] as *mut [T]) }
+ unsafe { Box::from_raw(Box::into_raw(boxed) as *mut [T; 1]) }
}
}
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub unsafe fn assume_init(self) -> Box<T> {
- Box::from_raw(Box::into_raw(self) as *mut T)
+ unsafe { Box::from_raw(Box::into_raw(self) as *mut T) }
}
}
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub unsafe fn assume_init(self) -> Box<[T]> {
- Box::from_raw(Box::into_raw(self) as *mut [T])
+ unsafe { Box::from_raw(Box::into_raw(self) as *mut [T]) }
}
}
#[stable(feature = "box_raw", since = "1.4.0")]
#[inline]
pub unsafe fn from_raw(raw: *mut T) -> Self {
- Box(Unique::new_unchecked(raw))
+ Box(unsafe { Unique::new_unchecked(raw) })
}
/// Consumes the `Box`, returning a wrapped raw pointer.
unsafe fn new(data: &'a mut [T], pos: usize) -> Self {
debug_assert!(pos < data.len());
// SAFE: pos should be inside the slice
- let elt = ptr::read(data.get_unchecked(pos));
+ let elt = unsafe { ptr::read(data.get_unchecked(pos)) };
Hole { data, elt: ManuallyDrop::new(elt), pos }
}
unsafe fn get(&self, index: usize) -> &T {
debug_assert!(index != self.pos);
debug_assert!(index < self.data.len());
- self.data.get_unchecked(index)
+ unsafe { self.data.get_unchecked(index) }
}
/// Move hole to new location
unsafe fn move_to(&mut self, index: usize) {
debug_assert!(index != self.pos);
debug_assert!(index < self.data.len());
- let index_ptr: *const _ = self.data.get_unchecked(index);
- let hole_ptr = self.data.get_unchecked_mut(self.pos);
- ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
+ unsafe {
+ let index_ptr: *const _ = self.data.get_unchecked(index);
+ let hole_ptr = self.data.get_unchecked_mut(self.pos);
+ ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
+ }
self.pos = index;
}
}
}
impl<K: Ord, V> BTreeMap<K, V> {
- /// Makes a new empty BTreeMap with a reasonable choice for B.
+ /// Makes a new empty BTreeMap.
+ ///
+ /// Does not allocate anything on its own.
///
/// # Examples
///
fn last(mut self) -> Option<(&'a K, &'a V)> {
self.next_back()
}
+
+ fn min(mut self) -> Option<(&'a K, &'a V)> {
+ self.next()
+ }
+
+ fn max(mut self) -> Option<(&'a K, &'a V)> {
+ self.next_back()
+ }
}
#[stable(feature = "fused", since = "1.26.0")]
fn last(mut self) -> Option<(&'a K, &'a mut V)> {
self.next_back()
}
+
+ fn min(mut self) -> Option<(&'a K, &'a mut V)> {
+ self.next()
+ }
+
+ fn max(mut self) -> Option<(&'a K, &'a mut V)> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
fn last(mut self) -> Option<&'a K> {
self.next_back()
}
+
+ fn min(mut self) -> Option<&'a K> {
+ self.next()
+ }
+
+ fn max(mut self) -> Option<&'a K> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
&mut self,
) -> Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>> {
let edge = self.cur_leaf_edge.as_ref()?;
- ptr::read(edge).next_kv().ok()
+ unsafe { ptr::read(edge).next_kv().ok() }
}
/// Implementation of a typical `DrainFilter::next` method, given the predicate.
fn last(mut self) -> Option<(&'a K, &'a V)> {
self.next_back()
}
+
+ fn min(mut self) -> Option<(&'a K, &'a V)> {
+ self.next()
+ }
+
+ fn max(mut self) -> Option<(&'a K, &'a V)> {
+ self.next_back()
+ }
}
#[stable(feature = "map_values_mut", since = "1.10.0")]
}
unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
- unwrap_unchecked(self.front.as_mut()).next_unchecked()
+ unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() }
}
}
impl<'a, K, V> Range<'a, K, V> {
unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
- unwrap_unchecked(self.back.as_mut()).next_back_unchecked()
+ unsafe { unwrap_unchecked(self.back.as_mut()).next_back_unchecked() }
}
}
fn last(mut self) -> Option<(&'a K, &'a mut V)> {
self.next_back()
}
+
+ fn min(mut self) -> Option<(&'a K, &'a mut V)> {
+ self.next()
+ }
+
+ fn max(mut self) -> Option<(&'a K, &'a mut V)> {
+ self.next_back()
+ }
}
impl<'a, K, V> RangeMut<'a, K, V> {
}
unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
- unwrap_unchecked(self.front.as_mut()).next_unchecked()
+ unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() }
}
}
impl<'a, K, V> RangeMut<'a, K, V> {
unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
- unwrap_unchecked(self.back.as_mut()).next_back_unchecked()
+ unsafe { unwrap_unchecked(self.back.as_mut()).next_back_unchecked() }
}
}
if cfg!(debug_assertions) {
panic!("'unchecked' unwrap on None in BTreeMap");
} else {
- core::intrinsics::unreachable();
+ unsafe {
+ core::intrinsics::unreachable();
+ }
}
})
}
edge = match edge.$adjacent_kv() {
Ok(internal_kv) => return internal_kv,
Err(last_edge) => {
- let parent_edge = last_edge.into_node().deallocate_and_ascend();
- unwrap_unchecked(parent_edge).forget_node_type()
+ unsafe {
+ let parent_edge = last_edge.into_node().deallocate_and_ascend();
+ unwrap_unchecked(parent_edge).forget_node_type()
+ }
}
}
}
/// Safety: The change closure must not panic.
#[inline]
unsafe fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R {
- let value = ptr::read(v);
+ let value = unsafe { ptr::read(v) };
let (new_value, ret) = change(value);
- ptr::write(v, new_value);
+ unsafe {
+ ptr::write(v, new_value);
+ }
ret
}
/// key and value in between.
/// Unsafe because the caller must ensure that the leaf edge is not the last one in the tree.
pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
- replace(self, |leaf_edge| {
- let kv = leaf_edge.next_kv();
- let kv = unwrap_unchecked(kv.ok());
- (kv.next_leaf_edge(), kv.into_kv())
- })
+ unsafe {
+ replace(self, |leaf_edge| {
+ let kv = leaf_edge.next_kv();
+ let kv = unwrap_unchecked(kv.ok());
+ (kv.next_leaf_edge(), kv.into_kv())
+ })
+ }
}
/// Moves the leaf edge handle to the previous leaf edge and returns references to the
/// key and value in between.
/// Unsafe because the caller must ensure that the leaf edge is not the first one in the tree.
pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
- replace(self, |leaf_edge| {
- let kv = leaf_edge.next_back_kv();
- let kv = unwrap_unchecked(kv.ok());
- (kv.next_back_leaf_edge(), kv.into_kv())
- })
+ unsafe {
+ replace(self, |leaf_edge| {
+ let kv = leaf_edge.next_back_kv();
+ let kv = unwrap_unchecked(kv.ok());
+ (kv.next_back_leaf_edge(), kv.into_kv())
+ })
+ }
}
}
/// - The caller must ensure that the leaf edge is not the last one in the tree.
/// - Using the updated handle may well invalidate the returned references.
pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
- let kv = replace(self, |leaf_edge| {
- let kv = leaf_edge.next_kv();
- let kv = unwrap_unchecked(kv.ok());
- (ptr::read(&kv).next_leaf_edge(), kv)
- });
- // Doing the descend (and perhaps another move) invalidates the references
- // returned by `into_kv_mut`, so we have to do this last.
- kv.into_kv_mut()
+ unsafe {
+ let kv = replace(self, |leaf_edge| {
+ let kv = leaf_edge.next_kv();
+ let kv = unwrap_unchecked(kv.ok());
+ (ptr::read(&kv).next_leaf_edge(), kv)
+ });
+ // Doing the descend (and perhaps another move) invalidates the references
+ // returned by `into_kv_mut`, so we have to do this last.
+ kv.into_kv_mut()
+ }
}
/// Moves the leaf edge handle to the previous leaf and returns references to the
/// - The caller must ensure that the leaf edge is not the first one in the tree.
/// - Using the updated handle may well invalidate the returned references.
pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
- let kv = replace(self, |leaf_edge| {
- let kv = leaf_edge.next_back_kv();
- let kv = unwrap_unchecked(kv.ok());
- (ptr::read(&kv).next_back_leaf_edge(), kv)
- });
- // Doing the descend (and perhaps another move) invalidates the references
- // returned by `into_kv_mut`, so we have to do this last.
- kv.into_kv_mut()
+ unsafe {
+ let kv = replace(self, |leaf_edge| {
+ let kv = leaf_edge.next_back_kv();
+ let kv = unwrap_unchecked(kv.ok());
+ (ptr::read(&kv).next_back_leaf_edge(), kv)
+ });
+ // Doing the descend (and perhaps another move) invalidates the references
+ // returned by `into_kv_mut`, so we have to do this last.
+ kv.into_kv_mut()
+ }
}
}
/// if the two preconditions above hold.
/// - Using the updated handle may well invalidate the returned references.
pub unsafe fn next_unchecked(&mut self) -> (K, V) {
- replace(self, |leaf_edge| {
- let kv = next_kv_unchecked_dealloc(leaf_edge);
- let k = ptr::read(kv.reborrow().into_kv().0);
- let v = ptr::read(kv.reborrow().into_kv().1);
- (kv.next_leaf_edge(), (k, v))
- })
+ unsafe {
+ replace(self, |leaf_edge| {
+ let kv = next_kv_unchecked_dealloc(leaf_edge);
+ let k = ptr::read(kv.reborrow().into_kv().0);
+ let v = ptr::read(kv.reborrow().into_kv().1);
+ (kv.next_leaf_edge(), (k, v))
+ })
+ }
}
/// Moves the leaf edge handle to the previous leaf edge and returns the key
/// if the two preconditions above hold.
/// - Using the updated handle may well invalidate the returned references.
pub unsafe fn next_back_unchecked(&mut self) -> (K, V) {
- replace(self, |leaf_edge| {
- let kv = next_back_kv_unchecked_dealloc(leaf_edge);
- let k = ptr::read(kv.reborrow().into_kv().0);
- let v = ptr::read(kv.reborrow().into_kv().1);
- (kv.next_back_leaf_edge(), (k, v))
- })
+ unsafe {
+ replace(self, |leaf_edge| {
+ let kv = next_back_kv_unchecked_dealloc(leaf_edge);
+ let k = ptr::read(kv.reborrow().into_kv().0);
+ let v = ptr::read(kv.reborrow().into_kv().1);
+ (kv.next_back_leaf_edge(), (k, v))
+ })
+ }
}
}
/// `len` of 0), there must be one initialized and valid edge. This function does not set up
/// such an edge.
unsafe fn new() -> Self {
- InternalNode { data: LeafNode::new(), edges: [MaybeUninit::UNINIT; 2 * B] }
+ InternalNode { data: unsafe { LeafNode::new() }, edges: [MaybeUninit::UNINIT; 2 * B] }
}
}
}
unsafe fn from_ptr(ptr: NonNull<LeafNode<K, V>>) -> Self {
- BoxedNode { ptr: Unique::new_unchecked(ptr.as_ptr()) }
+ BoxedNode { ptr: unsafe { Unique::new_unchecked(ptr.as_ptr()) } }
}
fn as_ptr(&self) -> NonNull<LeafNode<K, V>> {
let height = self.height;
let node = self.node;
let ret = self.ascend().ok();
- Global.dealloc(
- node.cast(),
- if height > 0 {
- Layout::new::<InternalNode<K, V>>()
- } else {
- Layout::new::<LeafNode<K, V>>()
- },
- );
+ unsafe {
+ Global.dealloc(
+ node.cast(),
+ if height > 0 {
+ Layout::new::<InternalNode<K, V>>()
+ } else {
+ Layout::new::<LeafNode<K, V>>()
+ },
+ );
+ }
ret
}
}
debug_assert!(first <= self.len());
debug_assert!(after_last <= self.len() + 1);
for i in first..after_last {
- Handle::new_edge(self.reborrow_mut(), i).correct_parent_link();
+ unsafe { Handle::new_edge(self.reborrow_mut(), i) }.correct_parent_link();
}
}
&mut self,
) -> Handle<NodeRef<marker::Mut<'_>, K, V, NodeType>, HandleType> {
// We can't use Handle::new_kv or Handle::new_edge because we don't know our type
- Handle { node: self.node.reborrow_mut(), idx: self.idx, _marker: PhantomData }
+ Handle { node: unsafe { self.node.reborrow_mut() }, idx: self.idx, _marker: PhantomData }
}
}
unsafe fn cast_unchecked<NewType>(
&mut self,
) -> Handle<NodeRef<marker::Mut<'_>, K, V, NewType>, marker::Edge> {
- Handle::new_edge(self.node.cast_unchecked(), self.idx)
+ unsafe { Handle::new_edge(self.node.cast_unchecked(), self.idx) }
}
/// Inserts a new key/value pair and an edge that will go to the right of that new pair
dest_offset: usize,
count: usize,
) {
- ptr::copy_nonoverlapping(source.0.add(source_offset), dest.0.add(dest_offset), count);
- ptr::copy_nonoverlapping(source.1.add(source_offset), dest.1.add(dest_offset), count);
+ unsafe {
+ ptr::copy_nonoverlapping(source.0.add(source_offset), dest.0.add(dest_offset), count);
+ ptr::copy_nonoverlapping(source.1.add(source_offset), dest.1.add(dest_offset), count);
+ }
}
// Source and destination must have the same height.
) {
let source_ptr = source.as_internal_mut().edges.as_mut_ptr();
let dest_ptr = dest.as_internal_mut().edges.as_mut_ptr();
- ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count);
- dest.correct_childrens_parent_links(dest_offset, dest_offset + count);
+ unsafe {
+ ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count);
+ dest.correct_childrens_parent_links(dest_offset, dest_offset + count);
+ }
}
impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
}
unsafe fn slice_insert<T>(slice: &mut [T], idx: usize, val: T) {
- ptr::copy(slice.as_ptr().add(idx), slice.as_mut_ptr().add(idx + 1), slice.len() - idx);
- ptr::write(slice.get_unchecked_mut(idx), val);
+ unsafe {
+ ptr::copy(slice.as_ptr().add(idx), slice.as_mut_ptr().add(idx + 1), slice.len() - idx);
+ ptr::write(slice.get_unchecked_mut(idx), val);
+ }
}
unsafe fn slice_remove<T>(slice: &mut [T], idx: usize) -> T {
- let ret = ptr::read(slice.get_unchecked(idx));
- ptr::copy(slice.as_ptr().add(idx + 1), slice.as_mut_ptr().add(idx), slice.len() - idx - 1);
- ret
+ unsafe {
+ let ret = ptr::read(slice.get_unchecked(idx));
+ ptr::copy(slice.as_ptr().add(idx + 1), slice.as_mut_ptr().add(idx), slice.len() - idx - 1);
+ ret
+ }
}
fn next(&mut self) -> Option<&'a T> {
self.iter.next()
}
+
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
+
fn last(mut self) -> Option<&'a T> {
self.next_back()
}
+
+ fn min(mut self) -> Option<&'a T> {
+ self.next()
+ }
+
+ fn max(mut self) -> Option<&'a T> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
fn next(&mut self) -> Option<T> {
self.iter.next().map(|(k, _)| k)
}
+
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
fn last(mut self) -> Option<&'a T> {
self.next_back()
}
+
+ fn min(mut self) -> Option<&'a T> {
+ self.next()
+ }
+
+ fn max(mut self) -> Option<&'a T> {
+ self.next_back()
+ }
}
#[stable(feature = "btree_range", since = "1.17.0")]
};
(self_len.saturating_sub(other_len), Some(self_len))
}
+
+ fn min(mut self) -> Option<&'a T> {
+ self.next()
+ }
}
#[stable(feature = "fused", since = "1.26.0")]
// the number of elements to less than half the range of usize.
(0, Some(a_len + b_len))
}
+
+ fn min(mut self) -> Option<&'a T> {
+ self.next()
+ }
}
#[stable(feature = "fused", since = "1.26.0")]
IntersectionInner::Answer(Some(_)) => (1, Some(1)),
}
}
+
+ fn min(mut self) -> Option<&'a T> {
+ self.next()
+ }
}
#[stable(feature = "fused", since = "1.26.0")]
// No checked_add - see SymmetricDifference::size_hint.
(max(a_len, b_len), Some(a_len + b_len))
}
+
+ fn min(mut self) -> Option<&'a T> {
+ self.next()
+ }
}
#[stable(feature = "fused", since = "1.26.0")]
/// maintain validity of aliasing pointers.
#[inline]
unsafe fn unlink_node(&mut self, mut node: NonNull<Node<T>>) {
- let node = node.as_mut(); // this one is ours now, we can create an &mut.
+ let node = unsafe { node.as_mut() }; // this one is ours now, we can create an &mut.
// Not creating new mutable (unique!) references overlapping `element`.
match node.prev {
- Some(prev) => (*prev.as_ptr()).next = node.next,
+ Some(prev) => unsafe { (*prev.as_ptr()).next = node.next },
// this node is the head node
None => self.head = node.next,
};
match node.next {
- Some(next) => (*next.as_ptr()).prev = node.prev,
+ Some(next) => unsafe { (*next.as_ptr()).prev = node.prev },
// this node is the tail node
None => self.tail = node.prev,
};
// This method takes care not to create multiple mutable references to whole nodes at the same time,
// to maintain validity of aliasing pointers into `element`.
if let Some(mut existing_prev) = existing_prev {
- existing_prev.as_mut().next = Some(splice_start);
+ unsafe {
+ existing_prev.as_mut().next = Some(splice_start);
+ }
} else {
self.head = Some(splice_start);
}
if let Some(mut existing_next) = existing_next {
- existing_next.as_mut().prev = Some(splice_end);
+ unsafe {
+ existing_next.as_mut().prev = Some(splice_end);
+ }
} else {
self.tail = Some(splice_end);
}
- splice_start.as_mut().prev = existing_prev;
- splice_end.as_mut().next = existing_next;
+ unsafe {
+ splice_start.as_mut().prev = existing_prev;
+ splice_end.as_mut().next = existing_next;
+ }
self.len += splice_length;
}
if let Some(mut split_node) = split_node {
let first_part_head;
let first_part_tail;
- first_part_tail = split_node.as_mut().prev.take();
+ unsafe {
+ first_part_tail = split_node.as_mut().prev.take();
+ }
if let Some(mut tail) = first_part_tail {
- tail.as_mut().next = None;
+ unsafe {
+ tail.as_mut().next = None;
+ }
first_part_head = self.head;
} else {
first_part_head = None;
if let Some(mut split_node) = split_node {
let second_part_head;
let second_part_tail;
- second_part_head = split_node.as_mut().next.take();
+ unsafe {
+ second_part_head = split_node.as_mut().next.take();
+ }
if let Some(mut head) = second_part_head {
- head.as_mut().prev = None;
+ unsafe {
+ head.as_mut().prev = None;
+ }
second_part_tail = self.tail;
} else {
second_part_tail = None;
#![stable(feature = "rust1", since = "1.0.0")]
+// ignore-tidy-filelength
+
use core::array::LengthAtMost32;
use core::cmp::{self, Ordering};
use core::fmt;
/// Turn ptr into a slice
#[inline]
unsafe fn buffer_as_slice(&self) -> &[T] {
- slice::from_raw_parts(self.ptr(), self.cap())
+ unsafe { slice::from_raw_parts(self.ptr(), self.cap()) }
}
/// Turn ptr into a mut slice
#[inline]
unsafe fn buffer_as_mut_slice(&mut self) -> &mut [T] {
- slice::from_raw_parts_mut(self.ptr(), self.cap())
+ unsafe { slice::from_raw_parts_mut(self.ptr(), self.cap()) }
}
/// Moves an element out of the buffer
#[inline]
unsafe fn buffer_read(&mut self, off: usize) -> T {
- ptr::read(self.ptr().add(off))
+ unsafe { ptr::read(self.ptr().add(off)) }
}
/// Writes an element into the buffer, moving it.
#[inline]
unsafe fn buffer_write(&mut self, off: usize, value: T) {
- ptr::write(self.ptr().add(off), value);
+ unsafe {
+ ptr::write(self.ptr().add(off), value);
+ }
}
/// Returns `true` if the buffer is at full capacity.
len,
self.cap()
);
- ptr::copy(self.ptr().add(src), self.ptr().add(dst), len);
+ unsafe {
+ ptr::copy(self.ptr().add(src), self.ptr().add(dst), len);
+ }
}
/// Copies a contiguous block of memory len long from src to dst
len,
self.cap()
);
- ptr::copy_nonoverlapping(self.ptr().add(src), self.ptr().add(dst), len);
+ unsafe {
+ ptr::copy_nonoverlapping(self.ptr().add(src), self.ptr().add(dst), len);
+ }
}
/// Copies a potentially wrapping block of memory len long from src to dest.
// 2 [_ _ A A A A B B _]
// D . . .
//
- self.copy(dst, src, len);
+ unsafe {
+ self.copy(dst, src, len);
+ }
}
(false, false, true) => {
// dst before src, src doesn't wrap, dst wraps
// 3 [B B B B _ _ _ A A]
// . . D .
//
- self.copy(dst, src, dst_pre_wrap_len);
- self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len);
+ unsafe {
+ self.copy(dst, src, dst_pre_wrap_len);
+ self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len);
+ }
}
(true, false, true) => {
// src before dst, src doesn't wrap, dst wraps
// 3 [B B _ _ _ A A A A]
// . . D .
//
- self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len);
- self.copy(dst, src, dst_pre_wrap_len);
+ unsafe {
+ self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len);
+ self.copy(dst, src, dst_pre_wrap_len);
+ }
}
(false, true, false) => {
// dst before src, src wraps, dst doesn't wrap
// 3 [C C _ _ _ B B C C]
// D . . .
//
- self.copy(dst, src, src_pre_wrap_len);
- self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len);
+ unsafe {
+ self.copy(dst, src, src_pre_wrap_len);
+ self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len);
+ }
}
(true, true, false) => {
// src before dst, src wraps, dst doesn't wrap
// 3 [C C A A _ _ _ C C]
// D . . .
//
- self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len);
- self.copy(dst, src, src_pre_wrap_len);
+ unsafe {
+ self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len);
+ self.copy(dst, src, src_pre_wrap_len);
+ }
}
(false, true, true) => {
// dst before src, src wraps, dst wraps
//
debug_assert!(dst_pre_wrap_len > src_pre_wrap_len);
let delta = dst_pre_wrap_len - src_pre_wrap_len;
- self.copy(dst, src, src_pre_wrap_len);
- self.copy(dst + src_pre_wrap_len, 0, delta);
- self.copy(0, delta, len - dst_pre_wrap_len);
+ unsafe {
+ self.copy(dst, src, src_pre_wrap_len);
+ self.copy(dst + src_pre_wrap_len, 0, delta);
+ self.copy(0, delta, len - dst_pre_wrap_len);
+ }
}
(true, true, true) => {
// src before dst, src wraps, dst wraps
//
debug_assert!(src_pre_wrap_len > dst_pre_wrap_len);
let delta = src_pre_wrap_len - dst_pre_wrap_len;
- self.copy(delta, 0, len - src_pre_wrap_len);
- self.copy(0, self.cap() - delta, delta);
- self.copy(dst, src, dst_pre_wrap_len);
+ unsafe {
+ self.copy(delta, 0, len - src_pre_wrap_len);
+ self.copy(0, self.cap() - delta, delta);
+ self.copy(dst, src, dst_pre_wrap_len);
+ }
}
}
}
// Nop
} else if self.head < old_capacity - self.tail {
// B
- self.copy_nonoverlapping(old_capacity, 0, self.head);
+ unsafe {
+ self.copy_nonoverlapping(old_capacity, 0, self.head);
+ }
self.head += old_capacity;
debug_assert!(self.head > self.tail);
} else {
// C
let new_tail = new_capacity - (old_capacity - self.tail);
- self.copy_nonoverlapping(new_tail, self.tail, old_capacity - self.tail);
+ unsafe {
+ self.copy_nonoverlapping(new_tail, self.tail, old_capacity - self.tail);
+ }
self.tail = new_tail;
debug_assert!(self.head < self.tail);
}
unsafe fn rotate_left_inner(&mut self, mid: usize) {
debug_assert!(mid * 2 <= self.len());
- self.wrap_copy(self.head, self.tail, mid);
+ unsafe {
+ self.wrap_copy(self.head, self.tail, mid);
+ }
self.head = self.wrap_add(self.head, mid);
self.tail = self.wrap_add(self.tail, mid);
}
debug_assert!(k * 2 <= self.len());
self.head = self.wrap_sub(self.head, k);
self.tail = self.wrap_sub(self.tail, k);
- self.wrap_copy(self.tail, self.head, k);
+ unsafe {
+ self.wrap_copy(self.tail, self.head, k);
+ }
}
}
use super::*;
-use test;
-
#[bench]
#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
fn bench_push_back_100(b: &mut test::Bencher) {
#![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings
#![allow(explicit_outlives_requirements)]
#![allow(incomplete_features)]
+#![deny(unsafe_op_in_unsafe_fn)]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(test))]
#![feature(allocator_api)]
#![feature(const_generic_impls_guard)]
#![feature(const_generics)]
#![feature(const_in_array_repeat_expressions)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(cow_is_borrowed)]
#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(unicode_internals)]
+#![feature(unsafe_block_in_unsafe_fn)]
#![feature(unsize)]
#![feature(unsized_locals)]
#![feature(allocator_internals)]
/// `#[rustc_force_min_const_fn]` attribute which requires conformance
/// with `min_const_fn` but does not necessarily allow calling it in
/// `stable(...) const fn` / user code not enabling `foo` when
- /// `#[rustc_const_unstable(feature = "foo", ..)]` is present.
+ /// `#[rustc_const_unstable(feature = "foo", issue = "01234")]` is present.
pub const NEW: Self = Self::new();
/// Creates the biggest possible `RawVec` (on the system heap)
///
/// # Panics
///
- /// * Panics if the requested capacity exceeds `usize::MAX` bytes.
- /// * Panics on 32-bit platforms if the requested capacity exceeds
- /// `isize::MAX` bytes.
+ /// Panics if the requested capacity exceeds `isize::MAX` bytes.
///
/// # Aborts
///
/// If the `ptr` and `capacity` come from a `RawVec`, then this is guaranteed.
#[inline]
pub unsafe fn from_raw_parts(ptr: *mut T, capacity: usize) -> Self {
- Self::from_raw_parts_in(ptr, capacity, Global)
+ unsafe { Self::from_raw_parts_in(ptr, capacity, Global) }
}
/// Converts a `Box<[T]>` into a `RawVec<T>`.
);
let me = ManuallyDrop::new(self);
- let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len);
- Box::from_raw(slice)
+ unsafe {
+ let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len);
+ Box::from_raw(slice)
+ }
}
}
/// If the `ptr` and `capacity` come from a `RawVec` created via `a`, then this is guaranteed.
#[inline]
pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, a: A) -> Self {
- Self { ptr: Unique::new_unchecked(ptr), cap: capacity, alloc: a }
+ Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap: capacity, alloc: a }
}
/// Gets a raw pointer to the start of the allocation. Note that this is
///
/// # Panics
///
- /// * Panics if the requested capacity exceeds `usize::MAX` bytes.
- /// * Panics on 32-bit platforms if the requested capacity exceeds
- /// `isize::MAX` bytes.
+ /// Panics if the new capacity exceeds `isize::MAX` bytes.
///
/// # Aborts
///
///
/// # Panics
///
- /// * Panics if the requested capacity exceeds `usize::MAX` bytes.
- /// * Panics on 32-bit platforms if the requested capacity exceeds
- /// `isize::MAX` bytes.
+ /// Panics if the new capacity exceeds `isize::MAX` bytes.
///
/// # Aborts
///
//
// Instead, this just checks that the `RawVec` methods do at
// least go through the Allocator API when it reserves
-
// storage.
// A dumb allocator that consumes a fixed amount of fuel
}
}
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
- Global.dealloc(ptr, layout)
+ unsafe { Global.dealloc(ptr, layout) }
}
}
}
unsafe fn from_ptr(ptr: *mut RcBox<T>) -> Self {
- Self::from_inner(NonNull::new_unchecked(ptr))
+ Self::from_inner(unsafe { NonNull::new_unchecked(ptr) })
}
}
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub unsafe fn assume_init(self) -> Rc<[T]> {
- Rc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _)
+ unsafe { Rc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) }
}
}
/// ```
#[stable(feature = "rc_raw", since = "1.17.0")]
pub unsafe fn from_raw(ptr: *const T) -> Self {
- let offset = data_offset(ptr);
+ let offset = unsafe { data_offset(ptr) };
// Reverse the offset to find the original RcBox.
let fake_ptr = ptr as *mut RcBox<T>;
- let rc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
+ let rc_ptr = unsafe { set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)) };
- Self::from_ptr(rc_ptr)
+ unsafe { Self::from_ptr(rc_ptr) }
}
/// Consumes the `Rc`, returning the wrapped pointer as `NonNull<T>`.
#[inline]
#[unstable(feature = "get_mut_unchecked", issue = "63292")]
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
- &mut this.ptr.as_mut().value
+ unsafe { &mut this.ptr.as_mut().value }
}
#[inline]
// Initialize the RcBox
let inner = mem_to_rcbox(mem.ptr.as_ptr());
- debug_assert_eq!(Layout::for_value(&*inner), layout);
+ unsafe {
+ debug_assert_eq!(Layout::for_value(&*inner), layout);
- ptr::write(&mut (*inner).strong, Cell::new(1));
- ptr::write(&mut (*inner).weak, Cell::new(1));
+ ptr::write(&mut (*inner).strong, Cell::new(1));
+ ptr::write(&mut (*inner).weak, Cell::new(1));
+ }
inner
}
/// Allocates an `RcBox<T>` with sufficient space for an unsized inner value
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
// Allocate for the `RcBox<T>` using the given value.
- Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| {
- set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T>
- })
+ unsafe {
+ Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| {
+ set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T>
+ })
+ }
}
fn from_box(v: Box<T>) -> Rc<T> {
impl<T> Rc<[T]> {
/// Allocates an `RcBox<[T]>` with the given length.
unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> {
- Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| {
- ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>
- })
+ unsafe {
+ Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| {
+ ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>
+ })
+ }
}
}
/// For a slice/trait object, this sets the `data` field and leaves the rest
/// unchanged. For a sized raw pointer, this simply sets the pointer.
unsafe fn set_data_ptr<T: ?Sized, U>(mut ptr: *mut T, data: *mut U) -> *mut T {
- ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8);
+ unsafe {
+ ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8);
+ }
ptr
}
///
/// Unsafe because the caller must either take ownership or bind `T: Copy`
unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> {
- let ptr = Self::allocate_for_slice(v.len());
-
- ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).value as *mut [T] as *mut T, v.len());
-
- Self::from_ptr(ptr)
+ unsafe {
+ let ptr = Self::allocate_for_slice(v.len());
+ ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).value as *mut [T] as *mut T, v.len());
+ Self::from_ptr(ptr)
+ }
}
/// Constructs an `Rc<[T]>` from an iterator known to be of a certain size.
}
}
- let ptr = Self::allocate_for_slice(len);
+ unsafe {
+ let ptr = Self::allocate_for_slice(len);
- let mem = ptr as *mut _ as *mut u8;
- let layout = Layout::for_value(&*ptr);
+ let mem = ptr as *mut _ as *mut u8;
+ let layout = Layout::for_value(&*ptr);
- // Pointer to first element
- let elems = &mut (*ptr).value as *mut [T] as *mut T;
+ // Pointer to first element
+ let elems = &mut (*ptr).value as *mut [T] as *mut T;
- let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 };
+ let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 };
- for (i, item) in iter.enumerate() {
- ptr::write(elems.add(i), item);
- guard.n_elems += 1;
- }
+ for (i, item) in iter.enumerate() {
+ ptr::write(elems.add(i), item);
+ guard.n_elems += 1;
+ }
- // All clear. Forget the guard so it doesn't free the new RcBox.
- forget(guard);
+ // All clear. Forget the guard so it doesn't free the new RcBox.
+ forget(guard);
- Self::from_ptr(ptr)
+ Self::from_ptr(ptr)
+ }
}
}
Self::new()
} else {
// See Rc::from_raw for details
- let offset = data_offset(ptr);
- let fake_ptr = ptr as *mut RcBox<T>;
- let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
- Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") }
+ unsafe {
+ let offset = data_offset(ptr);
+ let fake_ptr = ptr as *mut RcBox<T>;
+ let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
+ Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") }
+ }
}
}
}
// Because it is ?Sized, it will always be the last field in memory.
// Note: This is a detail of the current implementation of the compiler,
// and is not a guaranteed language detail. Do not rely on it outside of std.
- data_offset_align(align_of_val(&*ptr))
+ unsafe { data_offset_align(align_of_val(&*ptr)) }
}
/// Computes the offset of the data field within `RcBox`.
{
let len = v.len();
let v = v.as_mut_ptr();
- let v_mid = v.add(mid);
- let v_end = v.add(len);
+ let (v_mid, v_end) = unsafe { (v.add(mid), v.add(len)) };
// The merge process first copies the shorter run into `buf`. Then it traces the newly copied
// run and the longer run forwards (or backwards), comparing their next unconsumed elements and
if mid <= len - mid {
// The left run is shorter.
- ptr::copy_nonoverlapping(v, buf, mid);
- hole = MergeHole { start: buf, end: buf.add(mid), dest: v };
+ unsafe {
+ ptr::copy_nonoverlapping(v, buf, mid);
+ hole = MergeHole { start: buf, end: buf.add(mid), dest: v };
+ }
// Initially, these pointers point to the beginnings of their arrays.
let left = &mut hole.start;
while *left < hole.end && right < v_end {
// Consume the lesser side.
// If equal, prefer the left run to maintain stability.
- let to_copy = if is_less(&*right, &**left) {
- get_and_increment(&mut right)
- } else {
- get_and_increment(left)
- };
- ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1);
+ unsafe {
+ let to_copy = if is_less(&*right, &**left) {
+ get_and_increment(&mut right)
+ } else {
+ get_and_increment(left)
+ };
+ ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1);
+ }
}
} else {
// The right run is shorter.
- ptr::copy_nonoverlapping(v_mid, buf, len - mid);
- hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid };
+ unsafe {
+ ptr::copy_nonoverlapping(v_mid, buf, len - mid);
+ hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid };
+ }
// Initially, these pointers point past the ends of their arrays.
let left = &mut hole.dest;
while v < *left && buf < *right {
// Consume the greater side.
// If equal, prefer the right run to maintain stability.
- let to_copy = if is_less(&*right.offset(-1), &*left.offset(-1)) {
- decrement_and_get(left)
- } else {
- decrement_and_get(right)
- };
- ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1);
+ unsafe {
+ let to_copy = if is_less(&*right.offset(-1), &*left.offset(-1)) {
+ decrement_and_get(left)
+ } else {
+ decrement_and_get(right)
+ };
+ ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1);
+ }
}
}
// Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of
unsafe fn get_and_increment<T>(ptr: &mut *mut T) -> *mut T {
let old = *ptr;
- *ptr = ptr.offset(1);
+ *ptr = unsafe { ptr.offset(1) };
old
}
unsafe fn decrement_and_get<T>(ptr: &mut *mut T) -> *mut T {
- *ptr = ptr.offset(-1);
+ *ptr = unsafe { ptr.offset(-1) };
*ptr
}
#[stable(feature = "str_box_extras", since = "1.20.0")]
#[inline]
pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
- Box::from_raw(Box::into_raw(v) as *mut str)
+ unsafe { Box::from_raw(Box::into_raw(v) as *mut str) }
}
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String {
- String { vec: Vec::from_raw_parts(buf, length, capacity) }
+ unsafe { String { vec: Vec::from_raw_parts(buf, length, capacity) } }
}
/// Converts a vector of bytes to a `String` without checking that the
let amt = bytes.len();
self.vec.reserve(amt);
- ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx);
- ptr::copy(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt);
- self.vec.set_len(len + amt);
+ unsafe {
+ ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx);
+ ptr::copy(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt);
+ self.vec.set_len(len + amt);
+ }
}
/// Inserts a string slice into this `String` at a byte position.
}
}
+#[stable(feature = "char_to_string_specialization", since = "1.46.0")]
+impl ToString for char {
+ #[inline]
+ fn to_string(&self) -> String {
+ String::from(self.encode_utf8(&mut [0; 4]))
+ }
+}
+
#[stable(feature = "str_to_string_specialization", since = "1.9.0")]
impl ToString for str {
#[inline]
}
unsafe fn from_ptr(ptr: *mut ArcInner<T>) -> Self {
- Self::from_inner(NonNull::new_unchecked(ptr))
+ unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) }
}
}
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub unsafe fn assume_init(self) -> Arc<[T]> {
- Arc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _)
+ unsafe { Arc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) }
}
}
/// ```
#[stable(feature = "rc_raw", since = "1.17.0")]
pub unsafe fn from_raw(ptr: *const T) -> Self {
- let offset = data_offset(ptr);
+ unsafe {
+ let offset = data_offset(ptr);
- // Reverse the offset to find the original ArcInner.
- let fake_ptr = ptr as *mut ArcInner<T>;
- let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
+ // Reverse the offset to find the original ArcInner.
+ let fake_ptr = ptr as *mut ArcInner<T>;
+ let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
- Self::from_ptr(arc_ptr)
+ Self::from_ptr(arc_ptr)
+ }
}
/// Consumes the `Arc`, returning the wrapped pointer as `NonNull<T>`.
#[unstable(feature = "arc_mutate_strong_count", issue = "71983")]
pub unsafe fn incr_strong_count(ptr: *const T) {
// Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
- let arc = mem::ManuallyDrop::new(Arc::<T>::from_raw(ptr));
+ let arc = unsafe { mem::ManuallyDrop::new(Arc::<T>::from_raw(ptr)) };
// Now increase refcount, but don't drop new refcount either
let _arc_clone: mem::ManuallyDrop<_> = arc.clone();
}
#[inline]
#[unstable(feature = "arc_mutate_strong_count", issue = "71983")]
pub unsafe fn decr_strong_count(ptr: *const T) {
- mem::drop(Arc::from_raw(ptr));
+ unsafe { mem::drop(Arc::from_raw(ptr)) };
}
#[inline]
unsafe fn drop_slow(&mut self) {
// Destroy the data at this time, even though we may not free the box
// allocation itself (there may still be weak pointers lying around).
- ptr::drop_in_place(Self::get_mut_unchecked(self));
+ unsafe { ptr::drop_in_place(Self::get_mut_unchecked(self)) };
// Drop the weak ref collectively held by all strong references
drop(Weak { ptr: self.ptr });
// Initialize the ArcInner
let inner = mem_to_arcinner(mem.ptr.as_ptr());
- debug_assert_eq!(Layout::for_value(&*inner), layout);
+ debug_assert_eq!(unsafe { Layout::for_value(&*inner) }, layout);
- ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1));
- ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1));
+ unsafe {
+ ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1));
+ ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1));
+ }
inner
}
/// Allocates an `ArcInner<T>` with sufficient space for an unsized inner value.
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner<T> {
// Allocate for the `ArcInner<T>` using the given value.
- Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| {
- set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T>
- })
+ unsafe {
+ Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| {
+ set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T>
+ })
+ }
}
fn from_box(v: Box<T>) -> Arc<T> {
impl<T> Arc<[T]> {
/// Allocates an `ArcInner<[T]>` with the given length.
unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> {
- Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| {
- ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>
- })
+ unsafe {
+ Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| {
+ ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>
+ })
+ }
}
}
/// For a slice/trait object, this sets the `data` field and leaves the rest
/// unchanged. For a sized raw pointer, this simply sets the pointer.
unsafe fn set_data_ptr<T: ?Sized, U>(mut ptr: *mut T, data: *mut U) -> *mut T {
- ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8);
+ unsafe {
+ ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8);
+ }
ptr
}
///
/// Unsafe because the caller must either take ownership or bind `T: Copy`.
unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> {
- let ptr = Self::allocate_for_slice(v.len());
+ unsafe {
+ let ptr = Self::allocate_for_slice(v.len());
- ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).data as *mut [T] as *mut T, v.len());
+ ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).data as *mut [T] as *mut T, v.len());
- Self::from_ptr(ptr)
+ Self::from_ptr(ptr)
+ }
}
/// Constructs an `Arc<[T]>` from an iterator known to be of a certain size.
}
}
- let ptr = Self::allocate_for_slice(len);
+ unsafe {
+ let ptr = Self::allocate_for_slice(len);
- let mem = ptr as *mut _ as *mut u8;
- let layout = Layout::for_value(&*ptr);
+ let mem = ptr as *mut _ as *mut u8;
+ let layout = Layout::for_value(&*ptr);
- // Pointer to first element
- let elems = &mut (*ptr).data as *mut [T] as *mut T;
+ // Pointer to first element
+ let elems = &mut (*ptr).data as *mut [T] as *mut T;
- let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 };
+ let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 };
- for (i, item) in iter.enumerate() {
- ptr::write(elems.add(i), item);
- guard.n_elems += 1;
- }
+ for (i, item) in iter.enumerate() {
+ ptr::write(elems.add(i), item);
+ guard.n_elems += 1;
+ }
- // All clear. Forget the guard so it doesn't free the new ArcInner.
- mem::forget(guard);
+ // All clear. Forget the guard so it doesn't free the new ArcInner.
+ mem::forget(guard);
- Self::from_ptr(ptr)
+ Self::from_ptr(ptr)
+ }
}
}
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
// We are careful to *not* create a reference covering the "count" fields, as
// this would alias with concurrent access to the reference counts (e.g. by `Weak`).
- &mut (*this.ptr.as_ptr()).data
+ unsafe { &mut (*this.ptr.as_ptr()).data }
}
/// Determine whether this is the unique reference (including weak refs) to
Self::new()
} else {
// See Arc::from_raw for details
- let offset = data_offset(ptr);
- let fake_ptr = ptr as *mut ArcInner<T>;
- let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
- Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") }
+ unsafe {
+ let offset = data_offset(ptr);
+ let fake_ptr = ptr as *mut ArcInner<T>;
+ let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
+ Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") }
+ }
}
}
}
// Because it is `?Sized`, it will always be the last field in memory.
// Note: This is a detail of the current implementation of the compiler,
// and is not a guaranteed language detail. Do not rely on it outside of std.
- data_offset_align(align_of_val(&*ptr))
+ unsafe { data_offset_align(align_of_val(&*ptr)) }
}
/// Computes the offset of the data field within `ArcInner`.
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
// Increment the reference count of the arc to clone it.
unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
- Arc::incr_strong_count(waker as *const W);
+ unsafe { Arc::incr_strong_count(waker as *const W) };
RawWaker::new(
waker as *const (),
&RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
// Wake by value, moving the Arc into the Wake::wake function
unsafe fn wake<W: Wake + Send + Sync + 'static>(waker: *const ()) {
- let waker: Arc<W> = Arc::from_raw(waker as *const W);
+ let waker: Arc<W> = unsafe { Arc::from_raw(waker as *const W) };
<W as Wake>::wake(waker);
}
// Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
unsafe fn wake_by_ref<W: Wake + Send + Sync + 'static>(waker: *const ()) {
- let waker: ManuallyDrop<Arc<W>> = ManuallyDrop::new(Arc::from_raw(waker as *const W));
+ let waker: ManuallyDrop<Arc<W>> =
+ unsafe { ManuallyDrop::new(Arc::from_raw(waker as *const W)) };
<W as Wake>::wake_by_ref(&waker);
}
// Decrement the reference count of the Arc on drop
unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) {
- Arc::decr_strong_count(waker as *const W);
+ unsafe { Arc::decr_strong_count(waker as *const W) };
}
RawWaker::new(
test(size, map.into_iter());
}
+#[test]
+fn test_iter_min_max() {
+ let mut a = BTreeMap::new();
+ assert_eq!(a.iter().min(), None);
+ assert_eq!(a.iter().max(), None);
+ assert_eq!(a.iter_mut().min(), None);
+ assert_eq!(a.iter_mut().max(), None);
+ assert_eq!(a.range(..).min(), None);
+ assert_eq!(a.range(..).max(), None);
+ assert_eq!(a.range_mut(..).min(), None);
+ assert_eq!(a.range_mut(..).max(), None);
+ assert_eq!(a.keys().min(), None);
+ assert_eq!(a.keys().max(), None);
+ assert_eq!(a.values().min(), None);
+ assert_eq!(a.values().max(), None);
+ assert_eq!(a.values_mut().min(), None);
+ assert_eq!(a.values_mut().max(), None);
+ a.insert(1, 42);
+ a.insert(2, 24);
+ assert_eq!(a.iter().min(), Some((&1, &42)));
+ assert_eq!(a.iter().max(), Some((&2, &24)));
+ assert_eq!(a.iter_mut().min(), Some((&1, &mut 42)));
+ assert_eq!(a.iter_mut().max(), Some((&2, &mut 24)));
+ assert_eq!(a.range(..).min(), Some((&1, &42)));
+ assert_eq!(a.range(..).max(), Some((&2, &24)));
+ assert_eq!(a.range_mut(..).min(), Some((&1, &mut 42)));
+ assert_eq!(a.range_mut(..).max(), Some((&2, &mut 24)));
+ assert_eq!(a.keys().min(), Some(&1));
+ assert_eq!(a.keys().max(), Some(&2));
+ assert_eq!(a.values().min(), Some(&24));
+ assert_eq!(a.values().max(), Some(&42));
+ assert_eq!(a.values_mut().min(), Some(&mut 24));
+ assert_eq!(a.values_mut().max(), Some(&mut 42));
+}
+
fn range_keys(map: &BTreeMap<i32, i32>, range: impl RangeBounds<i32>) -> Vec<i32> {
map.range(range)
.map(|(&k, &v)| {
assert_eq!(hash(&x), hash(&y));
}
+#[test]
+fn test_iter_min_max() {
+ let mut a = BTreeSet::new();
+ assert_eq!(a.iter().min(), None);
+ assert_eq!(a.iter().max(), None);
+ assert_eq!(a.range(..).min(), None);
+ assert_eq!(a.range(..).max(), None);
+ assert_eq!(a.difference(&BTreeSet::new()).min(), None);
+ assert_eq!(a.difference(&BTreeSet::new()).max(), None);
+ assert_eq!(a.intersection(&a).min(), None);
+ assert_eq!(a.intersection(&a).max(), None);
+ assert_eq!(a.symmetric_difference(&BTreeSet::new()).min(), None);
+ assert_eq!(a.symmetric_difference(&BTreeSet::new()).max(), None);
+ assert_eq!(a.union(&a).min(), None);
+ assert_eq!(a.union(&a).max(), None);
+ a.insert(1);
+ a.insert(2);
+ assert_eq!(a.iter().min(), Some(&1));
+ assert_eq!(a.iter().max(), Some(&2));
+ assert_eq!(a.range(..).min(), Some(&1));
+ assert_eq!(a.range(..).max(), Some(&2));
+ assert_eq!(a.difference(&BTreeSet::new()).min(), Some(&1));
+ assert_eq!(a.difference(&BTreeSet::new()).max(), Some(&2));
+ assert_eq!(a.intersection(&a).min(), Some(&1));
+ assert_eq!(a.intersection(&a).max(), Some(&2));
+ assert_eq!(a.symmetric_difference(&BTreeSet::new()).min(), Some(&1));
+ assert_eq!(a.symmetric_difference(&BTreeSet::new()).max(), Some(&2));
+ assert_eq!(a.union(&a).min(), Some(&1));
+ assert_eq!(a.union(&a).max(), Some(&2));
+}
+
fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F)
where
F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, &mut dyn FnMut(&i32) -> bool) -> bool,
#![feature(associated_type_bounds)]
#![feature(binary_heap_into_iter_sorted)]
#![feature(binary_heap_drain_sorted)]
-#![feature(vec_remove_item)]
#![feature(split_inclusive)]
#![feature(binary_heap_retain)]
use std::borrow::Cow;
use std::collections::TryReserveError::*;
+use std::fmt::Debug;
use std::mem::size_of;
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::vec::{Drain, IntoIter};
assert_eq!(v, [1, 2, 3, 4, 5, 6, 7]);
}
-#[test]
-fn test_remove_item() {
- let mut v = vec![1, 2, 3];
- v.remove_item(&1);
-
- assert_eq!(v.len(), 2);
- assert_eq!(v, [2, 3]);
-
- let mut w = vec![1, 2, 3];
- w.remove_item(&4);
-
- assert_eq!(w.len(), 3);
- w.remove_item(&4);
-}
-
#[test]
fn test_slice_from_mut() {
let mut values = vec![1, 2, 3, 4, 5];
}
}
}
+
+macro_rules! generate_assert_eq_vec_and_prim {
+ ($name:ident<$B:ident>($type:ty)) => {
+ fn $name<A: PartialEq<$B> + Debug, $B: Debug>(a: Vec<A>, b: $type) {
+ assert!(a == b);
+ assert_eq!(a, b);
+ }
+ };
+}
+
+generate_assert_eq_vec_and_prim! { assert_eq_vec_and_slice <B>(&[B]) }
+generate_assert_eq_vec_and_prim! { assert_eq_vec_and_array_3<B>([B; 3]) }
+
+#[test]
+fn partialeq_vec_and_prim() {
+ assert_eq_vec_and_slice(vec![1, 2, 3], &[1, 2, 3]);
+ assert_eq_vec_and_array_3(vec![1, 2, 3], [1, 2, 3]);
+}
+
+macro_rules! assert_partial_eq_valid {
+ ($a2:ident, $a3:ident; $b2:ident, $b3: ident) => {
+ assert!($a2 == $b2);
+ assert!($a2 != $b3);
+ assert!($a3 != $b2);
+ assert!($a3 == $b3);
+ assert_eq!($a2, $b2);
+ assert_ne!($a2, $b3);
+ assert_ne!($a3, $b2);
+ assert_eq!($a3, $b3);
+ };
+}
+
+#[test]
+fn partialeq_vec_full() {
+ let vec2: Vec<_> = vec![1, 2];
+ let vec3: Vec<_> = vec![1, 2, 3];
+ let slice2: &[_] = &[1, 2];
+ let slice3: &[_] = &[1, 2, 3];
+ let slicemut2: &[_] = &mut [1, 2];
+ let slicemut3: &[_] = &mut [1, 2, 3];
+ let array2: [_; 2] = [1, 2];
+ let array3: [_; 3] = [1, 2, 3];
+ let arrayref2: &[_; 2] = &[1, 2];
+ let arrayref3: &[_; 3] = &[1, 2, 3];
+
+ assert_partial_eq_valid!(vec2,vec3; vec2,vec3);
+ assert_partial_eq_valid!(vec2,vec3; slice2,slice3);
+ assert_partial_eq_valid!(vec2,vec3; slicemut2,slicemut3);
+ assert_partial_eq_valid!(slice2,slice3; vec2,vec3);
+ assert_partial_eq_valid!(slicemut2,slicemut3; vec2,vec3);
+ assert_partial_eq_valid!(vec2,vec3; array2,array3);
+ assert_partial_eq_valid!(vec2,vec3; arrayref2,arrayref3);
+}
use core::array::LengthAtMost32;
use core::cmp::{self, Ordering};
use core::fmt;
-use core::hash::{self, Hash};
+use core::hash::{Hash, Hasher};
use core::intrinsics::{arith_offset, assume};
use core::iter::{FromIterator, FusedIterator, TrustedLen};
use core::marker::PhantomData;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Vec<T> {
- Vec { buf: RawVec::from_raw_parts(ptr, capacity), len: length }
+ unsafe { Vec { buf: RawVec::from_raw_parts(ptr, capacity), len: length } }
}
/// Returns the number of elements the vector can hold without
///
/// # Panics
///
- /// Panics if the new capacity overflows `usize`.
+ /// Panics if the new capacity exceeds `isize::MAX` bytes.
///
/// # Examples
///
///
/// # Panics
///
- /// Panics if the number of elements in the vector overflows a `usize`.
+ /// Panics if the new capacity exceeds `isize::MAX` bytes.
///
/// # Examples
///
/// Appends elements to `Self` from other buffer.
#[inline]
unsafe fn append_elements(&mut self, other: *const [T]) {
- let count = (*other).len();
+ let count = unsafe { (*other).len() };
self.reserve(count);
let len = self.len();
- ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count);
+ unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) };
self.len += count;
}
}
}
-// This code generalises `extend_with_{element,default}`.
+// This code generalizes `extend_with_{element,default}`.
trait ExtendWith<T> {
fn next(&mut self) -> T;
fn last(self) -> T;
impl<T> Vec<T> {
/// Removes the first instance of `item` from the vector if the item exists.
///
- /// # Examples
- ///
- /// ```
- /// # #![feature(vec_remove_item)]
- /// let mut vec = vec![1, 2, 3, 1];
- ///
- /// vec.remove_item(&1);
- ///
- /// assert_eq!(vec, vec![2, 3, 1]);
- /// ```
+ /// This method will be removed soon.
#[unstable(feature = "vec_remove_item", reason = "recently added", issue = "40062")]
+ #[rustc_deprecated(
+ reason = "Removing the first item equal to a needle is already easily possible \
+ with iterators and the current Vec methods. Furthermore, having a method for \
+ one particular case of removal (linear search, only the first item, no swap remove) \
+ but not for others is inconsistent. This method will be removed soon.",
+ since = "1.46.0"
+ )]
pub fn remove_item<V>(&mut self, item: &V) -> Option<T>
where
T: PartialEq<V>,
}
}
+impl SpecFromElem for i8 {
+ #[inline]
+ fn from_elem(elem: i8, n: usize) -> Vec<i8> {
+ if elem == 0 {
+ return Vec { buf: RawVec::with_capacity_zeroed(n), len: n };
+ }
+ unsafe {
+ let mut v = Vec::with_capacity(n);
+ ptr::write_bytes(v.as_mut_ptr(), elem as u8, n);
+ v.set_len(n);
+ v
+ }
+ }
+}
+
impl SpecFromElem for u8 {
#[inline]
fn from_elem(elem: u8, n: usize) -> Vec<u8> {
}
macro_rules! impl_is_zero {
- ($t: ty, $is_zero: expr) => {
+ ($t:ty, $is_zero:expr) => {
unsafe impl IsZero for $t {
#[inline]
fn is_zero(&self) -> bool {
};
}
-impl_is_zero!(i8, |x| x == 0);
impl_is_zero!(i16, |x| x == 0);
impl_is_zero!(i32, |x| x == 0);
impl_is_zero!(i64, |x| x == 0);
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash> Hash for Vec<T> {
#[inline]
- fn hash<H: hash::Hasher>(&self, state: &mut H) {
+ fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&**self, state)
}
}
}
macro_rules! __impl_slice_eq1 {
- ([$($vars:tt)*] $lhs:ty, $rhs:ty, $($constraints:tt)*) => {
- #[stable(feature = "rust1", since = "1.0.0")]
+ ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?, #[$stability:meta]) => {
+ #[$stability]
impl<A, B, $($vars)*> PartialEq<$rhs> for $lhs
where
A: PartialEq<B>,
- $($constraints)*
+ $($ty: $bound)?
{
#[inline]
fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
}
}
-__impl_slice_eq1! { [] Vec<A>, Vec<B>, }
-__impl_slice_eq1! { [] Vec<A>, &[B], }
-__impl_slice_eq1! { [] Vec<A>, &mut [B], }
-__impl_slice_eq1! { [] Cow<'_, [A]>, &[B], A: Clone }
-__impl_slice_eq1! { [] Cow<'_, [A]>, &mut [B], A: Clone }
-__impl_slice_eq1! { [] Cow<'_, [A]>, Vec<B>, A: Clone }
-__impl_slice_eq1! { [const N: usize] Vec<A>, [B; N], [B; N]: LengthAtMost32 }
-__impl_slice_eq1! { [const N: usize] Vec<A>, &[B; N], [B; N]: LengthAtMost32 }
+__impl_slice_eq1! { [] Vec<A>, Vec<B>, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [] Vec<A>, &[B], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [] Vec<A>, &mut [B], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [] &[A], Vec<B>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
+__impl_slice_eq1! { [] &mut [A], Vec<B>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
+__impl_slice_eq1! { [] Cow<'_, [A]>, Vec<B> where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [] Cow<'_, [A]>, &[B] where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [] Cow<'_, [A]>, &mut [B] where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [const N: usize] Vec<A>, [B; N] where [B; N]: LengthAtMost32, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [const N: usize] Vec<A>, &[B; N] where [B; N]: LengthAtMost32, #[stable(feature = "rust1", since = "1.0.0")] }
// NOTE: some less important impls are omitted to reduce code bloat
// FIXME(Centril): Reconsider this?
//__impl_slice_eq1! { [const N: usize] Vec<A>, &mut [B; N], [B; N]: LengthAtMost32 }
+//__impl_slice_eq1! { [const N: usize] [A; N], Vec<B>, [A; N]: LengthAtMost32 }
+//__impl_slice_eq1! { [const N: usize] &[A; N], Vec<B>, [A; N]: LengthAtMost32 }
+//__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec<B>, [A; N]: LengthAtMost32 }
//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], [B; N]: LengthAtMost32 }
//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], [B; N]: LengthAtMost32 }
//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], [B; N]: LengthAtMost32 }
/// Fill that range as much as possible with new elements from the `replace_with` iterator.
/// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.)
unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool {
- let vec = self.vec.as_mut();
+ let vec = unsafe { self.vec.as_mut() };
let range_start = vec.len;
let range_end = self.tail_start;
- let range_slice =
- slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start);
+ let range_slice = unsafe {
+ slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start)
+ };
for place in range_slice {
if let Some(new_item) = replace_with.next() {
- ptr::write(place, new_item);
+ unsafe { ptr::write(place, new_item) };
vec.len += 1;
} else {
return false;
/// Makes room for inserting more elements before the tail.
unsafe fn move_tail(&mut self, additional: usize) {
- let vec = self.vec.as_mut();
+ let vec = unsafe { self.vec.as_mut() };
let len = self.tail_start + self.tail_len;
vec.buf.reserve(len, additional);
let new_tail_start = self.tail_start + additional;
- let src = vec.as_ptr().add(self.tail_start);
- let dst = vec.as_mut_ptr().add(new_tail_start);
- ptr::copy(src, dst, self.tail_len);
+ unsafe {
+ let src = vec.as_ptr().add(self.tail_start);
+ let dst = vec.as_mut_ptr().add(new_tail_start);
+ ptr::copy(src, dst, self.tail_len);
+ }
self.tail_start = new_tail_start;
}
}
[[bench]]
name = "corebenches"
path = "../libcore/benches/lib.rs"
+test = true
[dev-dependencies]
rand = "0.7"
+// wasm32 does not support benches (no time).
+#![cfg(not(target_arch = "wasm32"))]
#![feature(flt2dec)]
#![feature(test)]
/// [`Into`]: trait.Into.html
/// [`from`]: trait.From.html#tymethod.from
/// [book]: ../../book/ch09-00-error-handling.html
+#[rustc_diagnostic_item = "from_trait"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(on(
all(_Self = "&str", T = "std::string::String"),
nzint_impl_from! { NonZeroU32, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU32, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU64, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+
+macro_rules! nzint_impl_try_from_int {
+ ($Int: ty, $NonZeroInt: ty, #[$attr:meta], $doc: expr) => {
+ #[$attr]
+ #[doc = $doc]
+ impl TryFrom<$Int> for $NonZeroInt {
+ type Error = TryFromIntError;
+
+ #[inline]
+ fn try_from(value: $Int) -> Result<Self, Self::Error> {
+ Self::new(value).ok_or(TryFromIntError(()))
+ }
+ }
+ };
+ ($Int: ty, $NonZeroInt: ty, #[$attr:meta]) => {
+ nzint_impl_try_from_int!($Int,
+ $NonZeroInt,
+ #[$attr],
+ concat!("Attempts to convert `",
+ stringify!($Int),
+ "` to `",
+ stringify!($NonZeroInt),
+ "`."));
+ }
+}
+
+// Int -> Non-zero Int
+nzint_impl_try_from_int! { u8, NonZeroU8, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { u16, NonZeroU16, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { u32, NonZeroU32, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { u64, NonZeroU64, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { u128, NonZeroU128, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { usize, NonZeroUsize, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i8, NonZeroI8, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i16, NonZeroI16, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i32, NonZeroI32, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i64, NonZeroI64, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i128, NonZeroI128, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { isize, NonZeroIsize, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[stable(feature = "futures_api", since = "1.36.0")]
#[lang = "future_trait"]
+#[rustc_on_unimplemented(label = "`{Self}` is not a future", message = "`{Self}` is not a future")]
pub trait Future {
/// The type of value produced on completion.
#[stable(feature = "futures_api", since = "1.36.0")]
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i16(&mut self, i: i16) {
- self.write(&i.to_ne_bytes())
+ self.write_u16(i as u16)
}
/// Writes a single `i32` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i32(&mut self, i: i32) {
- self.write(&i.to_ne_bytes())
+ self.write_u32(i as u32)
}
/// Writes a single `i64` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i64(&mut self, i: i64) {
- self.write(&i.to_ne_bytes())
+ self.write_u64(i as u64)
}
/// Writes a single `i128` into this hasher.
#[inline]
#[stable(feature = "i128", since = "1.26.0")]
fn write_i128(&mut self, i: i128) {
- self.write(&i.to_ne_bytes())
+ self.write_u128(i as u128)
}
/// Writes a single `isize` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_isize(&mut self, i: isize) {
- self.write(&i.to_ne_bytes())
+ self.write_usize(i as usize)
}
}
///
/// The stabilized version of this intrinsic is
/// [`std::any::type_name`](../../std/any/fn.type_name.html)
- #[rustc_const_unstable(feature = "const_type_name", issue = "none")]
+ #[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
pub fn type_name<T: ?Sized>() -> &'static str;
/// Gets an identifier which is globally unique to the specified type. This
///
/// The stabilized version of this intrinsic is
/// [`std::any::TypeId::of`](../../std/any/struct.TypeId.html#method.of)
- #[rustc_const_unstable(feature = "const_type_id", issue = "none")]
+ #[rustc_const_unstable(feature = "const_type_id", issue = "41875")]
pub fn type_id<T: ?Sized + 'static>() -> u64;
/// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
/// implements `Copy`.
///
/// If the actual type neither requires drop glue nor implements
- /// `Copy`, then may return `true` or `false`.
+ /// `Copy`, then the return value of this function is unspecified.
///
/// The stabilized version of this intrinsic is
/// [`std::mem::needs_drop`](../../std/mem/fn.needs_drop.html).
#[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
+ /// Returns the number of variants of the type `T` cast to a `usize`;
+ /// if `T` has no variants, returns 0. Uninhabited variants will be counted.
+ ///
+ /// The to-be-stabilized version of this intrinsic is
+ /// [`std::mem::variant_count`](../../std/mem/fn.variant_count.html)
+ #[rustc_const_unstable(feature = "variant_count", issue = "73662")]
+ #[cfg(not(bootstrap))]
+ pub fn variant_count<T>() -> usize;
+
/// Rust's "try catch" construct which invokes the function pointer `try_fn`
/// with the data pointer `data`.
///
pub fn nontemporal_store<T>(ptr: *mut T, val: T);
/// See documentation of `<*const T>::offset_from` for details.
- #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "none")]
+ #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
/// Internal hook used by Miri to implement unwinding.
///
/// Perma-unstable: do not use.
pub fn miri_start_panic(payload: *mut u8) -> !;
+
+ /// Internal placeholder for injecting code coverage counters when the "instrument-coverage"
+ /// option is enabled. The placeholder is replaced with `llvm.instrprof.increment` during code
+ /// generation.
+ #[cfg(not(bootstrap))]
+ #[lang = "count_code_region"]
+ pub fn count_code_region(index: u32);
+
+ /// See documentation of `<*const T>::guaranteed_eq` for details.
+ #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+ #[cfg(not(bootstrap))]
+ pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool;
+
+ /// See documentation of `<*const T>::guaranteed_ne` for details.
+ #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+ #[cfg(not(bootstrap))]
+ pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
+}
+
+#[rustc_const_unstable(feature = "variant_count", issue = "73662")]
+#[cfg(bootstrap)]
+pub const fn variant_count<T>() -> usize {
+ 0
}
// Some functions are defined here because they accidentally got made
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
}
- debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer");
- debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer");
- debug_assert!(is_nonoverlapping(src, dst, count), "attempt to copy to overlapping memory");
+ if cfg!(debug_assertions)
+ && !(is_aligned_and_not_null(src)
+ && is_aligned_and_not_null(dst)
+ && is_nonoverlapping(src, dst, count))
+ {
+ // Not panicking to keep codegen impact smaller.
+ abort();
+ }
copy_nonoverlapping(src, dst, count)
}
fn copy<T>(src: *const T, dst: *mut T, count: usize);
}
- debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer");
- debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer");
+ if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
+ // Not panicking to keep codegen impact smaller.
+ abort();
+ }
copy(src, dst, count)
}
}
/// Applies function to the elements of iterator and returns
- /// the first non-none result or the first error.
+ /// the first true result or the first error.
///
/// # Examples
///
/// ```
#[inline]
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
- fn try_find<F, E, R>(&mut self, mut f: F) -> Result<Option<Self::Item>, E>
+ fn try_find<F, R>(&mut self, f: F) -> Result<Option<Self::Item>, R::Error>
where
Self: Sized,
F: FnMut(&Self::Item) -> R,
- R: Try<Ok = bool, Error = E>,
- {
- self.try_fold((), move |(), x| match f(&x).into_result() {
- Ok(false) => LoopState::Continue(()),
- Ok(true) => LoopState::Break(Ok(x)),
- Err(x) => LoopState::Break(Err(x)),
- })
- .break_value()
- .transpose()
+ R: Try<Ok = bool>,
+ {
+ #[inline]
+ fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> LoopState<(), Result<T, R::Error>>
+ where
+ F: FnMut(&T) -> R,
+ R: Try<Ok = bool>,
+ {
+ move |(), x| match f(&x).into_result() {
+ Ok(false) => LoopState::Continue(()),
+ Ok(true) => LoopState::Break(Ok(x)),
+ Err(x) => LoopState::Break(Err(x)),
+ }
+ }
+
+ self.try_fold((), check(f)).break_value().transpose()
}
/// Searches for an element in an iterator, returning its index.
#![feature(const_ascii_ctype_on_intrinsics)]
#![feature(const_alloc_layout)]
#![feature(const_discriminant)]
-#![feature(const_if_match)]
-#![feature(const_loop)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
+#![cfg_attr(bootstrap, feature(const_loop))]
#![feature(const_checked_int_methods)]
#![feature(const_euclidean_int_methods)]
#![feature(const_overflowing_int_methods)]
#![feature(const_generics)]
#![feature(const_ptr_offset)]
#![feature(const_ptr_offset_from)]
+#![cfg_attr(not(bootstrap), feature(const_raw_ptr_comparison))]
#![feature(const_result)]
#![feature(const_slice_from_raw_parts)]
#![feature(const_slice_ptr_len)]
#![feature(unsized_locals)]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
+#![feature(variant_count)]
#![feature(doc_alias)]
#![feature(mmx_target_feature)]
#![feature(tbm_target_feature)]
// crate uses the this crate as its libcore.
#[path = "../stdarch/crates/core_arch/src/mod.rs"]
#[allow(missing_docs, missing_debug_implementations, dead_code, unused_imports)]
+// FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is
+// merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet.
+#[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))]
#[unstable(feature = "stdsimd", issue = "48556")]
mod core_arch;
/// - an (unstable) [extern type], then this function is always safe to
/// call, but may panic or otherwise return the wrong value, as the
/// extern type's layout is not known. This is the same behavior as
-/// [`size_of_val`] on a reference to an extern type tail.
+/// [`size_of_val`] on a reference to a type with an extern type tail.
/// - otherwise, it is conservatively not allowed to call this function.
///
/// [slice]: ../../std/primitive.slice.html
/// [trait object]: ../../book/ch17-02-trait-objects.html
/// [extern type]: ../../unstable-book/language-features/extern-types.html
+/// [`size_of_val`]: ../../core/mem/fn.size_of_val.html
///
/// # Examples
///
/// - an (unstable) [extern type], then this function is always safe to
/// call, but may panic or otherwise return the wrong value, as the
/// extern type's layout is not known. This is the same behavior as
-/// [`align_of_val`] on a reference to an extern type tail.
+/// [`align_of_val`] on a reference to a type with an extern type tail.
/// - otherwise, it is conservatively not allowed to call this function.
///
/// [slice]: ../../std/primitive.slice.html
/// [trait object]: ../../book/ch17-02-trait-objects.html
/// [extern type]: ../../unstable-book/language-features/extern-types.html
+/// [`align_of_val`]: ../../core/mem/fn.align_of_val.html
///
/// # Examples
///
/// This means that, for example, the padding byte in `(u8, u16)` is not
/// necessarily zeroed.
///
-/// There is no guarantee that an all-zero byte-pattern represents a valid value of
-/// some type `T`. For example, the all-zero byte-pattern is not a valid value
-/// for reference types (`&T` and `&mut T`). Using `zeroed` on such types
-/// causes immediate [undefined behavior][ub] because [the Rust compiler assumes][inv]
-/// that there always is a valid value in a variable it considers initialized.
+/// There is no guarantee that an all-zero byte-pattern represents a valid value
+/// of some type `T`. For example, the all-zero byte-pattern is not a valid value
+/// for reference types (`&T`, `&mut T`) and functions pointers. Using `zeroed`
+/// on such types causes immediate [undefined behavior][ub] because [the Rust
+/// compiler assumes][inv] that there always is a valid value in a variable it
+/// considers initialized.
///
/// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed].
/// It is useful for FFI sometimes, but should generally be avoided.
/// use std::mem;
///
/// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior!
+/// let _y: fn() = unsafe { mem::zeroed() }; // And again!
/// ```
#[inline(always)]
#[stable(feature = "rust1", since = "1.0.0")]
pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
Discriminant(intrinsics::discriminant_value(v))
}
+
+/// Returns the number of variants in the enum type `T`.
+///
+/// If `T` is not an enum, calling this function will not result in undefined behavior, but the
+/// return value is unspecified. Equally, if `T` is an enum with more variants than `usize::MAX`
+/// the return value is unspecified. Uninhabited variants will be counted.
+///
+/// # Examples
+///
+/// ```
+/// # #![feature(never_type)]
+/// # #![feature(variant_count)]
+///
+/// use std::mem;
+///
+/// enum Void {}
+/// enum Foo { A(&'static str), B(i32), C(i32) }
+///
+/// assert_eq!(mem::variant_count::<Void>(), 0);
+/// assert_eq!(mem::variant_count::<Foo>(), 3);
+///
+/// assert_eq!(mem::variant_count::<Option<!>>(), 2);
+/// assert_eq!(mem::variant_count::<Result<!, !>>(), 2);
+/// ```
+#[inline(always)]
+#[unstable(feature = "variant_count", issue = "73662")]
+#[rustc_const_unstable(feature = "variant_count", issue = "73662")]
+pub const fn variant_count<T>() -> usize {
+ intrinsics::variant_count::<T>()
+}
Basic usage:
```
-", $Feature, "#![feature(leading_trailing_ones)]
-let n = -1", stringify!($SelfT), ";
+", $Feature, "let n = -1", stringify!($SelfT), ";
assert_eq!(n.leading_ones(), ", stringify!($BITS), ");",
$EndFeature, "
```"),
- #[unstable(feature = "leading_trailing_ones", issue = "57969")]
+ #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
#[inline]
pub const fn leading_ones(self) -> u32 {
(self as $UnsignedT).leading_ones()
Basic usage:
```
-", $Feature, "#![feature(leading_trailing_ones)]
-let n = 3", stringify!($SelfT), ";
+", $Feature, "let n = 3", stringify!($SelfT), ";
assert_eq!(n.trailing_ones(), 2);",
$EndFeature, "
```"),
- #[unstable(feature = "leading_trailing_ones", issue = "57969")]
+ #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
#[inline]
pub const fn trailing_ones(self) -> u32 {
(self as $UnsignedT).trailing_ones()
#[stable(feature = "no_panic_abs", since = "1.13.0")]
#[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
#[allow(unused_attributes)]
- #[allow_internal_unstable(const_if_match)]
+ #[cfg_attr(bootstrap, allow_internal_unstable(const_if_match))]
#[inline]
pub const fn wrapping_abs(self) -> Self {
if self.is_negative() {
#[stable(feature = "wrapping", since = "1.7.0")]
#[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
#[allow(unused_attributes)]
- #[allow_internal_unstable(const_if_match)]
+ #[cfg_attr(bootstrap, allow_internal_unstable(const_if_match))]
pub const fn overflowing_neg(self) -> (Self, bool) {
if self == Self::MIN {
(Self::MIN, true)
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
#[allow(unused_attributes)]
- #[allow_internal_unstable(const_if_match)]
+ #[cfg_attr(bootstrap, allow_internal_unstable(const_if_match))]
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn abs(self) -> Self {
Basic usage:
```
-", $Feature, "#![feature(leading_trailing_ones)]
-let n = !(", stringify!($SelfT), "::MAX >> 2);
+", $Feature, "let n = !(", stringify!($SelfT), "::MAX >> 2);
assert_eq!(n.leading_ones(), 2);", $EndFeature, "
```"),
- #[unstable(feature = "leading_trailing_ones", issue = "57969")]
+ #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
#[inline]
pub const fn leading_ones(self) -> u32 {
(!self).leading_zeros()
Basic usage:
```
-", $Feature, "#![feature(leading_trailing_ones)]
-let n = 0b1010111", stringify!($SelfT), ";
+", $Feature, "let n = 0b1010111", stringify!($SelfT), ";
assert_eq!(n.trailing_ones(), 3);", $EndFeature, "
```"),
- #[unstable(feature = "leading_trailing_ones", issue = "57969")]
+ #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
#[inline]
pub const fn trailing_ones(self) -> u32 {
(!self).trailing_zeros()
#[must_use = "closures are lazy and do nothing unless called"]
pub trait FnOnce<Args> {
/// The returned type after the call operator is used.
+ #[cfg_attr(not(bootstrap), lang = "fn_once_output")]
#[stable(feature = "fn_once_output", since = "1.12.0")]
type Output;
ops::{self, Deref, DerefMut},
};
-// Note that this is not a lang item per se, but it has a hidden dependency on
-// `Iterator`, which is one. The compiler assumes that the `next` method of
-// `Iterator` is an enumeration with one type parameter and two variants,
-// which basically means it must be `Option`.
-
/// The `Option` type. See [the module level documentation](index.html) for more.
#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
#[rustc_diagnostic_item = "option_type"]
intrinsics::ptr_offset_from(self, origin)
}
+ /// Returns whether two pointers are guaranteed to be equal.
+ ///
+ /// At runtime this function behaves like `self == other`.
+ /// However, in some contexts (e.g., compile-time evaluation),
+ /// it is not always possible to determine equality of two pointers, so this function may
+ /// spuriously return `false` for pointers that later actually turn out to be equal.
+ /// But when it returns `true`, the pointers are guaranteed to be equal.
+ ///
+ /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
+ /// comparisons for which both functions return `false`.
+ ///
+ /// [`guaranteed_ne`]: #method.guaranteed_ne
+ ///
+ /// The return value may change depending on the compiler version and unsafe code may not
+ /// rely on the result of this function for soundness. It is suggested to only use this function
+ /// for performance optimizations where spurious `false` return values by this function do not
+ /// affect the outcome, but just the performance.
+ /// The consequences of using this method to make runtime and compile-time code behave
+ /// differently have not been explored. This method should not be used to introduce such
+ /// differences, and it should also not be stabilized before we have a better understanding
+ /// of this issue.
+ #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+ #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+ #[inline]
+ #[cfg(not(bootstrap))]
+ pub const fn guaranteed_eq(self, other: *const T) -> bool
+ where
+ T: Sized,
+ {
+ intrinsics::ptr_guaranteed_eq(self, other)
+ }
+
+ /// Returns whether two pointers are guaranteed to be inequal.
+ ///
+ /// At runtime this function behaves like `self != other`.
+ /// However, in some contexts (e.g., compile-time evaluation),
+ /// it is not always possible to determine the inequality of two pointers, so this function may
+ /// spuriously return `false` for pointers that later actually turn out to be inequal.
+ /// But when it returns `true`, the pointers are guaranteed to be inequal.
+ ///
+ /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
+ /// comparisons for which both functions return `false`.
+ ///
+ /// [`guaranteed_eq`]: #method.guaranteed_eq
+ ///
+ /// The return value may change depending on the compiler version and unsafe code may not
+ /// rely on the result of this function for soundness. It is suggested to only use this function
+ /// for performance optimizations where spurious `false` return values by this function do not
+ /// affect the outcome, but just the performance.
+ /// The consequences of using this method to make runtime and compile-time code behave
+ /// differently have not been explored. This method should not be used to introduce such
+ /// differences, and it should also not be stabilized before we have a better understanding
+ /// of this issue.
+ #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+ #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+ #[inline]
+ #[cfg(not(bootstrap))]
+ pub const fn guaranteed_ne(self, other: *const T) -> bool
+ where
+ T: Sized,
+ {
+ intrinsics::ptr_guaranteed_ne(self, other)
+ }
+
/// Calculates the distance between two pointers. The returned value is in
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
///
/// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2);
/// ```
#[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")]
+ #[rustc_deprecated(
+ since = "1.46.0",
+ reason = "Pointer distances across allocation \
+ boundaries are not typically meaningful. \
+ Use integer subtraction if you really need this."
+ )]
#[inline]
pub fn wrapping_offset_from(self, origin: *const T) -> isize
where
use crate::cmp::Ordering;
use crate::fmt;
use crate::hash;
-use crate::intrinsics::{self, is_aligned_and_not_null, is_nonoverlapping};
+use crate::intrinsics::{self, abort, is_aligned_and_not_null, is_nonoverlapping};
use crate::mem::{self, MaybeUninit};
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[stable(feature = "swap_nonoverlapping", since = "1.27.0")]
pub unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
- debug_assert!(is_aligned_and_not_null(x), "attempt to swap unaligned or null pointer");
- debug_assert!(is_aligned_and_not_null(y), "attempt to swap unaligned or null pointer");
- debug_assert!(is_nonoverlapping(x, y, count), "attempt to swap overlapping memory");
+ if cfg!(debug_assertions)
+ && !(is_aligned_and_not_null(x)
+ && is_aligned_and_not_null(y)
+ && is_nonoverlapping(x, y, count))
+ {
+ // Not panicking to keep codegen impact smaller.
+ abort();
+ }
let x = x as *mut u8;
let y = y as *mut u8;
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn write<T>(dst: *mut T, src: T) {
- debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer");
+ if cfg!(debug_assertions) && !is_aligned_and_not_null(dst) {
+ // Not panicking to keep codegen impact smaller.
+ abort();
+ }
intrinsics::move_val_init(&mut *dst, src)
}
#[inline]
#[stable(feature = "volatile", since = "1.9.0")]
pub unsafe fn read_volatile<T>(src: *const T) -> T {
- debug_assert!(is_aligned_and_not_null(src), "attempt to read from unaligned or null pointer");
+ if cfg!(debug_assertions) && !is_aligned_and_not_null(src) {
+ // Not panicking to keep codegen impact smaller.
+ abort();
+ }
intrinsics::volatile_load(src)
}
#[inline]
#[stable(feature = "volatile", since = "1.9.0")]
pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
- debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer");
+ if cfg!(debug_assertions) && !is_aligned_and_not_null(dst) {
+ // Not panicking to keep codegen impact smaller.
+ abort();
+ }
intrinsics::volatile_store(dst, src);
}
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J }
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K }
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L }
+
+/// Create a `const` raw pointer to a place, without creating an intermediate reference.
+///
+/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned
+/// and points to initialized data. For cases where those requirements do not hold,
+/// raw pointers should be used instead. However, `&expr as *const _` creates a reference
+/// before casting it to a raw pointer, and that reference is subject to the same rules
+/// as all other references. This macro can create a raw pointer *without* creating
+/// a reference first.
+///
+/// # Example
+///
+/// ```
+/// #![feature(raw_ref_macros)]
+/// use std::ptr;
+///
+/// #[repr(packed)]
+/// struct Packed {
+/// f1: u8,
+/// f2: u16,
+/// }
+///
+/// let packed = Packed { f1: 1, f2: 2 };
+/// // `&packed.f2` would create an unaligned reference, and thus be Undefined Behavior!
+/// let raw_f2 = ptr::raw_const!(packed.f2);
+/// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2);
+/// ```
+#[unstable(feature = "raw_ref_macros", issue = "73394")]
+#[rustc_macro_transparency = "semitransparent"]
+#[allow_internal_unstable(raw_ref_op)]
+pub macro raw_const($e:expr) {
+ &raw const $e
+}
+
+/// Create a `mut` raw pointer to a place, without creating an intermediate reference.
+///
+/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned
+/// and points to initialized data. For cases where those requirements do not hold,
+/// raw pointers should be used instead. However, `&mut expr as *mut _` creates a reference
+/// before casting it to a raw pointer, and that reference is subject to the same rules
+/// as all other references. This macro can create a raw pointer *without* creating
+/// a reference first.
+///
+/// # Example
+///
+/// ```
+/// #![feature(raw_ref_macros)]
+/// use std::ptr;
+///
+/// #[repr(packed)]
+/// struct Packed {
+/// f1: u8,
+/// f2: u16,
+/// }
+///
+/// let mut packed = Packed { f1: 1, f2: 2 };
+/// // `&mut packed.f2` would create an unaligned reference, and thus be Undefined Behavior!
+/// let raw_f2 = ptr::raw_mut!(packed.f2);
+/// unsafe { raw_f2.write_unaligned(42); }
+/// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference.
+/// ```
+#[unstable(feature = "raw_ref_macros", issue = "73394")]
+#[rustc_macro_transparency = "semitransparent"]
+#[allow_internal_unstable(raw_ref_op)]
+pub macro raw_mut($e:expr) {
+ &raw mut $e
+}
if self.is_null() { None } else { Some(&mut *self) }
}
+ /// Returns whether two pointers are guaranteed to be equal.
+ ///
+ /// At runtime this function behaves like `self == other`.
+ /// However, in some contexts (e.g., compile-time evaluation),
+ /// it is not always possible to determine equality of two pointers, so this function may
+ /// spuriously return `false` for pointers that later actually turn out to be equal.
+ /// But when it returns `true`, the pointers are guaranteed to be equal.
+ ///
+ /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
+ /// comparisons for which both functions return `false`.
+ ///
+ /// [`guaranteed_ne`]: #method.guaranteed_ne
+ ///
+ /// The return value may change depending on the compiler version and unsafe code may not
+ /// rely on the result of this function for soundness. It is suggested to only use this function
+ /// for performance optimizations where spurious `false` return values by this function do not
+ /// affect the outcome, but just the performance.
+ /// The consequences of using this method to make runtime and compile-time code behave
+ /// differently have not been explored. This method should not be used to introduce such
+ /// differences, and it should also not be stabilized before we have a better understanding
+ /// of this issue.
+ #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+ #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+ #[inline]
+ #[cfg(not(bootstrap))]
+ pub const fn guaranteed_eq(self, other: *mut T) -> bool
+ where
+ T: Sized,
+ {
+ intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _)
+ }
+
+ /// Returns whether two pointers are guaranteed to be inequal.
+ ///
+ /// At runtime this function behaves like `self != other`.
+ /// However, in some contexts (e.g., compile-time evaluation),
+ /// it is not always possible to determine the inequality of two pointers, so this function may
+ /// spuriously return `false` for pointers that later actually turn out to be inequal.
+ /// But when it returns `true`, the pointers are guaranteed to be inequal.
+ ///
+ /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
+ /// comparisons for which both functions return `false`.
+ ///
+ /// [`guaranteed_eq`]: #method.guaranteed_eq
+ ///
+ /// The return value may change depending on the compiler version and unsafe code may not
+ /// rely on the result of this function for soundness. It is suggested to only use this function
+ /// for performance optimizations where spurious `false` return values by this function do not
+ /// affect the outcome, but just the performance.
+ /// The consequences of using this method to make runtime and compile-time code behave
+ /// differently have not been explored. This method should not be used to introduce such
+ /// differences, and it should also not be stabilized before we have a better understanding
+ /// of this issue.
+ #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+ #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+ #[inline]
+ #[cfg(not(bootstrap))]
+ pub const unsafe fn guaranteed_ne(self, other: *mut T) -> bool
+ where
+ T: Sized,
+ {
+ intrinsics::ptr_guaranteed_ne(self as *const _, other as *const _)
+ }
+
/// Calculates the distance between two pointers. The returned value is in
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
///
/// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2);
/// ```
#[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")]
+ #[rustc_deprecated(
+ since = "1.46.0",
+ reason = "Pointer distances across allocation \
+ boundaries are not typically meaningful. \
+ Use integer subtraction if you really need this."
+ )]
#[inline]
pub fn wrapping_offset_from(self, origin: *const T) -> isize
where
T: Sized,
{
+ #[allow(deprecated_in_future, deprecated)]
(self as *const T).wrapping_offset_from(origin)
}
}
}
-#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
+#[unstable(feature = "inner_deref", issue = "50264")]
impl<T: Deref, E> Result<T, E> {
- /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T::Target, &E>`.
+ /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&<T as Deref>::Target, &E>`.
///
- /// Leaves the original `Result` in-place, creating a new one containing a reference to the
- /// `Ok` type's `Deref::Target` type.
+ /// Coerces the [`Ok`] variant of the original [`Result`] via [`Deref`](crate::ops::Deref)
+ /// and returns the new [`Result`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(inner_deref)]
+ /// let x: Result<String, u32> = Ok("hello".to_string());
+ /// let y: Result<&str, &u32> = Ok("hello");
+ /// assert_eq!(x.as_deref(), y);
+ ///
+ /// let x: Result<String, u32> = Err(42);
+ /// let y: Result<&str, &u32> = Err(&42);
+ /// assert_eq!(x.as_deref(), y);
+ /// ```
pub fn as_deref(&self) -> Result<&T::Target, &E> {
self.as_ref().map(|t| t.deref())
}
}
-#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
+#[unstable(feature = "inner_deref", issue = "50264")]
impl<T, E: Deref> Result<T, E> {
- /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T, &E::Target>`.
+ /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T, &<E as Deref>::Target>`.
///
- /// Leaves the original `Result` in-place, creating a new one containing a reference to the
- /// `Err` type's `Deref::Target` type.
+ /// Coerces the [`Err`] variant of the original [`Result`] via [`Deref`](crate::ops::Deref)
+ /// and returns the new [`Result`].
pub fn as_deref_err(&self) -> Result<&T, &E::Target> {
self.as_ref().map_err(|e| e.deref())
}
}
-#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
+#[unstable(feature = "inner_deref", issue = "50264")]
impl<T: DerefMut, E> Result<T, E> {
- /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T::Target, &mut E>`.
+ /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut <T as DerefMut>::Target, &mut E>`.
///
- /// Leaves the original `Result` in-place, creating a new one containing a mutable reference to
- /// the `Ok` type's `Deref::Target` type.
+ /// Coerces the [`Ok`] variant of the original [`Result`] via [`DerefMut`](crate::ops::DerefMut)
+ /// and returns the new [`Result`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(inner_deref)]
+ /// let mut s = "HELLO".to_string();
+ /// let mut x: Result<String, u32> = Ok("hello".to_string());
+ /// let y: Result<&mut str, &mut u32> = Ok(&mut s);
+ /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
+ ///
+ /// let mut i = 42;
+ /// let mut x: Result<String, u32> = Err(42);
+ /// let y: Result<&mut str, &mut u32> = Err(&mut i);
+ /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
+ /// ```
pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> {
self.as_mut().map(|t| t.deref_mut())
}
}
-#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
+#[unstable(feature = "inner_deref", issue = "50264")]
impl<T, E: DerefMut> Result<T, E> {
- /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T, &mut E::Target>`.
+ /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T, &mut <E as DerefMut>::Target>`.
///
- /// Leaves the original `Result` in-place, creating a new one containing a mutable reference to
- /// the `Err` type's `Deref::Target` type.
+ /// Coerces the [`Err`] variant of the original [`Result`] via [`DerefMut`](crate::ops::DerefMut)
+ /// and returns the new [`Result`].
pub fn as_deref_mut_err(&mut self) -> Result<&mut T, &mut E::Target> {
self.as_mut().map_err(|e| e.deref_mut())
}
{
self.iter().is_sorted_by_key(f)
}
+
+ /// Returns the index of the partition point according to the given predicate
+ /// (the index of the first element of the second partition).
+ ///
+ /// The slice is assumed to be partitioned according to the given predicate.
+ /// This means that all elements for which the predicate returns true are at the start of the slice
+ /// and all elements for which the predicate returns false are at the end.
+ /// For example, [7, 15, 3, 5, 4, 12, 6] is a partitioned under the predicate x % 2 != 0
+ /// (all odd numbers are at the start, all even at the end).
+ ///
+ /// If this slice is not partitioned, the returned result is unspecified and meaningless,
+ /// as this method performs a kind of binary search.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(partition_point)]
+ ///
+ /// let v = [1, 2, 3, 3, 5, 6, 7];
+ /// let i = v.partition_point(|&x| x < 5);
+ ///
+ /// assert_eq!(i, 4);
+ /// assert!(v[..i].iter().all(|&x| x < 5));
+ /// assert!(v[i..].iter().all(|&x| !(x < 5)));
+ /// ```
+ #[unstable(feature = "partition_point", reason = "new API", issue = "73831")]
+ pub fn partition_point<P>(&self, mut pred: P) -> usize
+ where
+ P: FnMut(&T) -> bool,
+ {
+ let mut left = 0;
+ let mut right = self.len();
+
+ while left != right {
+ let mid = left + (right - left) / 2;
+ // SAFETY:
+ // When left < right, left <= mid < right.
+ // Therefore left always increases and right always decreases,
+ // and eigher of them is selected.
+ // In both cases left <= right is satisfied.
+ // Therefore if left < right in a step,
+ // left <= right is satisfied in the next step.
+ // Therefore as long as left != right, 0 <= left < right <= len is satisfied
+ // and if this case 0 <= mid < len is satisfied too.
+ let value = unsafe { self.get_unchecked(mid) };
+ if pred(value) {
+ left = mid + 1;
+ } else {
+ right = mid;
+ }
+ }
+
+ left
+ }
}
#[lang = "slice_u8"]
/// performing any bounds checking.
/// Calling this method with an out-of-bounds index is *[undefined behavior]*
/// even if the resulting reference is not used.
+ ///
/// [undefined behavior]: ../../reference/behavior-considered-undefined.html
#[unstable(feature = "slice_index_methods", issue = "none")]
unsafe fn get_unchecked(self, slice: &T) -> &Self::Output;
/// performing any bounds checking.
/// Calling this method with an out-of-bounds index is *[undefined behavior]*
/// even if the resulting reference is not used.
+ ///
/// [undefined behavior]: ../../reference/behavior-considered-undefined.html
#[unstable(feature = "slice_index_methods", issue = "none")]
unsafe fn get_unchecked_mut(self, slice: &mut T) -> &mut Self::Output;
return false;
}
+ #[cfg(bootstrap)]
if self.as_ptr() == other.as_ptr() {
return true;
}
+ // While performance would suffer if `guaranteed_eq` just returned `false`
+ // for all arguments, correctness and return value of this function are not affected.
+ #[cfg(not(bootstrap))]
+ if self.as_ptr().guaranteed_eq(other.as_ptr()) {
+ return true;
+ }
+
self.iter().zip(other.iter()).all(|(x, y)| x == y)
}
}
if self.len() != other.len() {
return false;
}
+
+ #[cfg(bootstrap)]
if self.as_ptr() == other.as_ptr() {
return true;
}
+
+ // While performance would suffer if `guaranteed_eq` just returned `false`
+ // for all arguments, correctness and return value of this function are not affected.
+ #[cfg(not(bootstrap))]
+ if self.as_ptr().guaranteed_eq(other.as_ptr()) {
+ return true;
+ }
unsafe {
let size = mem::size_of_val(self);
memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
//! Slice sorting
//!
-//! This module contains an sort algorithm based on Orson Peters' pattern-defeating quicksort,
+//! This module contains a sorting algorithm based on Orson Peters' pattern-defeating quicksort,
//! published at: https://github.com/orlp/pdqsort
//!
//! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our
impl<T> Drop for CopyOnDrop<T> {
fn drop(&mut self) {
+ // SAFETY: This is a helper class.
+ // Please refer to its usage for correctness.
+ // Namely, one must be sure that `src` and `dst` does not overlap as required by `ptr::copy_nonoverlapping`.
unsafe {
ptr::copy_nonoverlapping(self.src, self.dest, 1);
}
F: FnMut(&T, &T) -> bool,
{
let len = v.len();
+ // SAFETY: The unsafe operations below involves indexing without a bound check (`get_unchecked` and `get_unchecked_mut`)
+ // and copying memory (`ptr::copy_nonoverlapping`).
+ //
+ // a. Indexing:
+ // 1. We checked the size of the array to >=2.
+ // 2. All the indexing that we will do is always between {0 <= index < len} at most.
+ //
+ // b. Memory copying
+ // 1. We are obtaining pointers to references which are guaranteed to be valid.
+ // 2. They cannot overlap because we obtain pointers to difference indices of the slice.
+ // Namely, `i` and `i-1`.
+ // 3. If the slice is properly aligned, the elements are properly aligned.
+ // It is the caller's responsibility to make sure the slice is properly aligned.
+ //
+ // See comments below for further detail.
unsafe {
// If the first two elements are out-of-order...
if len >= 2 && is_less(v.get_unchecked(1), v.get_unchecked(0)) {
F: FnMut(&T, &T) -> bool,
{
let len = v.len();
+ // SAFETY: The unsafe operations below involves indexing without a bound check (`get_unchecked` and `get_unchecked_mut`)
+ // and copying memory (`ptr::copy_nonoverlapping`).
+ //
+ // a. Indexing:
+ // 1. We checked the size of the array to >= 2.
+ // 2. All the indexing that we will do is always between `0 <= index < len-1` at most.
+ //
+ // b. Memory copying
+ // 1. We are obtaining pointers to references which are guaranteed to be valid.
+ // 2. They cannot overlap because we obtain pointers to difference indices of the slice.
+ // Namely, `i` and `i+1`.
+ // 3. If the slice is properly aligned, the elements are properly aligned.
+ // It is the caller's responsibility to make sure the slice is properly aligned.
+ //
+ // See comments below for further detail.
unsafe {
// If the last two elements are out-of-order...
if len >= 2 && is_less(v.get_unchecked(len - 1), v.get_unchecked(len - 2)) {
let mut i = 1;
for _ in 0..MAX_STEPS {
+ // SAFETY: We already explicitly did the bound checking with `i < len`.
+ // All our subsequent indexing is only in the range `0 <= index < len`
unsafe {
// Find the next pair of adjacent out-of-order elements.
while i < len && !is_less(v.get_unchecked(i), v.get_unchecked(i - 1)) {
let mut offsets_l = [MaybeUninit::<u8>::uninit(); BLOCK];
// The current block on the right side (from `r.sub(block_r)` to `r`).
+ // SAFETY: The documentation for .add() specifically mention that `vec.as_ptr().add(vec.len())` is always safe`
let mut r = unsafe { l.add(v.len()) };
let mut block_r = BLOCK;
let mut start_r = ptr::null_mut();
let mut elem = l;
for i in 0..block_l {
+ // SAFETY: The unsafety operations below involve the usage of the `offset`.
+ // According to the conditions required by the function, we satisfy them because:
+ // 1. `offsets_l` is stack-allocated, and thus considered separate allocated object.
+ // 2. The function `is_less` returns a `bool`.
+ // Casting a `bool` will never overflow `isize`.
+ // 3. We have guaranteed that `block_l` will be `<= BLOCK`.
+ // Plus, `end_l` was initially set to the begin pointer of `offsets_` which was declared on the stack.
+ // Thus, we know that even in the worst case (all invocations of `is_less` returns false) we will only be at most 1 byte pass the end.
+ // Another unsafety operation here is dereferencing `elem`.
+ // However, `elem` was initially the begin pointer to the slice which is always valid.
unsafe {
// Branchless comparison.
*end_l = i as u8;
let mut elem = r;
for i in 0..block_r {
+ // SAFETY: The unsafety operations below involve the usage of the `offset`.
+ // According to the conditions required by the function, we satisfy them because:
+ // 1. `offsets_r` is stack-allocated, and thus considered separate allocated object.
+ // 2. The function `is_less` returns a `bool`.
+ // Casting a `bool` will never overflow `isize`.
+ // 3. We have guaranteed that `block_r` will be `<= BLOCK`.
+ // Plus, `end_r` was initially set to the begin pointer of `offsets_` which was declared on the stack.
+ // Thus, we know that even in the worst case (all invocations of `is_less` returns true) we will only be at most 1 byte pass the end.
+ // Another unsafety operation here is dereferencing `elem`.
+ // However, `elem` was initially `1 * sizeof(T)` past the end and we decrement it by `1 * sizeof(T)` before accessing it.
+ // Plus, `block_r` was asserted to be less than `BLOCK` and `elem` will therefore at most be pointing to the beginning of the slice.
unsafe {
// Branchless comparison.
elem = elem.offset(-1);
// Find the first pair of out-of-order elements.
let mut l = 0;
let mut r = v.len();
+
+ // SAFETY: The unsafety below involves indexing an array.
+ // For the first one: We already do the bounds checking here with `l < r`.
+ // For the second one: We initially have `l == 0` and `r == v.len()` and we checked that `l < r` at every indexing operation.
+ // From here we know that `r` must be at least `r == l` which was shown to be valid from the first one.
unsafe {
- // Find the first element greater then or equal to the pivot.
+ // Find the first element greater than or equal to the pivot.
while l < r && is_less(v.get_unchecked(l), pivot) {
l += 1;
}
// Read the pivot into a stack-allocated variable for efficiency. If a following comparison
// operation panics, the pivot will be automatically written back into the slice.
+ // SAFETY: The pointer here is valid because it is obtained from a reference to a slice.
let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
let _pivot_guard = CopyOnDrop { src: &mut *tmp, dest: pivot };
let pivot = &*tmp;
let mut l = 0;
let mut r = v.len();
loop {
+ // SAFETY: The unsafety below involves indexing an array.
+ // For the first one: We already do the bounds checking here with `l < r`.
+ // For the second one: We initially have `l == 0` and `r == v.len()` and we checked that `l < r` at every indexing operation.
+ // From here we know that `r` must be at least `r == l` which was shown to be valid from the first one.
unsafe {
- // Find the first element greater that the pivot.
+ // Find the first element greater than the pivot.
while l < r && !is_less(pivot, v.get_unchecked(l)) {
l += 1;
}
}
assert_eq!(i.get(), 5);
}
+
+// This test does not work on targets without panic=unwind support.
+// To work around this problem, test is marked is should_panic, so it will
+// be automagically skipped on unsuitable targets, such as
+// wasm32-unknown-unkown.
+//
+// It means that we use panic for indicating success.
+#[test]
+#[should_panic(expected = "test succeeded")]
+fn array_default_impl_avoids_leaks_on_panic() {
+ use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
+ static COUNTER: AtomicUsize = AtomicUsize::new(0);
+ #[derive(Debug)]
+ struct Bomb(usize);
+
+ impl Default for Bomb {
+ fn default() -> Bomb {
+ if COUNTER.load(Relaxed) == 3 {
+ panic!("bomb limit exceeded");
+ }
+
+ COUNTER.fetch_add(1, Relaxed);
+ Bomb(COUNTER.load(Relaxed))
+ }
+ }
+
+ impl Drop for Bomb {
+ fn drop(&mut self) {
+ COUNTER.fetch_sub(1, Relaxed);
+ }
+ }
+
+ let res = std::panic::catch_unwind(|| <[Bomb; 5]>::default());
+ let panic_msg = match res {
+ Ok(_) => unreachable!(),
+ Err(p) => p.downcast::<&'static str>().unwrap(),
+ };
+ assert_eq!(*panic_msg, "bomb limit exceeded");
+ // check that all bombs are successfully dropped
+ assert_eq!(COUNTER.load(Relaxed), 0);
+ panic!("test succeeded")
+}
+
+#[test]
+fn empty_array_is_always_default() {
+ struct DoesNotImplDefault;
+
+ let _arr = <[DoesNotImplDefault; 0]>::default();
+}
#![feature(raw)]
#![feature(sort_internals)]
#![feature(slice_partition_at_index)]
-#![feature(specialization)]
+#![feature(min_specialization)]
#![feature(step_trait)]
#![feature(step_trait_ext)]
#![feature(str_internals)]
#![feature(const_raw_ptr_deref)]
#![feature(never_type)]
#![feature(unwrap_infallible)]
-#![feature(leading_trailing_ones)]
#![feature(const_forget)]
#![feature(option_unwrap_none)]
#![feature(peekable_next_if)]
+#![feature(partition_point)]
extern crate test;
+use core::convert::TryFrom;
use core::num::{IntErrorKind, NonZeroI32, NonZeroI8, NonZeroU32, NonZeroU8};
use core::option::Option::{self, None, Some};
use std::mem::size_of;
target |= 0;
assert_eq!(target.get(), 0b1011_1111);
}
+
+#[test]
+fn test_nonzero_from_int_on_success() {
+ assert_eq!(NonZeroU8::try_from(5), Ok(NonZeroU8::new(5).unwrap()));
+ assert_eq!(NonZeroU32::try_from(5), Ok(NonZeroU32::new(5).unwrap()));
+
+ assert_eq!(NonZeroI8::try_from(-5), Ok(NonZeroI8::new(-5).unwrap()));
+ assert_eq!(NonZeroI32::try_from(-5), Ok(NonZeroI32::new(-5).unwrap()));
+}
+
+#[test]
+fn test_nonzero_from_int_on_err() {
+ assert!(NonZeroU8::try_from(0).is_err());
+ assert!(NonZeroU32::try_from(0).is_err());
+
+ assert!(NonZeroI8::try_from(0).is_err());
+ assert!(NonZeroI32::try_from(0).is_err());
+}
assert_eq!(b.binary_search(&3), Ok(8));
}
+#[test]
+fn test_partition_point() {
+ let b: [i32; 0] = [];
+ assert_eq!(b.partition_point(|&x| x < 5), 0);
+
+ let b = [4];
+ assert_eq!(b.partition_point(|&x| x < 3), 0);
+ assert_eq!(b.partition_point(|&x| x < 4), 0);
+ assert_eq!(b.partition_point(|&x| x < 5), 1);
+
+ let b = [1, 2, 4, 6, 8, 9];
+ assert_eq!(b.partition_point(|&x| x < 5), 3);
+ assert_eq!(b.partition_point(|&x| x < 6), 3);
+ assert_eq!(b.partition_point(|&x| x < 7), 4);
+ assert_eq!(b.partition_point(|&x| x < 8), 4);
+
+ let b = [1, 2, 4, 5, 6, 8];
+ assert_eq!(b.partition_point(|&x| x < 9), 6);
+
+ let b = [1, 2, 4, 6, 7, 8, 9];
+ assert_eq!(b.partition_point(|&x| x < 6), 3);
+ assert_eq!(b.partition_point(|&x| x < 5), 3);
+ assert_eq!(b.partition_point(|&x| x < 8), 5);
+
+ let b = [1, 2, 4, 5, 6, 8, 9];
+ assert_eq!(b.partition_point(|&x| x < 7), 5);
+ assert_eq!(b.partition_point(|&x| x < 0), 0);
+
+ let b = [1, 3, 3, 3, 7];
+ assert_eq!(b.partition_point(|&x| x < 0), 0);
+ assert_eq!(b.partition_point(|&x| x < 1), 0);
+ assert_eq!(b.partition_point(|&x| x < 2), 1);
+ assert_eq!(b.partition_point(|&x| x < 3), 1);
+ assert_eq!(b.partition_point(|&x| x < 4), 4);
+ assert_eq!(b.partition_point(|&x| x < 5), 4);
+ assert_eq!(b.partition_point(|&x| x < 6), 4);
+ assert_eq!(b.partition_point(|&x| x < 7), 4);
+ assert_eq!(b.partition_point(|&x| x < 8), 5);
+}
+
#[test]
fn test_iterator_nth() {
let v: &[_] = &[0, 1, 2, 3, 4];
/// the number of nanoseconds.
///
/// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other
-/// [`ops`] traits.
+/// [`ops`] traits. It implements `Default` by returning a zero-length `Duration`.
///
/// [`Add`]: ../../std/ops/trait.Add.html
/// [`Sub`]: ../../std/ops/trait.Sub.html
Duration { secs, nanos }
}
+ /// Creates a new `Duration` that spans no time.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(duration_zero)]
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::zero();
+ /// assert!(duration.is_zero());
+ /// assert_eq!(duration.as_nanos(), 0);
+ /// ```
+ #[unstable(feature = "duration_zero", issue = "73544")]
+ #[inline]
+ pub const fn zero() -> Duration {
+ Duration { secs: 0, nanos: 0 }
+ }
+
/// Creates a new `Duration` from the specified number of whole seconds.
///
/// # Examples
}
}
+ /// Returns true if this `Duration` spans no time.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(duration_zero)]
+ /// use std::time::Duration;
+ ///
+ /// assert!(Duration::zero().is_zero());
+ /// assert!(Duration::new(0, 0).is_zero());
+ /// assert!(Duration::from_nanos(0).is_zero());
+ /// assert!(Duration::from_secs(0).is_zero());
+ ///
+ /// assert!(!Duration::new(1, 1).is_zero());
+ /// assert!(!Duration::from_nanos(1).is_zero());
+ /// assert!(!Duration::from_secs(1).is_zero());
+ /// ```
+ #[unstable(feature = "duration_zero", issue = "73544")]
+ #[inline]
+ pub const fn is_zero(&self) -> bool {
+ self.secs == 0 && self.nanos == 0
+ }
+
/// Returns the number of _whole_ seconds contained by this `Duration`.
///
/// The returned value does not include the fractional (nanosecond) part of the
use core::any::Any;
#[rustc_std_internal_symbol]
+#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) {
unreachable!()
}
mod dwarf;
#[rustc_std_internal_symbol]
+#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) {
Box::into_raw(imp::cleanup(payload))
}
"InstrProfilingUtil.c",
"InstrProfilingValue.c",
"InstrProfilingWriter.c",
+ // This file was renamed in LLVM 10.
+ "InstrProfilingRuntime.cc",
+ "InstrProfilingRuntime.cpp",
+ // These files were added in LLVM 11.
+ "InstrProfilingInternal.c",
+ "InstrProfilingBiasVar.c",
];
if target.contains("msvc") {
let src_root = root.join("lib").join("profile");
for src in profile_sources {
- cfg.file(src_root.join(src));
+ let path = src_root.join(src);
+ if path.exists() {
+ cfg.file(path);
+ }
}
- // The file was renamed in LLVM 10.
- let old_runtime_path = src_root.join("InstrProfilingRuntime.cc");
- let new_runtime_path = src_root.join("InstrProfilingRuntime.cpp");
- cfg.file(if old_runtime_path.exists() { old_runtime_path } else { new_runtime_path });
-
cfg.include(root.join("include"));
cfg.warnings(false);
cfg.compile("profiler-rt");
use rustc_data_structures::cold_path;
use smallvec::SmallVec;
+use std::alloc::Layout;
use std::cell::{Cell, RefCell};
use std::cmp;
use std::intrinsics;
}
}
- /// Allocates a byte slice with specified size and alignment from the
- /// current memory chunk. Returns `None` if there is no free space left to
- /// satisfy the request.
+ /// Allocates a byte slice with specified layout from the current memory
+ /// chunk. Returns `None` if there is no free space left to satisfy the
+ /// request.
#[inline]
- fn alloc_raw_without_grow(&self, bytes: usize, align: usize) -> Option<*mut u8> {
+ fn alloc_raw_without_grow(&self, layout: Layout) -> Option<*mut u8> {
let ptr = self.ptr.get() as usize;
let end = self.end.get() as usize;
+ let align = layout.align();
+ let bytes = layout.size();
// The allocation request fits into the current chunk iff:
//
// let aligned = align_to(ptr, align);
}
#[inline]
- pub fn alloc_raw(&self, bytes: usize, align: usize) -> *mut u8 {
- assert!(bytes != 0);
+ pub fn alloc_raw(&self, layout: Layout) -> *mut u8 {
+ assert!(layout.size() != 0);
loop {
- if let Some(a) = self.alloc_raw_without_grow(bytes, align) {
+ if let Some(a) = self.alloc_raw_without_grow(layout) {
break a;
}
// No free space left. Allocate a new chunk to satisfy the request.
// On failure the grow will panic or abort.
- self.grow(bytes);
+ self.grow(layout.size());
}
}
pub fn alloc<T>(&self, object: T) -> &mut T {
assert!(!mem::needs_drop::<T>());
- let mem = self.alloc_raw(mem::size_of::<T>(), mem::align_of::<T>()) as *mut T;
+ let mem = self.alloc_raw(Layout::for_value::<T>(&object)) as *mut T;
unsafe {
// Write into uninitialized memory.
assert!(mem::size_of::<T>() != 0);
assert!(!slice.is_empty());
- let mem = self.alloc_raw(slice.len() * mem::size_of::<T>(), mem::align_of::<T>()) as *mut T;
+ let mem = self.alloc_raw(Layout::for_value::<[T]>(slice)) as *mut T;
unsafe {
mem.copy_from_nonoverlapping(slice.as_ptr(), slice.len());
if len == 0 {
return &mut [];
}
- let size = len.checked_mul(mem::size_of::<T>()).unwrap();
- let mem = self.alloc_raw(size, mem::align_of::<T>()) as *mut T;
+
+ let mem = self.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T;
unsafe { self.write_from_iter(iter, len, mem) }
}
(_, _) => {
// the content of the SmallVec
unsafe {
let len = vec.len();
- let start_ptr = self
- .alloc_raw(len * mem::size_of::<T>(), mem::align_of::<T>())
- as *mut T;
+ let start_ptr =
+ self.alloc_raw(Layout::for_value::<[T]>(vec.as_slice())) as *mut T;
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
vec.set_len(0);
slice::from_raw_parts_mut(start_ptr, len)
impl DropArena {
#[inline]
pub unsafe fn alloc<T>(&self, object: T) -> &mut T {
- let mem = self.arena.alloc_raw(mem::size_of::<T>(), mem::align_of::<T>()) as *mut T;
+ let mem = self.arena.alloc_raw(Layout::new::<T>()) as *mut T;
// Write into uninitialized memory.
ptr::write(mem, object);
let result = &mut *mem;
}
let len = vec.len();
- let start_ptr = self
- .arena
- .alloc_raw(len.checked_mul(mem::size_of::<T>()).unwrap(), mem::align_of::<T>())
- as *mut T;
+ let start_ptr = self.arena.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T;
let mut destructors = self.destructors.borrow_mut();
// Reserve space for the destructors so we can't panic while adding them
#[macro_export]
macro_rules! declare_arena {
- ([], [$($a:tt $name:ident: $ty:ty, $gen_ty:ty;)*], $tcx:lifetime) => {
+ // This macro has to take the same input as
+ // `impl_arena_allocatable_decoders` which requires a second version of
+ // each type. We ignore that type until we can fix
+ // `impl_arena_allocatable_decoders`.
+ ([], [$($a:tt $name:ident: $ty:ty, $_gen_ty:ty;)*], $tcx:lifetime) => {
#[derive(Default)]
pub struct Arena<$tcx> {
pub dropless: $crate::DroplessArena,
$($name: $crate::arena_for_type!($a[$ty]),)*
}
- #[marker]
- pub trait ArenaAllocatable<'tcx> {}
-
- impl<'tcx, T: Copy> ArenaAllocatable<'tcx> for T {}
-
- unsafe trait ArenaField<'tcx>: Sized + ArenaAllocatable<'tcx> {
- /// Returns a specific arena to allocate from.
- /// If `None` is returned, the `DropArena` will be used.
- fn arena<'a>(arena: &'a Arena<'tcx>) -> Option<&'a $crate::TypedArena<Self>>;
+ pub trait ArenaAllocatable<'tcx, T = Self>: Sized {
+ fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self;
+ fn allocate_from_iter<'a>(
+ arena: &'a Arena<'tcx>,
+ iter: impl ::std::iter::IntoIterator<Item = Self>,
+ ) -> &'a mut [Self];
}
- unsafe impl<'tcx, T: ArenaAllocatable<'tcx>> ArenaField<'tcx> for T {
+ impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T {
#[inline]
- default fn arena<'a>(_: &'a Arena<'tcx>) -> Option<&'a $crate::TypedArena<Self>> {
- panic!()
+ fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
+ arena.dropless.alloc(self)
+ }
+ #[inline]
+ fn allocate_from_iter<'a>(
+ arena: &'a Arena<'tcx>,
+ iter: impl ::std::iter::IntoIterator<Item = Self>,
+ ) -> &'a mut [Self] {
+ arena.dropless.alloc_from_iter(iter)
}
- }
+ }
$(
- #[allow(unused_lifetimes)]
- impl<$tcx> ArenaAllocatable<$tcx> for $ty {}
- unsafe impl<$tcx, '_x, '_y, '_z, '_w> ArenaField<$tcx> for $gen_ty where Self: ArenaAllocatable<$tcx> {
+ impl<$tcx> ArenaAllocatable<$tcx, $ty> for $ty {
#[inline]
- fn arena<'a>(_arena: &'a Arena<$tcx>) -> Option<&'a $crate::TypedArena<Self>> {
- // SAFETY: We only implement `ArenaAllocatable<$tcx>` for
- // `$ty`, so `$ty` and Self are the same type
- unsafe {
- ::std::mem::transmute::<
- Option<&'a $crate::TypedArena<$ty>>,
- Option<&'a $crate::TypedArena<Self>>,
- >(
- $crate::which_arena_for_type!($a[&_arena.$name])
- )
+ fn allocate_on<'a>(self, arena: &'a Arena<$tcx>) -> &'a mut Self {
+ if !::std::mem::needs_drop::<Self>() {
+ return arena.dropless.alloc(self);
+ }
+ match $crate::which_arena_for_type!($a[&arena.$name]) {
+ ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
+ ty_arena.alloc(self)
+ }
+ ::std::option::Option::None => unsafe { arena.drop.alloc(self) },
+ }
+ }
+
+ #[inline]
+ fn allocate_from_iter<'a>(
+ arena: &'a Arena<$tcx>,
+ iter: impl ::std::iter::IntoIterator<Item = Self>,
+ ) -> &'a mut [Self] {
+ if !::std::mem::needs_drop::<Self>() {
+ return arena.dropless.alloc_from_iter(iter);
+ }
+ match $crate::which_arena_for_type!($a[&arena.$name]) {
+ ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
+ ty_arena.alloc_from_iter(iter)
+ }
+ ::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) },
}
}
}
impl<'tcx> Arena<'tcx> {
#[inline]
- pub fn alloc<T: ArenaAllocatable<'tcx>>(&self, value: T) -> &mut T {
- if !::std::mem::needs_drop::<T>() {
- return self.dropless.alloc(value);
- }
- match <T as ArenaField<'tcx>>::arena(self) {
- ::std::option::Option::Some(arena) => arena.alloc(value),
- ::std::option::Option::None => unsafe { self.drop.alloc(value) },
- }
+ pub fn alloc<T: ArenaAllocatable<'tcx, U>, U>(&self, value: T) -> &mut T {
+ value.allocate_on(self)
}
#[inline]
self.dropless.alloc_slice(value)
}
- pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx>>(
+ pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, U>, U>(
&'a self,
iter: impl ::std::iter::IntoIterator<Item = T>,
) -> &'a mut [T] {
- if !::std::mem::needs_drop::<T>() {
- return self.dropless.alloc_from_iter(iter);
- }
- match <T as ArenaField<'tcx>>::arena(self) {
- ::std::option::Option::Some(arena) => arena.alloc_from_iter(iter),
- ::std::option::Option::None => unsafe { self.drop.alloc_from_iter(iter) },
- }
+ T::allocate_from_iter(self, iter)
}
}
}
//! additional metadata), and [`ItemKind`] (which represents a concrete type and contains
//! information specific to the type of the item).
//!
-//! Other module items that worth mentioning:
+//! Other module items worth mentioning:
//! - [`Ty`] and [`TyKind`]: A parsed Rust type.
//! - [`Expr`] and [`ExprKind`]: A parsed Rust expression.
//! - [`Pat`] and [`PatKind`]: A parsed Rust pattern. Patterns are often dual to expressions.
},
Const {
ty: P<Ty>,
+ /// Span of the `const` keyword.
+ kw_span: Span,
},
}
match c {
'{' => f.write_str("{{")?,
'}' => f.write_str("}}")?,
- _ => write!(f, "{}", c.escape_debug())?,
+ _ => c.fmt(f)?,
}
}
Ok(())
let span = span.with_hi(segments.last().unwrap().ident.span.hi());
Path { span, segments }
}
- Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt {
+ Some(TokenTree::Token(Token { kind: token::Interpolated(nt, _), .. })) => match *nt {
token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span),
token::Nonterminal::NtPath(ref path) => path.clone(),
_ => return None,
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
#![feature(bool_to_option)]
#![feature(box_syntax)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_fn)] // For the `transmute` in `P::new`
#![feature(const_panic)]
#![feature(const_transmute)]
*span = ident.span;
return; // Avoid visiting the span for the second time.
}
- token::Interpolated(nt) => {
+ token::Interpolated(nt, _) => {
let mut nt = Lrc::make_mut(nt);
vis.visit_interpolated(&mut nt);
}
GenericParamKind::Type { default } => {
visit_opt(default, |default| vis.visit_ty(default));
}
- GenericParamKind::Const { ty } => {
+ GenericParamKind::Const { ty, kw_span: _ } => {
vis.visit_ty(ty);
}
}
.contains(&name)
}
+/// A hack used to pass AST fragments to attribute and derive macros
+/// as a single nonterminal token instead of a token stream.
+/// FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+pub enum FlattenGroup {
+ Yes,
+ No,
+}
+
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
pub enum TokenKind {
/* Expression-operator symbols. */
/// treat regular and interpolated lifetime identifiers in the same way.
Lifetime(Symbol),
- Interpolated(Lrc<Nonterminal>),
+ Interpolated(Lrc<Nonterminal>, FlattenGroup),
// Can be expanded into several tokens.
/// A doc comment.
/// if they keep spans or perform edition checks.
pub fn uninterpolated_span(&self) -> Span {
match &self.kind {
- Interpolated(nt) => nt.span(),
+ Interpolated(nt, _) => nt.span(),
_ => self.span,
}
}
ModSep | // global path
Lifetime(..) | // labeled loop
Pound => true, // expression attributes
- Interpolated(ref nt) => match **nt {
+ Interpolated(ref nt, _) => match **nt {
NtLiteral(..) |
NtExpr(..) |
NtBlock(..) |
Lifetime(..) | // lifetime bound in trait object
Lt | BinOp(Shl) | // associated path
ModSep => true, // global path
- Interpolated(ref nt) => match **nt {
+ Interpolated(ref nt, _) => match **nt {
NtTy(..) | NtPath(..) => true,
_ => false,
},
pub fn can_begin_const_arg(&self) -> bool {
match self.kind {
OpenDelim(Brace) => true,
- Interpolated(ref nt) => match **nt {
+ Interpolated(ref nt, _) => match **nt {
NtExpr(..) | NtBlock(..) | NtLiteral(..) => true,
_ => false,
},
match self.uninterpolate().kind {
Literal(..) | BinOp(Minus) => true,
Ident(name, false) if name.is_bool_lit() => true,
- Interpolated(ref nt) => match &**nt {
+ Interpolated(ref nt, _) => match &**nt {
NtLiteral(_) => true,
NtExpr(e) => match &e.kind {
ast::ExprKind::Lit(_) => true,
// otherwise returns the original token.
pub fn uninterpolate(&self) -> Cow<'_, Token> {
match &self.kind {
- Interpolated(nt) => match **nt {
+ Interpolated(nt, _) => match **nt {
NtIdent(ident, is_raw) => {
Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
}
/// Returns `true` if the token is an interpolated path.
fn is_path(&self) -> bool {
- if let Interpolated(ref nt) = self.kind {
+ if let Interpolated(ref nt, _) = self.kind {
if let NtPath(..) = **nt {
return true;
}
/// That is, is this a pre-parsed expression dropped into the token stream
/// (which happens while parsing the result of macro expansion)?
pub fn is_whole_expr(&self) -> bool {
- if let Interpolated(ref nt) = self.kind {
+ if let Interpolated(ref nt, _) = self.kind {
if let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt {
return true;
}
// Is the token an interpolated block (`$b:block`)?
pub fn is_whole_block(&self) -> bool {
- if let Interpolated(ref nt) = self.kind {
+ if let Interpolated(ref nt, _) = self.kind {
if let NtBlock(..) = **nt {
return true;
}
b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate)
}
- (&Interpolated(_), &Interpolated(_)) => false,
+ (&Interpolated(..), &Interpolated(..)) => false,
_ => panic!("forgot to add a token?"),
}
token::Lit::new(token::Bool, name, None)
}
token::Literal(lit) => lit,
- token::Interpolated(ref nt) => {
+ token::Interpolated(ref nt, _) => {
if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt {
if let ast::ExprKind::Lit(lit) = &expr.kind {
return Ok(lit.clone());
/// Associative operator with precedence.
///
/// This is the enum which specifies operator precedence and fixity to the parser.
-#[derive(PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum AssocOp {
/// `+`
Add,
}
pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
- let mut span = e.span;
ensure_sufficient_stack(|| {
let kind = match e.kind {
ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)),
hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args, span)
}
ExprKind::Binary(binop, ref lhs, ref rhs) => {
- span = self.mark_span_with_reason(DesugaringKind::Operator, e.span, None);
let binop = self.lower_binop(binop);
let lhs = self.lower_expr(lhs);
let rhs = self.lower_expr(rhs);
hir::Expr {
hir_id: self.lower_node_id(e.id),
kind,
- span,
+ span: e.span,
attrs: e.attrs.iter().map(|a| self.lower_attr(a)).collect::<Vec<_>>().into(),
}
})
}
fn lower_binop(&mut self, b: BinOp) -> hir::BinOp {
- let span = self.mark_span_with_reason(DesugaringKind::Operator, b.span, None);
Spanned {
node: match b.node {
BinOpKind::Add => hir::BinOpKind::Add,
BinOpKind::Ge => hir::BinOpKind::Ge,
BinOpKind::Gt => hir::BinOpKind::Gt,
},
- span,
+ span: b.span,
}
}
asm::InlineAsmReg::parse(
sess.asm_arch?,
|feature| sess.target_features.contains(&Symbol::intern(feature)),
+ &sess.target.target,
s,
)
.map_err(|e| {
hir::ItemKind::Const(ty, body_id)
}
ItemKind::Fn(_, FnSig { ref decl, header }, ref generics, ref body) => {
- let fn_def_id = self.resolver.definitions().local_def_id(id);
+ let fn_def_id = self.resolver.local_def_id(id);
self.with_new_scopes(|this| {
this.current_item = Some(ident.span);
self_ty: ref ty,
items: ref impl_items,
} => {
- let def_id = self.resolver.definitions().local_def_id(id);
+ let def_id = self.resolver.local_def_id(id);
// Lower the "impl header" first. This ordering is important
// for in-band lifetimes! Consider `'a` here:
}
fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem<'hir> {
- let def_id = self.resolver.definitions().local_def_id(i.id);
+ let def_id = self.resolver.local_def_id(i.id);
hir::ForeignItem {
hir_id: self.lower_node_id(i.id),
ident: i.ident,
}
fn lower_trait_item(&mut self, i: &AssocItem) -> hir::TraitItem<'hir> {
- let trait_item_def_id = self.resolver.definitions().local_def_id(i.id);
+ let trait_item_def_id = self.resolver.local_def_id(i.id);
let (generics, kind) = match i.kind {
AssocItemKind::Const(_, ref ty, ref default) => {
}
fn lower_impl_item(&mut self, i: &AssocItem) -> hir::ImplItem<'hir> {
- let impl_item_def_id = self.resolver.definitions().local_def_id(i.id);
+ let impl_item_def_id = self.resolver.local_def_id(i.id);
let (generics, kind) = match &i.kind {
AssocItemKind::Const(_, ty, expr) => {
if let Some(def_id) = def_id.as_local() {
for param in &generics.params {
if let GenericParamKind::Type { .. } = param.kind {
- if def_id
- == self
- .resolver
- .definitions()
- .local_def_id(param.id)
- {
+ if def_id == self.resolver.local_def_id(param.id) {
add_bounds
.entry(param.id)
.or_default()
#![feature(array_value_iter)]
#![feature(crate_visibility_modifier)]
-#![feature(marker_trait_attr)]
-#![feature(min_specialization)]
#![feature(or_patterns)]
#![recursion_limit = "256"]
use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
use rustc_hir::intravisit;
use rustc_hir::{ConstArg, GenericArg, ParamName};
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::{Idx, IndexVec};
use rustc_session::config::nightly_options;
use rustc_session::lint::{builtin::BARE_TRAIT_OBJECTS, BuiltinLintDiagnostics, LintBuffer};
use rustc_session::parse::ParseSess;
/// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes.
sess: &'a Session,
- resolver: &'a mut dyn Resolver,
+ resolver: &'a mut dyn ResolverAstLowering,
/// HACK(Centril): there is a cyclic dependency between the parser and lowering
/// if we don't have this function pointer. To avoid that dependency so that
allow_gen_future: Option<Lrc<[Symbol]>>,
}
-pub trait Resolver {
+pub trait ResolverAstLowering {
fn def_key(&mut self, id: DefId) -> DefKey;
fn item_generics_num_lifetimes(&self, def: DefId, sess: &Session) -> usize;
fn lint_buffer(&mut self) -> &mut LintBuffer;
fn next_node_id(&mut self) -> NodeId;
+
+ fn trait_map(&self) -> &NodeMap<Vec<hir::TraitCandidate>>;
+
+ fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>;
+
+ fn local_def_id(&self, node: NodeId) -> LocalDefId;
+
+ fn create_def(
+ &mut self,
+ parent: LocalDefId,
+ node_id: ast::NodeId,
+ data: DefPathData,
+ expn_id: ExpnId,
+ span: Span,
+ ) -> LocalDefId;
}
type NtToTokenstream = fn(&Nonterminal, &ParseSess, Span) -> TokenStream;
pub fn lower_crate<'a, 'hir>(
sess: &'a Session,
krate: &'a Crate,
- resolver: &'a mut dyn Resolver,
+ resolver: &'a mut dyn ResolverAstLowering,
nt_to_tokenstream: NtToTokenstream,
arena: &'hir Arena<'hir>,
) -> hir::Crate<'hir> {
match tree.kind {
UseTreeKind::Simple(_, id1, id2) => {
for &id in &[id1, id2] {
- self.lctx.resolver.definitions().create_def_with_parent(
+ self.lctx.resolver.create_def(
owner,
id,
DefPathData::Misc,
| ItemKind::Enum(_, ref generics)
| ItemKind::TyAlias(_, ref generics, ..)
| ItemKind::Trait(_, _, ref generics, ..) => {
- let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
+ let def_id = self.lctx.resolver.local_def_id(item.id);
let count = generics
.params
.iter()
let proc_macros =
c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id].unwrap()).collect();
- self.resolver.definitions().init_node_id_to_hir_id_mapping(self.node_id_to_hir_id);
+ let trait_map = self
+ .resolver
+ .trait_map()
+ .iter()
+ .map(|(&k, v)| (self.node_id_to_hir_id[k].unwrap(), v.clone()))
+ .collect();
+
+ let mut def_id_to_hir_id = IndexVec::default();
+
+ for (node_id, hir_id) in self.node_id_to_hir_id.into_iter_enumerated() {
+ if let Some(def_id) = self.resolver.opt_local_def_id(node_id) {
+ if def_id_to_hir_id.len() <= def_id.index() {
+ def_id_to_hir_id.resize(def_id.index() + 1, None);
+ }
+ def_id_to_hir_id[def_id] = hir_id;
+ }
+ }
+
+ self.resolver.definitions().init_def_id_to_hir_id_mapping(def_id_to_hir_id);
hir::Crate {
item: hir::CrateItem { module, attrs, span: c.span },
trait_impls: self.trait_impls,
modules: self.modules,
proc_macros,
+ trait_map,
}
}
.item_local_id_counters
.insert(owner, HIR_ID_COUNTER_LOCKED)
.unwrap_or_else(|| panic!("no `item_local_id_counters` entry for {:?}", owner));
- let def_id = self.resolver.definitions().local_def_id(owner);
+ let def_id = self.resolver.local_def_id(owner);
self.current_hir_id_owner.push((def_id, counter));
let ret = f(self);
let (new_def_id, new_counter) = self.current_hir_id_owner.pop().unwrap();
debug_assert!(local_id != HIR_ID_COUNTER_LOCKED);
*local_id_counter += 1;
- let owner = this.resolver.definitions().opt_local_def_id(owner).expect(
- "you forgot to call `create_def_with_parent` or are lowering node-IDs \
+ let owner = this.resolver.opt_local_def_id(owner).expect(
+ "you forgot to call `create_def` or are lowering node-IDs \
that do not belong to the current owner",
);
};
// Add a definition for the in-band lifetime def.
- self.resolver.definitions().create_def_with_parent(
+ self.resolver.create_def(
parent_def_id,
node_id,
DefPathData::LifetimeNs(str_name),
fn lower_token(&mut self, token: Token) -> TokenStream {
match token.kind {
- token::Interpolated(nt) => {
+ token::Interpolated(nt, _) => {
let tts = (self.nt_to_tokenstream)(&nt, &self.sess.parse_sess, token.span);
self.lower_token_stream(tts)
}
let impl_trait_node_id = self.resolver.next_node_id();
let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
- self.resolver.definitions().create_def_with_parent(
+ self.resolver.create_def(
parent_def_id,
impl_trait_node_id,
DefPathData::ImplTrait,
let node_id = self.resolver.next_node_id();
// Add a definition for the in-band const def.
- self.resolver.definitions().create_def_with_parent(
+ self.resolver.create_def(
parent_def_id,
node_id,
DefPathData::AnonConst,
}
ImplTraitContext::Universal(in_band_ty_params) => {
// Add a definition for the in-band `Param`.
- let def_id = self.resolver.definitions().local_def_id(def_node_id);
+ let def_id = self.resolver.local_def_id(def_node_id);
let hir_bounds = self.lower_param_bounds(
bounds,
// frequently opened issues show.
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
- let opaque_ty_def_id = self.resolver.definitions().local_def_id(opaque_ty_node_id);
+ let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id);
self.allocate_hir_id_counter(opaque_ty_node_id);
let def_node_id = self.context.resolver.next_node_id();
let hir_id =
self.context.lower_node_id_with_owner(def_node_id, self.opaque_ty_id);
- self.context.resolver.definitions().create_def_with_parent(
+ self.context.resolver.create_def(
self.parent,
def_node_id,
DefPathData::LifetimeNs(name.ident().name),
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
- let opaque_ty_def_id = self.resolver.definitions().local_def_id(opaque_ty_node_id);
+ let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id);
self.allocate_hir_id_counter(opaque_ty_node_id);
(hir::ParamName::Plain(param.ident), kind)
}
- GenericParamKind::Const { ref ty } => {
+ GenericParamKind::Const { ref ty, kw_span: _ } => {
let ty = self
.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
this.lower_ty(&ty, ImplTraitContext::disallowed())
generics.params.iter().map(|param| {
let ident = Some(param.ident.to_string());
let (kind, ident) = match ¶m.kind {
- GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
- GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
- GenericParamKind::Const { ref ty } => {
+ GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident),
+ GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
+ GenericParamKind::Const { ref ty, kw_span: _ } => {
let ty = pprust::ty_to_string(ty);
(ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
}
token::Shebang(s) => format!("/* shebang: {}*/", s),
token::Unknown(s) => s.to_string(),
- token::Interpolated(ref nt) => nonterminal_to_string(nt),
+ token::Interpolated(ref nt, _) => nonterminal_to_string(nt),
}
}
s.print_type(default)
}
}
- ast::GenericParamKind::Const { ref ty } => {
+ ast::GenericParamKind::Const { ref ty, kw_span: _ } => {
s.word_space("const");
s.print_ident(param.ident);
s.s.space();
use rustc_ast::ast;
use rustc_ast::with_default_globals;
-use rustc_span;
use rustc_span::source_map::respan;
use rustc_span::symbol::Ident;
use rustc_span::{InnerSpan, Span};
struct AsmArgs {
- template: P<ast::Expr>,
+ templates: Vec<P<ast::Expr>>,
operands: Vec<(ast::InlineAsmOperand, Span)>,
named_args: FxHashMap<Symbol, usize>,
reg_args: FxHashSet<usize>,
options: ast::InlineAsmOptions,
- options_span: Option<Span>,
+ options_spans: Vec<Span>,
}
fn parse_args<'a>(
return Err(err);
}
- let template = p.parse_expr()?;
+ let first_template = p.parse_expr()?;
let mut args = AsmArgs {
- template,
+ templates: vec![first_template],
operands: vec![],
named_args: FxHashMap::default(),
reg_args: FxHashSet::default(),
options: ast::InlineAsmOptions::empty(),
- options_span: None,
+ options_spans: vec![],
};
- let mut first = true;
+ let mut allow_templates = true;
while p.token != token::Eof {
if !p.eat(&token::Comma) {
- if first {
- // After `asm!(""` we always expect *only* a comma...
+ if allow_templates {
+ // After a template string, we always expect *only* a comma...
let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
err.span_label(p.token.span, "expected `,`");
p.maybe_annotate_with_ascription(&mut err, false);
return Err(p.expect(&token::Comma).err().unwrap());
}
}
- first = false;
if p.token == token::Eof {
break;
} // accept trailing commas
// Parse options
if p.eat(&token::Ident(sym::options, false)) {
parse_options(&mut p, &mut args)?;
+ allow_templates = false;
continue;
}
let (ident, _) = p.token.ident().unwrap();
p.bump();
p.expect(&token::Eq)?;
+ allow_templates = false;
Some(ident.name)
} else {
None
} else if p.eat(&token::Ident(kw::Const, false)) {
let expr = p.parse_expr()?;
ast::InlineAsmOperand::Const { expr }
- } else {
- p.expect(&token::Ident(sym::sym, false))?;
+ } else if p.eat(&token::Ident(sym::sym, false)) {
let expr = p.parse_expr()?;
match expr.kind {
ast::ExprKind::Path(..) => {}
}
}
ast::InlineAsmOperand::Sym { expr }
+ } else if allow_templates {
+ let template = p.parse_expr()?;
+ // If it can't possibly expand to a string, provide diagnostics here to include other
+ // things it could have been.
+ match template.kind {
+ ast::ExprKind::Lit(ast::Lit { kind: ast::LitKind::Str(..), .. }) => {}
+ ast::ExprKind::MacCall(..) => {}
+ _ => {
+ let errstr = "expected operand, options, or additional template string";
+ let mut err = ecx.struct_span_err(template.span, errstr);
+ err.span_label(template.span, errstr);
+ return Err(err);
+ }
+ }
+ args.templates.push(template);
+ continue;
+ } else {
+ return Err(p.expect_one_of(&[], &[]).unwrap_err());
};
+ allow_templates = false;
let span = span_start.to(p.prev_token.span);
let slot = args.operands.len();
args.operands.push((op, span));
// Validate the order of named, positional & explicit register operands and options. We do
// this at the end once we have the full span of the argument available.
- if let Some(options_span) = args.options_span {
+ if !args.options_spans.is_empty() {
ecx.struct_span_err(span, "arguments are not allowed after options")
- .span_label(options_span, "previous options")
+ .span_labels(args.options_spans.clone(), "previous options")
.span_label(span, "argument")
.emit();
}
if args.options.contains(ast::InlineAsmOptions::NOMEM)
&& args.options.contains(ast::InlineAsmOptions::READONLY)
{
- let span = args.options_span.unwrap();
- ecx.struct_span_err(span, "the `nomem` and `readonly` options are mutually exclusive")
+ let spans = args.options_spans.clone();
+ ecx.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive")
.emit();
}
if args.options.contains(ast::InlineAsmOptions::PURE)
&& args.options.contains(ast::InlineAsmOptions::NORETURN)
{
- let span = args.options_span.unwrap();
- ecx.struct_span_err(span, "the `pure` and `noreturn` options are mutually exclusive")
+ let spans = args.options_spans.clone();
+ ecx.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive")
.emit();
}
if args.options.contains(ast::InlineAsmOptions::PURE)
&& !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
{
- let span = args.options_span.unwrap();
+ let spans = args.options_spans.clone();
ecx.struct_span_err(
- span,
+ spans,
"the `pure` option must be combined with either `nomem` or `readonly`",
)
.emit();
}
if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
ecx.struct_span_err(
- args.options_span.unwrap(),
+ args.options_spans.clone(),
"asm with `pure` option must have at least one output",
)
.emit();
Ok(args)
}
+/// Report a duplicate option error.
+///
+/// This function must be called immediately after the option token is parsed.
+/// Otherwise, the suggestion will be incorrect.
+fn err_duplicate_option<'a>(p: &mut Parser<'a>, symbol: Symbol, span: Span) {
+ let mut err = p
+ .sess
+ .span_diagnostic
+ .struct_span_err(span, &format!("the `{}` option was already provided", symbol));
+ err.span_label(span, "this option was already provided");
+
+ // Tool-only output
+ let mut full_span = span;
+ if p.token.kind == token::Comma {
+ full_span = full_span.to(p.token.span);
+ }
+ err.tool_only_span_suggestion(
+ full_span,
+ "remove this option",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+
+ err.emit();
+}
+
+/// Try to set the provided option in the provided `AsmArgs`.
+/// If it is already set, report a duplicate option error.
+///
+/// This function must be called immediately after the option token is parsed.
+/// Otherwise, the error will not point to the correct spot.
+fn try_set_option<'a>(
+ p: &mut Parser<'a>,
+ args: &mut AsmArgs,
+ symbol: Symbol,
+ option: ast::InlineAsmOptions,
+) {
+ if !args.options.contains(option) {
+ args.options |= option;
+ } else {
+ err_duplicate_option(p, symbol, p.prev_token.span);
+ }
+}
+
fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), DiagnosticBuilder<'a>> {
let span_start = p.prev_token.span;
while !p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
if p.eat(&token::Ident(sym::pure, false)) {
- args.options |= ast::InlineAsmOptions::PURE;
+ try_set_option(p, args, sym::pure, ast::InlineAsmOptions::PURE);
} else if p.eat(&token::Ident(sym::nomem, false)) {
- args.options |= ast::InlineAsmOptions::NOMEM;
+ try_set_option(p, args, sym::nomem, ast::InlineAsmOptions::NOMEM);
} else if p.eat(&token::Ident(sym::readonly, false)) {
- args.options |= ast::InlineAsmOptions::READONLY;
+ try_set_option(p, args, sym::readonly, ast::InlineAsmOptions::READONLY);
} else if p.eat(&token::Ident(sym::preserves_flags, false)) {
- args.options |= ast::InlineAsmOptions::PRESERVES_FLAGS;
+ try_set_option(p, args, sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS);
} else if p.eat(&token::Ident(sym::noreturn, false)) {
- args.options |= ast::InlineAsmOptions::NORETURN;
+ try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN);
} else if p.eat(&token::Ident(sym::nostack, false)) {
- args.options |= ast::InlineAsmOptions::NOSTACK;
+ try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK);
} else {
p.expect(&token::Ident(sym::att_syntax, false))?;
- args.options |= ast::InlineAsmOptions::ATT_SYNTAX;
+ try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
}
// Allow trailing commas
}
let new_span = span_start.to(p.prev_token.span);
- if let Some(options_span) = args.options_span {
- p.struct_span_err(new_span, "asm options cannot be specified multiple times")
- .span_label(options_span, "previously here")
- .span_label(new_span, "duplicate options")
- .emit();
- } else {
- args.options_span = Some(new_span);
- }
+ args.options_spans.push(new_span);
Ok(())
}
}
fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast::Expr> {
- let msg = "asm template must be a string literal";
- let template_sp = args.template.span;
- let (template_str, template_style, template_span) =
- match expr_to_spanned_string(ecx, args.template, msg) {
- Ok(template) => template,
- Err(err) => {
- if let Some(mut err) = err {
- err.emit();
- }
- return DummyResult::raw_expr(sp, true);
- }
- };
-
- let str_style = match template_style {
- ast::StrStyle::Cooked => None,
- ast::StrStyle::Raw(raw) => Some(raw as usize),
- };
-
- let template_str = &template_str.as_str();
- let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok();
- let mut parser = parse::Parser::new(
- template_str,
- str_style,
- template_snippet,
- false,
- parse::ParseMode::InlineAsm,
- );
-
- let mut unverified_pieces = Vec::new();
- while let Some(piece) = parser.next() {
- if !parser.errors.is_empty() {
- break;
- } else {
- unverified_pieces.push(piece);
- }
- }
-
- if !parser.errors.is_empty() {
- let err = parser.errors.remove(0);
- let err_sp = template_span.from_inner(err.span);
- let mut e = ecx
- .struct_span_err(err_sp, &format!("invalid asm template string: {}", err.description));
- e.span_label(err_sp, err.label + " in asm template string");
- if let Some(note) = err.note {
- e.note(¬e);
- }
- if let Some((label, span)) = err.secondary_label {
- let err_sp = template_span.from_inner(span);
- e.span_label(err_sp, label);
- }
- e.emit();
- return DummyResult::raw_expr(sp, true);
- }
-
+ let mut template = vec![];
// Register operands are implicitly used since they are not allowed to be
// referenced in the template string.
let mut used = vec![false; args.operands.len()];
for pos in &args.reg_args {
used[*pos] = true;
}
-
let named_pos: FxHashMap<usize, Symbol> =
args.named_args.iter().map(|(&sym, &idx)| (idx, sym)).collect();
- let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span));
- let mut template = vec![];
- for piece in unverified_pieces {
- match piece {
- parse::Piece::String(s) => {
- template.push(ast::InlineAsmTemplatePiece::String(s.to_string()))
+ let mut line_spans = Vec::with_capacity(args.templates.len());
+ let mut curarg = 0;
+
+ for template_expr in args.templates.into_iter() {
+ if !template.is_empty() {
+ template.push(ast::InlineAsmTemplatePiece::String("\n".to_string()));
+ }
+
+ let msg = "asm template must be a string literal";
+ let template_sp = template_expr.span;
+ let (template_str, template_style, template_span) =
+ match expr_to_spanned_string(ecx, template_expr, msg) {
+ Ok(template_part) => template_part,
+ Err(err) => {
+ if let Some(mut err) = err {
+ err.emit();
+ }
+ return DummyResult::raw_expr(sp, true);
+ }
+ };
+
+ let str_style = match template_style {
+ ast::StrStyle::Cooked => None,
+ ast::StrStyle::Raw(raw) => Some(raw as usize),
+ };
+
+ let template_str = &template_str.as_str();
+ let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok();
+ let mut parser = parse::Parser::new(
+ template_str,
+ str_style,
+ template_snippet,
+ false,
+ parse::ParseMode::InlineAsm,
+ );
+ parser.curarg = curarg;
+
+ let mut unverified_pieces = Vec::new();
+ while let Some(piece) = parser.next() {
+ if !parser.errors.is_empty() {
+ break;
+ } else {
+ unverified_pieces.push(piece);
+ }
+ }
+
+ if !parser.errors.is_empty() {
+ let err = parser.errors.remove(0);
+ let err_sp = template_span.from_inner(err.span);
+ let msg = &format!("invalid asm template string: {}", err.description);
+ let mut e = ecx.struct_span_err(err_sp, msg);
+ e.span_label(err_sp, err.label + " in asm template string");
+ if let Some(note) = err.note {
+ e.note(¬e);
+ }
+ if let Some((label, span)) = err.secondary_label {
+ let err_sp = template_span.from_inner(span);
+ e.span_label(err_sp, label);
}
- parse::Piece::NextArgument(arg) => {
- let span = arg_spans.next().unwrap_or(template_sp);
-
- let operand_idx = match arg.position {
- parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => {
- if idx >= args.operands.len()
- || named_pos.contains_key(&idx)
- || args.reg_args.contains(&idx)
- {
- let msg = format!("invalid reference to argument at index {}", idx);
- let mut err = ecx.struct_span_err(span, &msg);
- err.span_label(span, "from here");
-
- let positional_args =
- args.operands.len() - args.named_args.len() - args.reg_args.len();
- let positional = if positional_args != args.operands.len() {
- "positional "
+ e.emit();
+ return DummyResult::raw_expr(sp, true);
+ }
+
+ curarg = parser.curarg;
+
+ let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span));
+ for piece in unverified_pieces {
+ match piece {
+ parse::Piece::String(s) => {
+ template.push(ast::InlineAsmTemplatePiece::String(s.to_string()))
+ }
+ parse::Piece::NextArgument(arg) => {
+ let span = arg_spans.next().unwrap_or(template_sp);
+
+ let operand_idx = match arg.position {
+ parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => {
+ if idx >= args.operands.len()
+ || named_pos.contains_key(&idx)
+ || args.reg_args.contains(&idx)
+ {
+ let msg = format!("invalid reference to argument at index {}", idx);
+ let mut err = ecx.struct_span_err(span, &msg);
+ err.span_label(span, "from here");
+
+ let positional_args = args.operands.len()
+ - args.named_args.len()
+ - args.reg_args.len();
+ let positional = if positional_args != args.operands.len() {
+ "positional "
+ } else {
+ ""
+ };
+ let msg = match positional_args {
+ 0 => format!("no {}arguments were given", positional),
+ 1 => format!("there is 1 {}argument", positional),
+ x => format!("there are {} {}arguments", x, positional),
+ };
+ err.note(&msg);
+
+ if named_pos.contains_key(&idx) {
+ err.span_label(args.operands[idx].1, "named argument");
+ err.span_note(
+ args.operands[idx].1,
+ "named arguments cannot be referenced by position",
+ );
+ } else if args.reg_args.contains(&idx) {
+ err.span_label(
+ args.operands[idx].1,
+ "explicit register argument",
+ );
+ err.span_note(
+ args.operands[idx].1,
+ "explicit register arguments cannot be used in the asm template",
+ );
+ }
+ err.emit();
+ None
} else {
- ""
- };
- let msg = match positional_args {
- 0 => format!("no {}arguments were given", positional),
- 1 => format!("there is 1 {}argument", positional),
- x => format!("there are {} {}arguments", x, positional),
- };
- err.note(&msg);
-
- if named_pos.contains_key(&idx) {
- err.span_label(args.operands[idx].1, "named argument");
- err.span_note(
- args.operands[idx].1,
- "named arguments cannot be referenced by position",
- );
- } else if args.reg_args.contains(&idx) {
- err.span_label(args.operands[idx].1, "explicit register argument");
- err.span_note(
- args.operands[idx].1,
- "explicit register arguments cannot be used in the asm template",
- );
+ Some(idx)
}
- err.emit();
- None
- } else {
- Some(idx)
- }
- }
- parse::ArgumentNamed(name) => match args.named_args.get(&name) {
- Some(&idx) => Some(idx),
- None => {
- let msg = format!("there is no argument named `{}`", name);
- ecx.struct_span_err(span, &msg[..]).emit();
- None
}
- },
- };
-
- let mut chars = arg.format.ty.chars();
- let mut modifier = chars.next();
- if chars.next().is_some() {
- let span = arg
- .format
- .ty_span
- .map(|sp| template_sp.from_inner(sp))
- .unwrap_or(template_sp);
- ecx.struct_span_err(span, "asm template modifier must be a single character")
+ parse::ArgumentNamed(name) => match args.named_args.get(&name) {
+ Some(&idx) => Some(idx),
+ None => {
+ let msg = format!("there is no argument named `{}`", name);
+ ecx.struct_span_err(span, &msg[..]).emit();
+ None
+ }
+ },
+ };
+
+ let mut chars = arg.format.ty.chars();
+ let mut modifier = chars.next();
+ if chars.next().is_some() {
+ let span = arg
+ .format
+ .ty_span
+ .map(|sp| template_sp.from_inner(sp))
+ .unwrap_or(template_sp);
+ ecx.struct_span_err(
+ span,
+ "asm template modifier must be a single character",
+ )
.emit();
- modifier = None;
- }
+ modifier = None;
+ }
- if let Some(operand_idx) = operand_idx {
- used[operand_idx] = true;
- template.push(ast::InlineAsmTemplatePiece::Placeholder {
- operand_idx,
- modifier,
- span,
- });
+ if let Some(operand_idx) = operand_idx {
+ used[operand_idx] = true;
+ template.push(ast::InlineAsmTemplatePiece::Placeholder {
+ operand_idx,
+ modifier,
+ span,
+ });
+ }
}
}
}
+
+ if parser.line_spans.is_empty() {
+ let template_num_lines = 1 + template_str.matches('\n').count();
+ line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines));
+ } else {
+ line_spans.extend(parser.line_spans.iter().map(|span| template_span.from_inner(*span)));
+ };
}
let mut unused_operands = vec![];
}
}
- let line_spans = if parser.line_spans.is_empty() {
- vec![template_sp]
- } else {
- parser.line_spans.iter().map(|span| template_span.from_inner(*span)).collect()
- };
-
let inline_asm =
ast::InlineAsm { template, operands: args.operands, options: args.options, line_spans };
P(ast::Expr {
*default = None;
ast::GenericArg::Type(cx.ty_ident(span, param.ident))
}
- ast::GenericParamKind::Const { ty: _ } => {
+ ast::GenericParamKind::Const { ty: _, kw_span: _ } => {
ast::GenericArg::Const(cx.const_ident(span, param.ident))
}
})
};
let sp = cx.with_def_site_ctxt(sp);
- let e = match env::var(&var.as_str()) {
- Err(..) => {
+ let value = env::var(&var.as_str()).ok().as_deref().map(Symbol::intern);
+ cx.parse_sess.env_depinfo.borrow_mut().insert((Symbol::intern(&var), value));
+ let e = match value {
+ None => {
let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp));
cx.expr_path(cx.path_all(
sp,
))],
))
}
- Ok(s) => cx.expr_call_global(
+ Some(value) => cx.expr_call_global(
sp,
cx.std_path(&[sym::option, sym::Option, sym::Some]),
- vec![cx.expr_str(sp, Symbol::intern(&s))],
+ vec![cx.expr_str(sp, value)],
),
};
MacEager::expr(e)
}
let sp = cx.with_def_site_ctxt(sp);
- let e = match env::var(&*var.as_str()) {
- Err(_) => {
+ let value = env::var(&*var.as_str()).ok().as_deref().map(Symbol::intern);
+ cx.parse_sess.env_depinfo.borrow_mut().insert((var, value));
+ let e = match value {
+ None => {
cx.span_err(sp, &msg.as_str());
return DummyResult::any(sp);
}
- Ok(s) => cx.expr_str(sp, Symbol::intern(&s)),
+ Some(value) => cx.expr_str(sp, value),
};
MacEager::expr(e)
}
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
+#![feature(inner_deref)]
#![feature(nll)]
#![feature(or_patterns)]
#![feature(proc_macro_internals)]
use crate::deriving::*;
-use rustc_expand::base::{MacroExpanderFn, Resolver, SyntaxExtension, SyntaxExtensionKind};
+use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::proc_macro::BangProcMacro;
use rustc_span::edition::Edition;
use rustc_span::symbol::{sym, Ident};
pub mod standard_library_imports;
pub mod test_harness;
-pub fn register_builtin_macros(resolver: &mut dyn Resolver, edition: Edition) {
+pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand, edition: Edition) {
let mut register = |name, kind| {
resolver.register_builtin_macro(
Ident::with_dummy_span(name),
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, Visitor};
use rustc_ast_pretty::pprust;
-use rustc_expand::base::{ExtCtxt, Resolver};
+use rustc_expand::base::{ExtCtxt, ResolverExpand};
use rustc_expand::expand::{AstFragment, ExpansionConfig};
use rustc_session::parse::ParseSess;
use rustc_span::hygiene::AstPass;
pub fn inject(
sess: &ParseSess,
- resolver: &mut dyn Resolver,
+ resolver: &mut dyn ResolverExpand,
mut krate: ast::Crate,
is_proc_macro_crate: bool,
has_proc_macro_decls: bool,
use rustc_ast::ptr::P;
use rustc_ast::{ast, attr};
-use rustc_expand::base::{ExtCtxt, Resolver};
+use rustc_expand::base::{ExtCtxt, ResolverExpand};
use rustc_expand::expand::ExpansionConfig;
use rustc_session::parse::ParseSess;
use rustc_span::edition::Edition;
pub fn inject(
mut krate: ast::Crate,
- resolver: &mut dyn Resolver,
+ resolver: &mut dyn ResolverExpand,
sess: &ParseSess,
alt_std_name: Option<Symbol>,
) -> (ast::Crate, Option<Symbol>) {
use rustc_ast::entry::{self, EntryPointType};
use rustc_ast::mut_visit::{ExpectOne, *};
use rustc_ast::ptr::P;
-use rustc_expand::base::{ExtCtxt, Resolver};
+use rustc_expand::base::{ExtCtxt, ResolverExpand};
use rustc_expand::expand::{AstFragment, ExpansionConfig};
use rustc_feature::Features;
use rustc_session::parse::ParseSess;
// existing main functions, and synthesizing a main test harness
pub fn inject(
sess: &ParseSess,
- resolver: &mut dyn Resolver,
+ resolver: &mut dyn ResolverExpand,
should_test: bool,
krate: &mut ast::Crate,
span_diagnostic: &rustc_errors::Handler,
/// Crawl over the crate, inserting test reexports and the test main function
fn generate_test_harness(
sess: &ParseSess,
- resolver: &mut dyn Resolver,
+ resolver: &mut dyn ResolverExpand,
reexport_test_harness_main: Option<Symbol>,
krate: &mut ast::Crate,
features: &Features,
}
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {}
InlineAsmArch::Nvptx64 => {}
+ InlineAsmArch::Hexagon => {}
}
}
if !options.contains(InlineAsmOptions::NOMEM) {
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => "x",
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w",
+ InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
modifier
}
}
+ InlineAsmRegClass::Hexagon(_) => None,
InlineAsmRegClass::Nvptx(_) => None,
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
| InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None,
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
cx.type_vector(cx.type_i64(), 2)
}
+ InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
-use rustc_session::config::{OptLevel, Sanitizer};
+use rustc_session::config::{OptLevel, SanitizerSet};
use rustc_session::Session;
use crate::attributes;
/// Apply LLVM sanitize attributes.
#[inline]
-pub fn sanitize(cx: &CodegenCx<'ll, '_>, codegen_fn_flags: CodegenFnAttrFlags, llfn: &'ll Value) {
- if let Some(ref sanitizer) = cx.tcx.sess.opts.debugging_opts.sanitizer {
- match *sanitizer {
- Sanitizer::Address => {
- if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_ADDRESS) {
- llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn);
- }
- }
- Sanitizer::Memory => {
- if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_MEMORY) {
- llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn);
- }
- }
- Sanitizer::Thread => {
- if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_THREAD) {
- llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
- }
- }
- Sanitizer::Leak => {}
- }
+pub fn sanitize(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &'ll Value) {
+ let enabled = cx.tcx.sess.opts.debugging_opts.sanitizer - no_sanitize;
+ if enabled.contains(SanitizerSet::ADDRESS) {
+ llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn);
+ }
+ if enabled.contains(SanitizerSet::MEMORY) {
+ llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn);
+ }
+ if enabled.contains(SanitizerSet::THREAD) {
+ llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
}
}
// Currently stack probes seem somewhat incompatible with the address
// sanitizer and thread sanitizer. With asan we're already protected from
// stack overflow anyway so we don't really need stack probes regardless.
- match cx.sess().opts.debugging_opts.sanitizer {
- Some(Sanitizer::Address | Sanitizer::Thread) => return,
- _ => {}
+ if cx
+ .sess()
+ .opts
+ .debugging_opts
+ .sanitizer
+ .intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD)
+ {
+ return;
}
// probestack doesn't play nice either with `-C profile-generate`.
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
Attribute::NoAlias.apply_llfn(llvm::AttributePlace::ReturnValue, llfn);
}
- sanitize(cx, codegen_fn_attrs.flags, llfn);
+ sanitize(cx, codegen_fn_attrs.no_sanitize, llfn);
// Always annotate functions with the target-cpu they are compiled for.
// Without this, ThinLTO won't inline Rust functions into Clang generated
kind: ModuleKind::Regular,
};
{
+ let target = &*module.module_llvm.tm;
let llmod = module.module_llvm.llmod();
save_temp_bitcode(&cgcx, &module, "thin-lto-input");
{
let _timer =
cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name());
- if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod) {
+ if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg));
}
{
let _timer =
cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name());
- if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod) {
+ if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg));
}
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::bug;
use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{self, Lto, OutputType, Passes, Sanitizer, SwitchWithOptPath};
+use rustc_session::config::{self, Lto, OutputType, Passes, SanitizerSet, SwitchWithOptPath};
use rustc_session::Session;
+use rustc_span::symbol::sym;
use rustc_span::InnerSpan;
use rustc_target::spec::{CodeModel, RelocModel};
// lower atomic operations to single-threaded operations.
if singlethread
&& sess.target.target.llvm_target.contains("wasm32")
- && features.iter().any(|s| *s == "+atomics")
+ && sess.target_features.contains(&sym::atomics)
{
singlethread = false;
}
let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO;
// Sanitizer instrumentation is only inserted during the pre-link optimization stage.
let sanitizer_options = if !is_lto {
- config.sanitizer.as_ref().map(|s| llvm::SanitizerOptions {
- sanitize_memory: *s == Sanitizer::Memory,
- sanitize_thread: *s == Sanitizer::Thread,
- sanitize_address: *s == Sanitizer::Address,
- sanitize_recover: config.sanitizer_recover.contains(s),
+ Some(llvm::SanitizerOptions {
+ sanitize_address: config.sanitizer.contains(SanitizerSet::ADDRESS),
+ sanitize_address_recover: config.sanitizer_recover.contains(SanitizerSet::ADDRESS),
+ sanitize_memory: config.sanitizer.contains(SanitizerSet::MEMORY),
+ sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
+ sanitize_thread: config.sanitizer.contains(SanitizerSet::THREAD),
})
} else {
None
}
unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static mut llvm::Pass>) {
- let sanitizer = match &config.sanitizer {
- None => return,
- Some(s) => s,
- };
-
- let recover = config.sanitizer_recover.contains(sanitizer);
- match sanitizer {
- Sanitizer::Address => {
- passes.push(llvm::LLVMRustCreateAddressSanitizerFunctionPass(recover));
- passes.push(llvm::LLVMRustCreateModuleAddressSanitizerPass(recover));
- }
- Sanitizer::Memory => {
- let track_origins = config.sanitizer_memory_track_origins as c_int;
- passes.push(llvm::LLVMRustCreateMemorySanitizerPass(track_origins, recover));
- }
- Sanitizer::Thread => {
- passes.push(llvm::LLVMRustCreateThreadSanitizerPass());
- }
- Sanitizer::Leak => {}
+ if config.sanitizer.contains(SanitizerSet::ADDRESS) {
+ let recover = config.sanitizer_recover.contains(SanitizerSet::ADDRESS);
+ passes.push(llvm::LLVMRustCreateAddressSanitizerFunctionPass(recover));
+ passes.push(llvm::LLVMRustCreateModuleAddressSanitizerPass(recover));
+ }
+ if config.sanitizer.contains(SanitizerSet::MEMORY) {
+ let track_origins = config.sanitizer_memory_track_origins as c_int;
+ let recover = config.sanitizer_recover.contains(SanitizerSet::MEMORY);
+ passes.push(llvm::LLVMRustCreateMemorySanitizerPass(track_origins, recover));
+ }
+ if config.sanitizer.contains(SanitizerSet::THREAD) {
+ passes.push(llvm::LLVMRustCreateThreadSanitizerPass());
}
}
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_middle::dep_graph;
-use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::middle::exported_symbols;
use rustc_middle::mir::mono::{Linkage, Visibility};
use rustc_middle::ty::TyCtxt;
-use rustc_session::config::DebugInfo;
+use rustc_session::config::{DebugInfo, SanitizerSet};
use rustc_span::symbol::Symbol;
use std::ffi::CString;
// If this codegen unit contains the main function, also create the
// wrapper here
if let Some(entry) = maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx) {
- attributes::sanitize(&cx, CodegenFnAttrFlags::empty(), entry);
+ attributes::sanitize(&cx, SanitizerSet::empty(), entry);
}
// Run replace-all-uses-with for statics that need it
self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size);
}
+ fn instrprof_increment(
+ &mut self,
+ fn_name: &'ll Value,
+ hash: &'ll Value,
+ num_counters: &'ll Value,
+ index: &'ll Value,
+ ) -> &'ll Value {
+ debug!(
+ "instrprof_increment() with args ({:?}, {:?}, {:?}, {:?})",
+ fn_name, hash, num_counters, index
+ );
+
+ let llfn = unsafe { llvm::LLVMRustGetInstrprofIncrementIntrinsic(self.cx().llmod) };
+ let args = &[fn_name, hash, num_counters, index];
+ let args = self.check_call("call", llfn, args);
+
+ unsafe {
+ llvm::LLVMRustBuildCall(
+ self.llbuilder,
+ llfn,
+ args.as_ptr() as *const &llvm::Value,
+ args.len() as c_uint,
+ None,
+ )
+ }
+ }
+
fn call(
&mut self,
llfn: &'ll Value,
let len = s.as_str().len();
let cs = consts::ptrcast(
self.const_cstr(s, false),
- self.type_ptr_to(self.layout_of(self.tcx.mk_str()).llvm_type(self)),
+ self.type_ptr_to(self.layout_of(self.tcx.types.str_).llvm_type(self)),
);
(cs, self.const_usize(len as u64))
}
ifn!("llvm.lifetime.start.p0i8", fn(t_i64, i8p) -> void);
ifn!("llvm.lifetime.end.p0i8", fn(t_i64, i8p) -> void);
+ ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void);
+
ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32);
ifn!("llvm.localescape", fn(...) -> void);
-use self::EnumDiscriminantInfo::*;
+use self::EnumTagInfo::*;
use self::MemberDescriptionFactory::*;
use self::RecursiveTypeDescription::*;
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::ich::NodeIdHashingMode;
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::interpret::truncate;
use rustc_middle::mir::{self, Field, GeneratorLayout};
use rustc_middle::ty::layout::{self, IntegerExt, PrimitiveExt, TyAndLayout};
-use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
+use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::Instance;
-use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, GeneratorSubsts, ParamEnv, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::config::{self, DebugInfo};
use rustc_span::symbol::{Interner, Symbol};
use rustc_span::{self, SourceFile, SourceFileHash, Span};
-use rustc_target::abi::{Abi, Align, DiscriminantKind, HasDataLayout, Integer, LayoutOf};
+use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, LayoutOf, TagEncoding};
use rustc_target::abi::{Int, Pointer, F32, F64};
use rustc_target::abi::{Primitive, Size, VariantIdx, Variants};
align: pointer_align,
flags: DIFlags::FlagZero,
discriminant: None,
+ source_info: None,
},
MemberDescription {
name: "length".to_owned(),
align: usize_align,
flags: DIFlags::FlagZero,
discriminant: None,
+ source_info: None,
},
];
align: data_ptr_field.align.abi,
flags: DIFlags::FlagArtificial,
discriminant: None,
+ source_info: None,
},
MemberDescription {
name: "vtable".to_owned(),
align: vtable_field.align.abi,
flags: DIFlags::FlagArtificial,
discriminant: None,
+ source_info: None,
},
];
debug!("foreign_type_metadata: {:?}", t);
let name = compute_debuginfo_type_name(cx.tcx, t, false);
- create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA)
+ create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero)
}
fn pointer_type_metadata(
}
}
+#[derive(Debug)]
+struct SourceInfo<'ll> {
+ file: &'ll DIFile,
+ line: u32,
+}
+
/// Description of a type member, which can either be a regular field (as in
/// structs or tuples) or an enum variant.
#[derive(Debug)]
align: Align,
flags: DIFlags,
discriminant: Option<u64>,
+ source_info: Option<SourceInfo<'ll>>,
}
impl<'ll> MemberDescription<'ll> {
cx: &CodegenCx<'ll, '_>,
composite_type_metadata: &'ll DIScope,
) -> &'ll DIType {
+ let (file, line) = self
+ .source_info
+ .map(|info| (info.file, info.line))
+ .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER));
unsafe {
llvm::LLVMRustDIBuilderCreateVariantMemberType(
DIB(cx),
composite_type_metadata,
self.name.as_ptr().cast(),
self.name.len(),
- unknown_file_metadata(cx),
- UNKNOWN_LINE_NUMBER,
+ file,
+ line,
self.size.bits(),
self.align.bits() as u32,
self.offset.bits(),
align: field.align.abi,
flags: DIFlags::FlagZero,
discriminant: None,
+ source_info: None,
}
})
.collect()
let containing_scope = get_namespace_for_item(cx, struct_def_id);
- let struct_metadata_stub =
- create_struct_stub(cx, struct_type, &struct_name, unique_type_id, Some(containing_scope));
+ let struct_metadata_stub = create_struct_stub(
+ cx,
+ struct_type,
+ &struct_name,
+ unique_type_id,
+ Some(containing_scope),
+ DIFlags::FlagZero,
+ );
create_and_register_recursive_type_forward_declaration(
cx,
align,
flags: DIFlags::FlagZero,
discriminant: None,
+ source_info: None,
}
})
.collect()
) -> RecursiveTypeDescription<'ll, 'tcx> {
let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false);
- let struct_stub =
- create_struct_stub(cx, tuple_type, &tuple_name[..], unique_type_id, containing_scope);
+ let struct_stub = create_struct_stub(
+ cx,
+ tuple_type,
+ &tuple_name[..],
+ unique_type_id,
+ containing_scope,
+ DIFlags::FlagZero,
+ );
create_and_register_recursive_type_forward_declaration(
cx,
align: field.align.abi,
flags: DIFlags::FlagZero,
discriminant: None,
+ source_info: None,
}
})
.collect()
struct EnumMemberDescriptionFactory<'ll, 'tcx> {
enum_type: Ty<'tcx>,
layout: TyAndLayout<'tcx>,
- discriminant_type_metadata: Option<&'ll DIType>,
+ tag_type_metadata: Option<&'ll DIType>,
containing_scope: &'ll DIScope,
span: Span,
}
let variant_info_for = |index: VariantIdx| match self.enum_type.kind {
ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]),
- ty::Generator(_, substs, _) => {
+ ty::Generator(def_id, _, _) => {
let (generator_layout, generator_saved_local_names) =
generator_variant_info_data.as_ref().unwrap();
VariantInfo::Generator {
- substs,
+ def_id,
generator_layout: *generator_layout,
generator_saved_local_names,
variant_index: index,
} else {
type_metadata(cx, self.enum_type, self.span)
};
+ let flags = match self.enum_type.kind {
+ ty::Generator(..) => DIFlags::FlagArtificial,
+ _ => DIFlags::FlagZero,
+ };
match self.layout.variants {
Variants::Single { index } => {
cx,
self.layout,
variant_info,
- NoDiscriminant,
+ NoTag,
self_metadata,
self.span,
);
offset: Size::ZERO,
size: self.layout.size,
align: self.layout.align.abi,
- flags: DIFlags::FlagZero,
+ flags,
discriminant: None,
+ source_info: variant_info.source_info(cx),
}]
}
Variants::Multiple {
- discr_kind: DiscriminantKind::Tag,
- discr_index,
+ tag_encoding: TagEncoding::Direct,
+ tag_field,
ref variants,
..
} => {
- let discriminant_info = if fallback {
- RegularDiscriminant {
- discr_field: Field::from(discr_index),
- discr_type_metadata: self.discriminant_type_metadata.unwrap(),
+ let tag_info = if fallback {
+ RegularTag {
+ tag_field: Field::from(tag_field),
+ tag_type_metadata: self.tag_type_metadata.unwrap(),
}
} else {
// This doesn't matter in this case.
- NoDiscriminant
+ NoTag
};
variants
.iter_enumerated()
cx,
variant,
variant_info,
- discriminant_info,
+ tag_info,
self_metadata,
self.span,
);
offset: Size::ZERO,
size: self.layout.size,
align: self.layout.align.abi,
- flags: DIFlags::FlagZero,
+ flags,
discriminant: Some(
self.layout.ty.discriminant_for_variant(cx.tcx, i).unwrap().val
as u64,
),
+ source_info: variant_info.source_info(cx),
}
})
.collect()
}
Variants::Multiple {
- discr_kind:
- DiscriminantKind::Niche { ref niche_variants, niche_start, dataful_variant },
- ref discr,
+ tag_encoding:
+ TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant },
+ ref tag,
ref variants,
- discr_index,
+ tag_field,
} => {
if fallback {
let variant = self.layout.for_variant(cx, dataful_variant);
cx,
variant,
variant_info_for(dataful_variant),
- OptimizedDiscriminant,
+ OptimizedTag,
self.containing_scope,
self.span,
);
cx,
&mut name,
self.layout,
- self.layout.fields.offset(discr_index),
- self.layout.field(cx, discr_index).size,
+ self.layout.fields.offset(tag_field),
+ self.layout.field(cx, tag_field).size,
);
- variant_info_for(*niche_variants.start()).map_struct_name(|variant_name| {
+ let variant_info = variant_info_for(*niche_variants.start());
+ variant_info.map_struct_name(|variant_name| {
name.push_str(variant_name);
});
offset: Size::ZERO,
size: variant.size,
align: variant.align.abi,
- flags: DIFlags::FlagZero,
+ flags,
discriminant: None,
+ source_info: variant_info.source_info(cx),
}]
} else {
variants
cx,
variant,
variant_info,
- OptimizedDiscriminant,
+ OptimizedTag,
self_metadata,
self.span,
);
let value = (i.as_u32() as u128)
.wrapping_sub(niche_variants.start().as_u32() as u128)
.wrapping_add(niche_start);
- let value = truncate(value, discr.value.size(cx));
+ let value = truncate(value, tag.value.size(cx));
// NOTE(eddyb) do *NOT* remove this assert, until
// we pass the full 128-bit value to LLVM, otherwise
// truncation will be silent and remain undetected.
offset: Size::ZERO,
size: self.layout.size,
align: self.layout.align.abi,
- flags: DIFlags::FlagZero,
+ flags,
discriminant: niche_value,
+ source_info: variant_info.source_info(cx),
}
})
.collect()
/// Cloned from the `layout::Struct` describing the variant.
offsets: Vec<Size>,
args: Vec<(String, Ty<'tcx>)>,
- discriminant_type_metadata: Option<&'ll DIType>,
+ tag_type_metadata: Option<&'ll DIType>,
span: Span,
}
.iter()
.enumerate()
.map(|(i, &(ref name, ty))| {
+ // Discriminant is always the first field of our variant
+ // when using the enum fallback.
+ let is_artificial_discr = use_enum_fallback(cx) && i == 0;
let (size, align) = cx.size_and_align_of(ty);
MemberDescription {
name: name.to_string(),
- type_metadata: if use_enum_fallback(cx) {
- match self.discriminant_type_metadata {
- // Discriminant is always the first field of our variant
- // when using the enum fallback.
- Some(metadata) if i == 0 => metadata,
- _ => type_metadata(cx, ty, self.span),
- }
+ type_metadata: if is_artificial_discr {
+ self.tag_type_metadata.unwrap_or_else(|| type_metadata(cx, ty, self.span))
} else {
type_metadata(cx, ty, self.span)
},
offset: self.offsets[i],
size,
align,
- flags: DIFlags::FlagZero,
+ flags: if is_artificial_discr {
+ DIFlags::FlagArtificial
+ } else {
+ DIFlags::FlagZero
+ },
discriminant: None,
+ source_info: None,
}
})
.collect()
}
}
+// FIXME: terminology here should be aligned with `abi::TagEncoding`.
+// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`.
+// `NoTag` should be removed; users should use `Option<EnumTagInfo>` instead.
#[derive(Copy, Clone)]
-enum EnumDiscriminantInfo<'ll> {
- RegularDiscriminant { discr_field: Field, discr_type_metadata: &'ll DIType },
- OptimizedDiscriminant,
- NoDiscriminant,
+enum EnumTagInfo<'ll> {
+ RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType },
+ OptimizedTag,
+ NoTag,
}
#[derive(Copy, Clone)]
enum VariantInfo<'a, 'tcx> {
Adt(&'tcx ty::VariantDef),
Generator {
- substs: SubstsRef<'tcx>,
+ def_id: DefId,
generator_layout: &'tcx GeneratorLayout<'tcx>,
generator_saved_local_names: &'a IndexVec<mir::GeneratorSavedLocal, Option<Symbol>>,
variant_index: VariantIdx,
fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R {
match self {
VariantInfo::Adt(variant) => f(&variant.ident.as_str()),
- VariantInfo::Generator { substs, variant_index, .. } => {
- f(&substs.as_generator().variant_name(*variant_index))
+ VariantInfo::Generator { variant_index, .. } => {
+ f(&GeneratorSubsts::variant_name(*variant_index))
}
}
}
};
field_name.map(|name| name.to_string()).unwrap_or_else(|| format!("__{}", i))
}
+
+ fn source_info(&self, cx: &CodegenCx<'ll, 'tcx>) -> Option<SourceInfo<'ll>> {
+ match self {
+ VariantInfo::Generator { def_id, variant_index, .. } => {
+ let span =
+ cx.tcx.generator_layout(*def_id).variant_source_info[*variant_index].span;
+ if !span.is_dummy() {
+ let loc = cx.lookup_debug_loc(span.lo());
+ return Some(SourceInfo {
+ file: file_metadata(cx, &loc.file, def_id.krate),
+ line: loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
+ });
+ }
+ }
+ _ => {}
+ }
+ None
+ }
+
+ #[allow(dead_code)]
+ fn is_artificial(&self) -> bool {
+ match self {
+ VariantInfo::Generator { .. } => true,
+ VariantInfo::Adt(..) => false,
+ }
+ }
}
/// Returns a tuple of (1) `type_metadata_stub` of the variant, (2) a
cx: &CodegenCx<'ll, 'tcx>,
layout: layout::TyAndLayout<'tcx>,
variant: VariantInfo<'_, 'tcx>,
- discriminant_info: EnumDiscriminantInfo<'ll>,
+ discriminant_info: EnumTagInfo<'ll>,
containing_scope: &'ll DIScope,
span: Span,
) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
.type_map
.borrow_mut()
.get_unique_type_id_of_enum_variant(cx, layout.ty, &variant_name);
- create_struct_stub(cx, layout.ty, &variant_name, unique_type_id, Some(containing_scope))
+ create_struct_stub(
+ cx,
+ layout.ty,
+ &variant_name,
+ unique_type_id,
+ Some(containing_scope),
+ // FIXME(tmandry): This doesn't seem to have any effect.
+ if variant.is_artificial() { DIFlags::FlagArtificial } else { DIFlags::FlagZero },
+ )
});
// Build an array of (field name, field type) pairs to be captured in the factory closure.
let (offsets, args) = if use_enum_fallback(cx) {
// If this is not a univariant enum, there is also the discriminant field.
let (discr_offset, discr_arg) = match discriminant_info {
- RegularDiscriminant { discr_field, .. } => {
+ RegularTag { tag_field, .. } => {
// We have the layout of an enum variant, we need the layout of the outer enum
let enum_layout = cx.layout_of(layout.ty);
- let offset = enum_layout.fields.offset(discr_field.as_usize());
+ let offset = enum_layout.fields.offset(tag_field.as_usize());
let args =
- ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, discr_field.as_usize()).ty);
+ ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
(Some(offset), Some(args))
}
_ => (None, None),
let member_description_factory = VariantMDF(VariantMemberDescriptionFactory {
offsets,
args,
- discriminant_type_metadata: match discriminant_info {
- RegularDiscriminant { discr_type_metadata, .. } => Some(discr_type_metadata),
+ tag_type_metadata: match discriminant_info {
+ RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata),
_ => None,
},
span,
span: Span,
outer_field_tys: Vec<Ty<'tcx>>,
) -> RecursiveTypeDescription<'ll, 'tcx> {
- let enum_name = compute_debuginfo_type_name(cx.tcx, enum_type, false);
+ let tcx = cx.tcx;
+ let enum_name = compute_debuginfo_type_name(tcx, enum_type, false);
+ // FIXME(tmandry): This doesn't seem to have any effect.
+ let enum_flags = match enum_type.kind {
+ ty::Generator(..) => DIFlags::FlagArtificial,
+ _ => DIFlags::FlagZero,
+ };
let containing_scope = get_namespace_for_item(cx, enum_def_id);
// FIXME: This should emit actual file metadata for the enum, but we
let discriminant_type_metadata = |discr: Primitive| {
let enumerators_metadata: Vec<_> = match enum_type.kind {
ty::Adt(def, _) => def
- .discriminants(cx.tcx)
+ .discriminants(tcx)
.zip(&def.variants)
.map(|((_, discr), v)| {
let name = v.ident.as_str();
.collect(),
ty::Generator(_, substs, _) => substs
.as_generator()
- .variant_range(enum_def_id, cx.tcx)
+ .variant_range(enum_def_id, tcx)
.map(|variant_index| {
- let name = substs.as_generator().variant_name(variant_index);
+ debug_assert_eq!(tcx.types.u32, substs.as_generator().discr_ty(tcx));
+ let name = GeneratorSubsts::variant_name(variant_index);
unsafe {
Some(llvm::LLVMRustDIBuilderCreateEnumerator(
DIB(cx),
name.as_ptr().cast(),
name.len(),
- // Generators use u32 as discriminant type.
+ // Generators use u32 as discriminant type, verified above.
variant_index.as_u32().into(),
true, // IsUnsigned
))
None => {
let (discriminant_size, discriminant_align) = (discr.size(cx), discr.align(cx));
let discriminant_base_type_metadata =
- type_metadata(cx, discr.to_ty(cx.tcx), rustc_span::DUMMY_SP);
+ type_metadata(cx, discr.to_ty(tcx), rustc_span::DUMMY_SP);
let item_name;
let discriminant_name = match enum_type.kind {
ty::Adt(..) => {
- item_name = cx.tcx.item_name(enum_def_id).as_str();
+ item_name = tcx.item_name(enum_def_id).as_str();
&*item_name
}
ty::Generator(..) => enum_name.as_str(),
if let (
&Abi::Scalar(_),
- &Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. },
+ &Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. },
) = (&layout.abi, &layout.variants)
{
- return FinalMetadata(discriminant_type_metadata(discr.value));
+ return FinalMetadata(discriminant_type_metadata(tag.value));
}
if use_enum_fallback(cx) {
let discriminant_type_metadata = match layout.variants {
Variants::Single { .. }
- | Variants::Multiple { discr_kind: DiscriminantKind::Niche { .. }, .. } => None,
- Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. } => {
- Some(discriminant_type_metadata(discr.value))
+ | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None,
+ Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
+ Some(discriminant_type_metadata(tag.value))
}
};
UNKNOWN_LINE_NUMBER,
layout.size.bits(),
layout.align.abi.bits() as u32,
- DIFlags::FlagZero,
+ enum_flags,
None,
0, // RuntimeLang
unique_type_id_str.as_ptr().cast(),
EnumMDF(EnumMemberDescriptionFactory {
enum_type,
layout,
- discriminant_type_metadata,
+ tag_type_metadata: discriminant_type_metadata,
containing_scope,
span,
}),
Variants::Single { .. } => None,
Variants::Multiple {
- discr_kind: DiscriminantKind::Niche { .. },
- ref discr,
- discr_index,
- ..
+ tag_encoding: TagEncoding::Niche { .. }, ref tag, tag_field, ..
} => {
// Find the integer type of the correct size.
- let size = discr.value.size(cx);
- let align = discr.value.align(cx);
+ let size = tag.value.size(cx);
+ let align = tag.value.align(cx);
- let discr_type = match discr.value {
+ let tag_type = match tag.value {
Int(t, _) => t,
F32 => Integer::I32,
F64 => Integer::I64,
}
.to_ty(cx.tcx, false);
- let discr_metadata = basic_type_metadata(cx, discr_type);
+ let tag_metadata = basic_type_metadata(cx, tag_type);
unsafe {
Some(llvm::LLVMRustDIBuilderCreateMemberType(
DIB(cx),
UNKNOWN_LINE_NUMBER,
size.bits(),
align.abi.bits() as u32,
- layout.fields.offset(discr_index).bits(),
+ layout.fields.offset(tag_field).bits(),
DIFlags::FlagArtificial,
- discr_metadata,
+ tag_metadata,
))
}
}
- Variants::Multiple {
- discr_kind: DiscriminantKind::Tag, ref discr, discr_index, ..
- } => {
- let discr_type = discr.value.to_ty(cx.tcx);
+ Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, tag_field, .. } => {
+ let discr_type = tag.value.to_ty(cx.tcx);
let (size, align) = cx.size_and_align_of(discr_type);
let discr_metadata = basic_type_metadata(cx, discr_type);
UNKNOWN_LINE_NUMBER,
size.bits(),
align.bits() as u32,
- layout.fields.offset(discr_index).bits(),
+ layout.fields.offset(tag_field).bits(),
DIFlags::FlagArtificial,
discr_metadata,
))
UNKNOWN_LINE_NUMBER,
layout.size.bits(),
layout.align.abi.bits() as u32,
- DIFlags::FlagZero,
+ enum_flags,
discriminator_metadata,
empty_array,
variant_part_unique_type_id_str.as_ptr().cast(),
UNKNOWN_LINE_NUMBER,
layout.size.bits(),
layout.align.abi.bits() as u32,
- DIFlags::FlagZero,
+ enum_flags,
None,
type_array,
0,
EnumMDF(EnumMemberDescriptionFactory {
enum_type,
layout,
- discriminant_type_metadata: None,
+ tag_type_metadata: None,
containing_scope,
span,
}),
composite_type_name,
composite_type_unique_id,
containing_scope,
+ DIFlags::FlagZero,
);
// ... and immediately create and add the member descriptions.
set_members_of_composite_type(cx, composite_type, composite_type_metadata, member_descriptions);
struct_type_name: &str,
unique_type_id: UniqueTypeId,
containing_scope: Option<&'ll DIScope>,
+ flags: DIFlags,
) -> &'ll DICompositeType {
let (struct_size, struct_align) = cx.size_and_align_of(struct_type);
UNKNOWN_LINE_NUMBER,
struct_size.bits(),
struct_align.bits() as u32,
- DIFlags::FlagZero,
+ flags,
None,
empty_array,
0,
}
let tcx = cx.tcx;
- let attrs = tcx.codegen_fn_attrs(def_id);
- let no_mangle = attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE);
// We may want to remove the namespace scope if we're in an extern block (see
// https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952).
let var_scope = get_namespace_for_item(cx, def_id);
let variable_type = Instance::mono(cx.tcx, def_id).monomorphic_ty(cx.tcx);
let type_metadata = type_metadata(cx, variable_type, span);
let var_name = tcx.item_name(def_id).as_str();
- let linkage_name = if no_mangle {
- None
- } else {
- Some(mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name.as_str())
- };
+ let linkage_name: &str =
+ &mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name.as_str();
// When empty, linkage_name field is omitted,
// which is what we want for no_mangle statics
- let linkage_name = linkage_name.as_deref().unwrap_or("");
+ let linkage_name = if var_name == linkage_name { "" } else { linkage_name };
let global_align = cx.align_of(variable_type);
let substs = instance.substs.truncate_to(self.tcx(), generics);
let template_parameters = get_template_parameters(self, &generics, substs, &mut name);
- // Get the linkage_name, which is just the symbol name
- let linkage_name = mangled_name_of_instance(self, instance);
- let linkage_name = linkage_name.name.as_str();
+ let linkage_name: &str = &mangled_name_of_instance(self, instance).name.as_str();
+ // Omit the linkage_name if it is the same as subprogram name.
+ let linkage_name = if &name == linkage_name { "" } else { linkage_name };
// FIXME(eddyb) does this need to be separate from `loc.line` for some reason?
let scope_line = loc.line;
use crate::va_arg::emit_va_arg;
use crate::value::Value;
+use log::debug;
+
use rustc_ast::ast;
use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh};
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
-use rustc_codegen_ssa::common::TypeKind;
+use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc_codegen_ssa::glue;
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
use rustc_codegen_ssa::mir::place::PlaceRef;
args: &[OperandRef<'tcx, &'ll Value>],
llresult: &'ll Value,
span: Span,
+ caller_instance: ty::Instance<'tcx>,
) {
let tcx = self.tcx;
let callee_ty = instance.monomorphic_ty(tcx);
let llfn = self.get_intrinsic(&("llvm.debugtrap"));
self.call(llfn, &[], None)
}
+ "count_code_region" => {
+ // FIXME(richkadel): The current implementation assumes the MIR for the given
+ // caller_instance represents a single function. Validate and/or correct if inlining
+ // and/or monomorphization invalidates these assumptions.
+ let coverage_data = tcx.coverage_data(caller_instance.def_id());
+ let mangled_fn = tcx.symbol_name(caller_instance);
+ let (mangled_fn_name, _len_val) = self.const_str(mangled_fn.name);
+ let hash = self.const_u64(coverage_data.hash);
+ let num_counters = self.const_u32(coverage_data.num_counters);
+ let index = args[0].immediate();
+ debug!(
+ "count_code_region to LLVM intrinsic instrprof.increment(fn_name={}, hash={:?}, num_counters={:?}, index={:?})",
+ mangled_fn.name, hash, num_counters, index
+ );
+ self.instrprof_increment(mangled_fn_name, hash, num_counters, index)
+ }
"va_start" => self.va_start(args[0].immediate()),
"va_end" => self.va_end(args[0].immediate()),
"va_copy" => {
}
}
"size_of" | "pref_align_of" | "min_align_of" | "needs_drop" | "type_id"
- | "type_name" => {
+ | "type_name" | "variant_count" => {
let value = self
.tcx
.const_eval_instance(ty::ParamEnv::reveal_all(), instance, None)
return;
}
+ "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
+ let a = args[0].immediate();
+ let b = args[1].immediate();
+ if name == "ptr_guaranteed_eq" {
+ self.icmp(IntPredicate::IntEQ, a, b)
+ } else {
+ self.icmp(IntPredicate::IntNE, a, b)
+ }
+ }
+
"ptr_offset_from" => {
let ty = substs.type_at(0);
let pointee_size = self.size_of(ty);
Metadata = 14,
X86_MMX = 15,
Token = 16,
+ ScalableVector = 17,
+ BFloat = 18,
}
impl TypeKind {
TypeKind::Metadata => rustc_codegen_ssa::common::TypeKind::Metadata,
TypeKind::X86_MMX => rustc_codegen_ssa::common::TypeKind::X86_MMX,
TypeKind::Token => rustc_codegen_ssa::common::TypeKind::Token,
+ TypeKind::ScalableVector => rustc_codegen_ssa::common::TypeKind::ScalableVector,
+ TypeKind::BFloat => rustc_codegen_ssa::common::TypeKind::BFloat,
}
}
}
/// LLVMRustSanitizerOptions
#[repr(C)]
pub struct SanitizerOptions {
- pub sanitize_memory: bool,
- pub sanitize_thread: bool,
pub sanitize_address: bool,
- pub sanitize_recover: bool,
+ pub sanitize_address_recover: bool,
+ pub sanitize_memory: bool,
+ pub sanitize_memory_recover: bool,
pub sanitize_memory_track_origins: c_int,
+ pub sanitize_thread: bool,
}
/// LLVMRelocMode
// Miscellaneous instructions
pub fn LLVMBuildPhi(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value;
+ pub fn LLVMRustGetInstrprofIncrementIntrinsic(M: &Module) -> &'a Value;
pub fn LLVMRustBuildCall(
B: &Builder<'a>,
Fn: &'a Value,
PreservedSymbols: *const *const c_char,
PreservedSymbolsLen: c_uint,
) -> Option<&'static mut ThinLTOData>;
- pub fn LLVMRustPrepareThinLTORename(Data: &ThinLTOData, Module: &Module) -> bool;
+ pub fn LLVMRustPrepareThinLTORename(
+ Data: &ThinLTOData,
+ Module: &Module,
+ Target: &TargetMachine,
+ ) -> bool;
pub fn LLVMRustPrepareThinLTOResolveWeak(Data: &ThinLTOData, Module: &Module) -> bool;
pub fn LLVMRustPrepareThinLTOInternalize(Data: &ThinLTOData, Module: &Module) -> bool;
- pub fn LLVMRustPrepareThinLTOImport(Data: &ThinLTOData, Module: &Module) -> bool;
+ pub fn LLVMRustPrepareThinLTOImport(
+ Data: &ThinLTOData,
+ Module: &Module,
+ Target: &TargetMachine,
+ ) -> bool;
pub fn LLVMRustGetThinLTOModuleImports(
Data: *const ThinLTOData,
ModuleNameCallback: ThinLTOModuleNameCallback,
("vfp2", Some(sym::arm_target_feature)),
("vfp3", Some(sym::arm_target_feature)),
("vfp4", Some(sym::arm_target_feature)),
+ // This is needed for inline assembly, but shouldn't be stabilized as-is
+ // since it should be enabled per-function using #[instruction_set], not
+ // #[target_feature].
+ ("thumb-mode", Some(sym::arm_target_feature)),
];
const AARCH64_WHITELIST: &[(&str, Option<Symbol>)] = &[
write!(&mut name, "::{}", def.variants[index].ident).unwrap();
}
}
- if let (&ty::Generator(_, substs, _), &Variants::Single { index })
+ if let (&ty::Generator(_, _, _), &Variants::Single { index })
= (&layout.ty.kind, &layout.variants)
{
- write!(&mut name, "::{}", substs.as_generator().variant_name(index)).unwrap();
+ write!(&mut name, "::{}", ty::GeneratorSubsts::variant_name(index)).unwrap();
}
Some(name)
}
use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib};
use rustc_middle::middle::dependency_format::Linkage;
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo};
-use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, Sanitizer};
+use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SanitizerSet};
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
use rustc_session::search_paths::PathKind;
use rustc_session::utils::NativeLibKind;
// The third parameter is for env vars, used on windows to set up the
// path for MSVC to find its DLLs, and gcc to find its bundled
// toolchain
-fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> Command {
+fn get_linker(
+ sess: &Session,
+ linker: &Path,
+ flavor: LinkerFlavor,
+ self_contained: bool,
+) -> Command {
let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe");
// If our linker looks like a batch script on Windows then to execute this
// The compiler's sysroot often has some bundled tools, so add it to the
// PATH for the child.
- let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths();
+ let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(self_contained);
let mut msvc_changed_path = false;
if sess.target.target.options.is_like_msvc {
if let Some(ref tool) = msvc_tool {
"Linker does not support -static-pie command line option. Retrying with -static instead."
);
// Mirror `add_(pre,post)_link_objects` to replace CRT objects.
- let fallback = crt_objects_fallback(sess, crate_type);
+ let self_contained = crt_objects_fallback(sess, crate_type);
let opts = &sess.target.target.options;
- let pre_objects =
- if fallback { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
- let post_objects =
- if fallback { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
+ let pre_objects = if self_contained {
+ &opts.pre_link_objects_fallback
+ } else {
+ &opts.pre_link_objects
+ };
+ let post_objects = if self_contained {
+ &opts.post_link_objects_fallback
+ } else {
+ &opts.post_link_objects
+ };
let get_objects = |objects: &CrtObjects, kind| {
objects
.get(&kind)
.iter()
.copied()
.flatten()
- .map(|obj| get_object_file_path(sess, obj).into_os_string())
+ .map(|obj| get_object_file_path(sess, obj, self_contained).into_os_string())
.collect::<Vec<_>>()
};
let pre_objects_static_pie = get_objects(pre_objects, LinkOutputKind::StaticPicExe);
}
}
-fn link_sanitizer_runtime(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
- let sanitizer = match &sess.opts.debugging_opts.sanitizer {
- Some(s) => s,
- None => return,
- };
-
+fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
if crate_type != CrateType::Executable {
return;
}
+ let sanitizer = sess.opts.debugging_opts.sanitizer;
+ if sanitizer.contains(SanitizerSet::ADDRESS) {
+ link_sanitizer_runtime(sess, linker, "asan");
+ }
+ if sanitizer.contains(SanitizerSet::LEAK) {
+ link_sanitizer_runtime(sess, linker, "lsan");
+ }
+ if sanitizer.contains(SanitizerSet::MEMORY) {
+ link_sanitizer_runtime(sess, linker, "msan");
+ }
+ if sanitizer.contains(SanitizerSet::THREAD) {
+ link_sanitizer_runtime(sess, linker, "tsan");
+ }
+}
- let name = match sanitizer {
- Sanitizer::Address => "asan",
- Sanitizer::Leak => "lsan",
- Sanitizer::Memory => "msan",
- Sanitizer::Thread => "tsan",
- };
-
+fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
let default_sysroot = filesearch::get_or_default_sysroot();
let default_tlib =
filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.triple());
linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
linker.link_dylib(Symbol::intern(&libname));
}
- "x86_64-unknown-linux-gnu" | "x86_64-fuchsia" | "aarch64-fuchsia" => {
+ "aarch64-fuchsia"
+ | "aarch64-unknown-linux-gnu"
+ | "x86_64-fuchsia"
+ | "x86_64-unknown-linux-gnu" => {
let filename = format!("librustc{}_rt.{}.a", channel, name);
let path = default_tlib.join(&filename);
linker.link_whole_rlib(&path);
}
}
-fn get_object_file_path(sess: &Session, name: &str) -> PathBuf {
+fn get_object_file_path(sess: &Session, name: &str, self_contained: bool) -> PathBuf {
// prefer system {,dll}crt2.o libs, see get_crt_libs_path comment for more details
- if sess.target.target.llvm_target.contains("windows-gnu") {
+ if sess.opts.debugging_opts.link_self_contained.is_none()
+ && sess.target.target.llvm_target.contains("windows-gnu")
+ {
if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
let file_path = compiler_libs_path.join(name);
if file_path.exists() {
if file_path.exists() {
return file_path;
}
+ // Special directory with objects used only in self-contained linkage mode
+ if self_contained {
+ let file_path = fs.get_self_contained_lib_path().join(name);
+ if file_path.exists() {
+ return file_path;
+ }
+ }
for search_path in fs.search_paths() {
let file_path = search_path.dir.join(name);
if file_path.exists() {
/// Whether we link to our own CRT objects instead of relying on gcc to pull them.
/// We only provide such support for a very limited number of targets.
fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool {
+ if let Some(self_contained) = sess.opts.debugging_opts.link_self_contained {
+ return self_contained;
+ }
+
match sess.target.target.options.crt_objects_fallback {
// FIXME: Find a better heuristic for "native musl toolchain is available",
// based on host and linker path, for example.
cmd: &mut dyn Linker,
sess: &Session,
link_output_kind: LinkOutputKind,
- fallback: bool,
+ self_contained: bool,
) {
let opts = &sess.target.target.options;
- let objects = if fallback { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
+ let objects =
+ if self_contained { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
for obj in objects.get(&link_output_kind).iter().copied().flatten() {
- cmd.add_object(&get_object_file_path(sess, obj));
+ cmd.add_object(&get_object_file_path(sess, obj, self_contained));
}
}
cmd: &mut dyn Linker,
sess: &Session,
link_output_kind: LinkOutputKind,
- fallback: bool,
+ self_contained: bool,
) {
let opts = &sess.target.target.options;
- let objects = if fallback { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
+ let objects =
+ if self_contained { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
for obj in objects.get(&link_output_kind).iter().copied().flatten() {
- cmd.add_object(&get_object_file_path(sess, obj));
+ cmd.add_object(&get_object_file_path(sess, obj, self_contained));
}
}
}
/// Add sysroot and other globally set directories to the directory search list.
-fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session) {
+fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) {
// Prefer system mingw-w64 libs, see get_crt_libs_path comment for more details.
- if cfg!(windows) && sess.target.target.llvm_target.contains("windows-gnu") {
+ if sess.opts.debugging_opts.link_self_contained.is_none()
+ && cfg!(windows)
+ && sess.target.target.llvm_target.contains("windows-gnu")
+ {
if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
cmd.include_path(&compiler_libs_path);
}
// The location of crates will be determined as needed.
let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
+
+ // Special directory with libraries used only in self-contained linkage mode
+ if self_contained {
+ let lib_path = sess.target_filesearch(PathKind::All).get_self_contained_lib_path();
+ cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
+ }
}
/// Add options making relocation sections in the produced ELF files read-only
codegen_results: &CodegenResults,
target_cpu: &str,
) -> Command {
- let base_cmd = get_linker(sess, path, flavor);
+ let crt_objects_fallback = crt_objects_fallback(sess, crate_type);
+ let base_cmd = get_linker(sess, path, flavor, crt_objects_fallback);
// FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
// to the linker args construction.
assert!(base_cmd.get_args().is_empty() || sess.target.target.target_vendor == "uwp");
let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor, target_cpu);
let link_output_kind = link_output_kind(sess, crate_type);
- let crt_objects_fallback = crt_objects_fallback(sess, crate_type);
// NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
add_pre_link_args(cmd, sess, flavor);
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
if sess.target.target.options.is_like_fuchsia && crate_type == CrateType::Executable {
- let prefix = match sess.opts.debugging_opts.sanitizer {
- Some(Sanitizer::Address) => "asan/",
- _ => "",
+ let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
+ "asan/"
+ } else {
+ ""
};
cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix));
}
}
// OBJECT-FILES-YES, AUDIT-ORDER
- link_sanitizer_runtime(sess, crate_type, cmd);
+ link_sanitizers(sess, crate_type, cmd);
// OBJECT-FILES-NO, AUDIT-ORDER
// Linker plugins should be specified early in the list of arguments
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
// FIXME: Order-dependent, at least relatively to other args adding searh directories.
- add_library_search_dirs(cmd, sess);
+ add_library_search_dirs(cmd, sess, crt_objects_fallback);
// OBJECT-FILES-YES
add_local_crate_regular_objects(cmd, codegen_results);
use super::archive;
use super::command::Command;
use super::symbol_export;
+use rustc_span::symbol::sym;
use std::ffi::{OsStr, OsString};
use std::fs::{self, File};
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
match output_kind {
LinkOutputKind::DynamicNoPicExe => {
- if !self.is_ld {
+ if !self.is_ld && self.sess.target.target.options.linker_is_gnu {
self.cmd.arg("-no-pie");
}
}
LinkOutputKind::StaticNoPicExe => {
// `-static` works for both gcc wrapper and ld.
self.cmd.arg("-static");
- if !self.is_ld {
+ if !self.is_ld && self.sess.target.target.options.linker_is_gnu {
self.cmd.arg("-no-pie");
}
}
}
fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
- // not supported?
self.link_staticlib(lib);
+ self.cmd.arg(format!("/WHOLEARCHIVE:{}.lib", lib));
}
fn link_whole_rlib(&mut self, path: &Path) {
- // not supported?
self.link_rlib(path);
+ let mut arg = OsString::from("/WHOLEARCHIVE:");
+ arg.push(path);
+ self.cmd.arg(arg);
}
fn optimize(&mut self) {
// Needs more investigation of `/OPT` arguments
//
// * `--export=*tls*` - when `#[thread_local]` symbols are used these
// symbols are how the TLS segments are initialized and configured.
- let atomics = sess.opts.cg.target_feature.contains("+atomics")
- || sess.target.target.options.features.contains("+atomics");
- if atomics {
+ if sess.target_features.contains(&sym::atomics) {
cmd.arg("--shared-memory");
cmd.arg("--max-memory=1073741824");
cmd.arg("--import-memory");
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::Instance;
use rustc_middle::ty::{SymbolName, TyCtxt};
-use rustc_session::config::{CrateType, Sanitizer};
+use rustc_session::config::{CrateType, SanitizerSet};
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
crates_export_threshold(&tcx.sess.crate_types())
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
let def_id = tcx.hir().local_def_id(hir_id);
let generics = tcx.generics_of(def_id);
- if !generics.requires_monomorphization(tcx) &&
- // Functions marked with #[inline] are only ever codegened
- // with "internal" linkage and are never exported.
- !Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx)
+ if !generics.requires_monomorphization(tcx)
+ // Functions marked with #[inline] are codegened with "internal"
+ // linkage and are not exported unless marked with an extern
+ // inidicator
+ && (!Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx)
+ || tcx.codegen_fn_attrs(def_id.to_def_id()).contains_extern_indicator())
{
Some(def_id)
} else {
}));
}
- if let Some(Sanitizer::Memory) = tcx.sess.opts.debugging_opts.sanitizer {
+ if tcx.sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::MEMORY) {
// Similar to profiling, preserve weak msan symbol during LTO.
const MSAN_WEAK_SYMBOLS: [&str; 2] = ["__msan_track_origins", "__msan_keep_going"];
use rustc_middle::ty::TyCtxt;
use rustc_session::cgu_reuse_tracker::CguReuseTracker;
use rustc_session::config::{self, CrateType, Lto, OutputFilenames, OutputType};
-use rustc_session::config::{Passes, Sanitizer, SwitchWithOptPath};
+use rustc_session::config::{Passes, SanitizerSet, SwitchWithOptPath};
use rustc_session::Session;
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{sym, Symbol};
pub pgo_gen: SwitchWithOptPath,
pub pgo_use: Option<PathBuf>,
- pub sanitizer: Option<Sanitizer>,
- pub sanitizer_recover: Vec<Sanitizer>,
+ pub sanitizer: SanitizerSet,
+ pub sanitizer_recover: SanitizerSet,
pub sanitizer_memory_track_origins: usize,
// Flags indicating which outputs to produce.
if sess.opts.debugging_opts.profile && !is_compiler_builtins {
passes.push("insert-gcov-profiling".to_owned());
}
+
+ // The rustc option `-Zinstrument_coverage` injects intrinsic calls to
+ // `llvm.instrprof.increment()`, which requires the LLVM `instrprof` pass.
+ if sess.opts.debugging_opts.instrument_coverage {
+ passes.push("instrprof".to_owned());
+ }
passes
},
vec![]
),
pgo_use: if_regular!(sess.opts.cg.profile_use.clone(), None),
- sanitizer: if_regular!(sess.opts.debugging_opts.sanitizer.clone(), None),
+ sanitizer: if_regular!(sess.opts.debugging_opts.sanitizer, SanitizerSet::empty()),
sanitizer_recover: if_regular!(
- sess.opts.debugging_opts.sanitizer_recover.clone(),
- vec![]
+ sess.opts.debugging_opts.sanitizer_recover,
+ SanitizerSet::empty()
),
sanitizer_memory_track_origins: if_regular!(
sess.opts.debugging_opts.sanitizer_memory_track_origins,
Metadata,
X86_MMX,
Token,
+ ScalableVector,
+ BFloat,
}
// FIXME(mw): Anything that is produced via DepGraph::with_task() must implement
tcx.def_key(def_id).disambiguated_data.disambiguator
));
}
- ty::Error
+ ty::Error(_)
| ty::Infer(_)
| ty::Placeholder(..)
| ty::Projection(..)
self.visit_rvalue(rvalue, location);
}
- fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location: Location) {
- let check = match *kind {
+ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
+ let check = match terminator.kind {
mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. } => {
match c.literal.ty.kind {
ty::FnDef(did, _) => Some((did, args)),
}
}
- self.super_terminator_kind(kind, location);
+ self.super_terminator(terminator, location);
}
fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
targets: &Vec<mir::BasicBlock>,
) {
let discr = self.codegen_operand(&mut bx, &discr);
+ // `switch_ty` is redundant, sanity-check that.
+ assert_eq!(discr.layout.ty, switch_ty);
if targets.len() == 2 {
// If there are two targets, emit br instead of switch
let lltrue = helper.llblock(self, targets[0]);
// checked operation, just a comparison with the minimum
// value, so we have to check for the assert message.
if !bx.check_overflow() {
- if let AssertKind::OverflowNeg = *msg {
+ if let AssertKind::OverflowNeg(_) = *msg {
const_cond = Some(expected);
}
}
&args,
dest,
terminator.source_info.span,
+ self.instance,
);
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
bx.unreachable();
}
- mir::TerminatorKind::Drop { location, target, unwind } => {
- self.codegen_drop_terminator(helper, bx, location, target, unwind);
+ mir::TerminatorKind::Drop { place, target, unwind } => {
+ self.codegen_drop_terminator(helper, bx, place, target, unwind);
}
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => {
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
use rustc_middle::ty::{self, Ty};
-use rustc_target::abi::{Abi, Align, DiscriminantKind, FieldsShape, Int};
+use rustc_target::abi::{Abi, Align, FieldsShape, Int, TagEncoding};
use rustc_target::abi::{LayoutOf, VariantIdx, Variants};
#[derive(Copy, Clone, Debug)]
if self.layout.abi.is_uninhabited() {
return bx.cx().const_undef(cast_to);
}
- let (discr_scalar, discr_kind, discr_index) = match self.layout.variants {
+ let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants {
Variants::Single { index } => {
let discr_val = self
.layout
.map_or(index.as_u32() as u128, |discr| discr.val);
return bx.cx().const_uint_big(cast_to, discr_val);
}
- Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => {
- (discr, discr_kind, discr_index)
+ Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => {
+ (tag, tag_encoding, tag_field)
}
};
// Read the tag/niche-encoded discriminant from memory.
- let encoded_discr = self.project_field(bx, discr_index);
- let encoded_discr = bx.load_operand(encoded_discr);
+ let tag = self.project_field(bx, tag_field);
+ let tag = bx.load_operand(tag);
// Decode the discriminant (specifically if it's niche-encoded).
- match *discr_kind {
- DiscriminantKind::Tag => {
- let signed = match discr_scalar.value {
+ match *tag_encoding {
+ TagEncoding::Direct => {
+ let signed = match tag_scalar.value {
// We use `i1` for bytes that are always `0` or `1`,
// e.g., `#[repr(i8)] enum E { A, B }`, but we can't
// let LLVM interpret the `i1` as signed, because
// then `i1 1` (i.e., `E::B`) is effectively `i8 -1`.
- Int(_, signed) => !discr_scalar.is_bool() && signed,
+ Int(_, signed) => !tag_scalar.is_bool() && signed,
_ => false,
};
- bx.intcast(encoded_discr.immediate(), cast_to, signed)
+ bx.intcast(tag.immediate(), cast_to, signed)
}
- DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => {
+ TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
// Rebase from niche values to discriminants, and check
// whether the result is in range for the niche variants.
- let niche_llty = bx.cx().immediate_backend_type(encoded_discr.layout);
- let encoded_discr = encoded_discr.immediate();
+ let niche_llty = bx.cx().immediate_backend_type(tag.layout);
+ let tag = tag.immediate();
// We first compute the "relative discriminant" (wrt `niche_variants`),
// that is, if `n = niche_variants.end() - niche_variants.start()`,
let relative_discr = if niche_start == 0 {
// Avoid subtracting `0`, which wouldn't work for pointers.
// FIXME(eddyb) check the actual primitive type here.
- encoded_discr
+ tag
} else {
- bx.sub(encoded_discr, bx.cx().const_uint_big(niche_llty, niche_start))
+ bx.sub(tag, bx.cx().const_uint_big(niche_llty, niche_start))
};
let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
let is_niche = {
Variants::Single { index } => {
assert_eq!(index, variant_index);
}
- Variants::Multiple { discr_kind: DiscriminantKind::Tag, discr_index, .. } => {
- let ptr = self.project_field(bx, discr_index);
+ Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => {
+ let ptr = self.project_field(bx, tag_field);
let to =
self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val;
bx.store(
);
}
Variants::Multiple {
- discr_kind:
- DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start },
- discr_index,
+ tag_encoding:
+ TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
+ tag_field,
..
} => {
if variant_index != dataful_variant {
bx.memset(self.llval, fill_byte, size, self.align, MemFlags::empty());
}
- let niche = self.project_field(bx, discr_index);
+ let niche = self.project_field(bx, tag_field);
let niche_llty = bx.cx().immediate_backend_type(niche.layout);
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
let niche_value = (niche_value as u128).wrapping_add(niche_start);
/// Called for `StorageDead`
fn lifetime_end(&mut self, ptr: Self::Value, size: Size);
+ fn instrprof_increment(
+ &mut self,
+ fn_name: Self::Value,
+ hash: Self::Value,
+ num_counters: Self::Value,
+ index: Self::Value,
+ ) -> Self::Value;
+
fn call(
&mut self,
llfn: Self::Value,
args: &[OperandRef<'tcx, Self::Value>],
llresult: Self::Value,
span: Span,
+ caller_instance: ty::Instance<'tcx>,
);
fn abort(&mut self);
}
fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
- ty.is_freeze(self.tcx(), ty::ParamEnv::reveal_all(), DUMMY_SP)
+ ty.is_freeze(self.tcx().at(DUMMY_SP), ty::ParamEnv::reveal_all())
}
fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
stable_deref_trait = "1.0.0"
rayon = { version = "0.3.0", package = "rustc-rayon" }
rayon-core = { version = "0.3.0", package = "rustc-rayon-core" }
-rustc-hash = "1.0.1"
+rustc-hash = "1.1.0"
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
rustc_index = { path = "../librustc_index", package = "rustc_index" }
bitflags = "1.2.1"
use parking_lot::Mutex as InnerLock;
use parking_lot::RwLock as InnerRwLock;
- use std;
use std::thread;
pub use rayon::{join, scope};
compiler.output_file().as_ref().map(|p| &**p),
);
}
+ trace!("finished pretty-printing");
return early_exit();
}
E0753: include_str!("./error_codes/E0753.md"),
E0754: include_str!("./error_codes/E0754.md"),
E0758: include_str!("./error_codes/E0758.md"),
+E0759: include_str!("./error_codes/E0759.md"),
E0760: include_str!("./error_codes/E0760.md"),
E0761: include_str!("./error_codes/E0761.md"),
E0762: include_str!("./error_codes/E0762.md"),
+E0763: include_str!("./error_codes/E0763.md"),
+E0764: include_str!("./error_codes/E0764.md"),
+E0765: include_str!("./error_codes/E0765.md"),
+E0766: include_str!("./error_codes/E0766.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
-A discrimant value is present more than once.
+A discriminant value is present more than once.
Erroneous code example:
Malformed inline assembly rejected by LLVM.
-LLVM checks the validity of the constraints and the assembly string passed to
-it. This error implies that LLVM seems something wrong with the inline
-assembly call.
+Erroneous code example:
-In particular, it can happen if you forgot the closing bracket of a register
-constraint (see issue #51430):
```compile_fail,E0668
#![feature(llvm_asm)]
}
}
```
+
+LLVM checks the validity of the constraints and the assembly string passed to
+it. This error implies that LLVM seems something wrong with the inline
+assembly call.
+
+In particular, it can happen if you forgot the closing bracket of a register
+constraint (see issue #51430), like in the previous code example.
Rust 2015 does not permit the use of `async fn`.
-Example of erroneous code:
+Erroneous code example:
```compile_fail,E0670
async fn foo() {}
-This error indicates that the numeric value for the method being passed exists
-but the type of the numeric value or binding could not be identified.
+A method was called on an ambiguous numeric type.
-The error happens on numeric literals:
+Erroneous code example:
```compile_fail,E0689
-2.0.neg();
+2.0.neg(); // error!
```
-and on numeric bindings without an identified concrete type:
+This error indicates that the numeric value for the method being passed exists
+but the type of the numeric value or binding could not be identified.
+
+The error happens on numeric literals and on numeric bindings without an
+identified concrete type:
```compile_fail,E0689
let x = 2.0;
```
use std::ops::Neg;
-let _ = 2.0_f32.neg();
+let _ = 2.0_f32.neg(); // ok!
let x: f32 = 2.0;
-let _ = x.neg();
-let _ = (2.0 as f32).neg();
+let _ = x.neg(); // ok!
+let _ = (2.0 as f32).neg(); // ok!
```
A `break` statement without a label appeared inside a labeled block.
-Example of erroneous code:
+Erroneous code example:
```compile_fail,E0695
# #![feature(label_break_value)]
A method was called on a raw pointer whose inner type wasn't completely known.
-For example, you may have done something like:
+Erroneous code example:
-```compile_fail
+```compile_fail,edition2018,E0699
# #![deny(warnings)]
+# fn main() {
let foo = &1;
let bar = foo as *const _;
if bar.is_null() {
// ...
}
+# }
```
Here, the type of `bar` isn't known; it could be a pointer to anything. Instead,
This error indicates that a `#[non_exhaustive]` attribute was incorrectly placed
on something other than a struct or enum.
-Examples of erroneous code:
+Erroneous code example:
```compile_fail,E0701
#[non_exhaustive]
--- /dev/null
+A `'static` requirement in a return type involving a trait is not fulfilled.
+
+Erroneous code examples:
+
+```compile_fail,E0759
+use std::fmt::Debug;
+
+fn foo(x: &i32) -> impl Debug {
+ x
+}
+```
+
+```compile_fail,E0759
+# use std::fmt::Debug;
+fn bar(x: &i32) -> Box<dyn Debug> {
+ Box::new(x)
+}
+```
+
+These examples have the same semantics as the following:
+
+```compile_fail,E0759
+# use std::fmt::Debug;
+fn foo(x: &i32) -> impl Debug + 'static {
+ x
+}
+```
+
+```compile_fail,E0759
+# use std::fmt::Debug;
+fn bar(x: &i32) -> Box<dyn Debug + 'static> {
+ Box::new(x)
+}
+```
+
+Both [`dyn Trait`] and [`impl Trait`] in return types have a an implicit
+`'static` requirement, meaning that the value implementing them that is being
+returned has to be either a `'static` borrow or an owned value.
+
+In order to change the requirement from `'static` to be a lifetime derived from
+its arguments, you can add an explicit bound, either to an anonymous lifetime
+`'_` or some appropriate named lifetime.
+
+```
+# use std::fmt::Debug;
+fn foo(x: &i32) -> impl Debug + '_ {
+ x
+}
+fn bar(x: &i32) -> Box<dyn Debug + '_> {
+ Box::new(x)
+}
+```
+
+These are equivalent to the following explicit lifetime annotations:
+
+```
+# use std::fmt::Debug;
+fn foo<'a>(x: &'a i32) -> impl Debug + 'a {
+ x
+}
+fn bar<'a>(x: &'a i32) -> Box<dyn Debug + 'a> {
+ Box::new(x)
+}
+```
+
+[`dyn Trait`]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types
+[`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits
--- /dev/null
+A byte constant wasn't correctly ended.
+
+Erroneous code example:
+
+```compile_fail,E0763
+let c = b'a; // error!
+```
+
+To fix this error, add the missing quote:
+
+```
+let c = b'a'; // ok!
+```
--- /dev/null
+Mutable references (`&mut`) can only be used in constant functions, not statics
+or constants. This limitation exists to prevent the creation of constants that
+have a mutable reference in their final value. If you had a constant of `&mut
+i32` type, you could modify the value through that reference, making the
+constant essentially mutable. While there could be a more fine-grained scheme
+in the future that allows mutable references if they are not "leaked" to the
+final value, a more conservative approach was chosen for now. `const fn` do not
+have this problem, as the borrow checker will prevent the `const fn` from
+returning new mutable references.
+
+Erroneous code example:
+
+```compile_fail,E0764
+#![feature(const_fn)]
+#![feature(const_mut_refs)]
+
+fn main() {
+ const OH_NO: &'static mut usize = &mut 1; // error!
+}
+```
+
+Remember: you cannot use a function call inside a constant or static. However,
+you can totally use it in constant functions:
+
+```
+#![feature(const_fn)]
+#![feature(const_mut_refs)]
+
+const fn foo(x: usize) -> usize {
+ let mut y = 1;
+ let z = &mut y;
+ *z += x;
+ y
+}
+
+fn main() {
+ const FOO: usize = foo(10); // ok!
+}
+```
--- /dev/null
+A double quote string (`"`) was not terminated.
+
+Erroneous code example:
+
+```compile_fail,E0765
+let s = "; // error!
+```
+
+To fix this error, add the missing double quote at the end of the string:
+
+```
+let s = ""; // ok!
+```
--- /dev/null
+A double quote byte string (`b"`) was not terminated.
+
+Erroneous code example:
+
+```compile_fail,E0766
+let s = b"; // error!
+```
+
+To fix this error, add the missing double quote at the end of the string:
+
+```
+let s = b""; // ok!
+```
use termcolor::{Ansi, BufferWriter, ColorChoice, ColorSpec, StandardStream};
use termcolor::{Buffer, Color, WriteColor};
+/// Default column width, used in tests and when terminal dimensions cannot be determined.
+const DEFAULT_COLUMN_WIDTH: usize = 140;
+
/// Describes the way the content of the `rendered` field of the json output is generated
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum HumanReadableErrorType {
pub computed_left: usize,
/// The end of the line to be displayed.
pub computed_right: usize,
- /// The current width of the terminal. 140 by default and in tests.
+ /// The current width of the terminal. Uses value of `DEFAULT_COLUMN_WIDTH` constant by default
+ /// and in tests.
pub column_width: usize,
/// The end column of a span label, including the span. Doesn't account for labels not in the
/// same line as the span.
let column_width = if let Some(width) = self.terminal_width {
width.saturating_sub(code_offset)
} else if self.ui_testing {
- 140
+ DEFAULT_COLUMN_WIDTH
} else {
termize::dimensions()
.map(|(w, _)| w.saturating_sub(code_offset))
- .unwrap_or(usize::MAX)
+ .unwrap_or(DEFAULT_COLUMN_WIDTH)
};
let margin = Margin::new(
pretty: bool,
ui_testing: bool,
json_rendered: HumanReadableErrorType,
+ terminal_width: Option<usize>,
macro_backtrace: bool,
}
source_map: Lrc<SourceMap>,
pretty: bool,
json_rendered: HumanReadableErrorType,
+ terminal_width: Option<usize>,
macro_backtrace: bool,
) -> JsonEmitter {
JsonEmitter {
pretty,
ui_testing: false,
json_rendered,
+ terminal_width,
macro_backtrace,
}
}
pub fn basic(
pretty: bool,
json_rendered: HumanReadableErrorType,
+ terminal_width: Option<usize>,
macro_backtrace: bool,
) -> JsonEmitter {
let file_path_mapping = FilePathMapping::empty();
Lrc::new(SourceMap::new(file_path_mapping)),
pretty,
json_rendered,
+ terminal_width,
macro_backtrace,
)
}
source_map: Lrc<SourceMap>,
pretty: bool,
json_rendered: HumanReadableErrorType,
+ terminal_width: Option<usize>,
macro_backtrace: bool,
) -> JsonEmitter {
JsonEmitter {
pretty,
ui_testing: false,
json_rendered,
+ terminal_width,
macro_backtrace,
}
}
let buf = BufWriter::default();
let output = buf.clone();
je.json_rendered
- .new_emitter(Box::new(buf), Some(je.sm.clone()), false, None, je.macro_backtrace)
+ .new_emitter(
+ Box::new(buf),
+ Some(je.sm.clone()),
+ false,
+ je.terminal_width,
+ je.macro_backtrace,
+ )
.ui_testing(je.ui_testing)
.emit_diagnostic(diag);
let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(crate_visibility_modifier)]
#![feature(nll)]
+#![feature(track_caller)]
pub use emitter::ColorConfig;
self.inner.borrow_mut().span_bug(span, msg)
}
+ #[track_caller]
pub fn delay_span_bug(&self, span: impl Into<MultiSpan>, msg: &str) {
self.inner.borrow_mut().delay_span_bug(span, msg)
}
self.emit_diagnostic(diag.set_span(sp));
}
+ #[track_caller]
fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) {
// This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
// incrementing `err_count` by one, so we need to +1 the comparing.
}
let mut diagnostic = Diagnostic::new(Level::Bug, msg);
diagnostic.set_span(sp.into());
+ diagnostic.note(&format!("delayed at {}", std::panic::Location::caller()));
self.delay_as_bug(diagnostic)
}
use rustc_ast::ast::{self, Attribute, NodeId, PatKind};
use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_ast::ptr::P;
-use rustc_ast::token;
+use rustc_ast::token::{self, FlattenGroup};
use rustc_ast::tokenstream::{self, TokenStream, TokenTree};
use rustc_ast::visit::{AssocCtxt, Visitor};
use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability};
| Annotatable::StructField(..)
| Annotatable::Variant(..) => panic!("unexpected annotatable"),
};
- TokenTree::token(token::Interpolated(Lrc::new(nt)), DUMMY_SP).into()
+ TokenTree::token(token::Interpolated(Lrc::new(nt), FlattenGroup::Yes), DUMMY_SP).into()
}
pub fn expect_item(self) -> P<ast::Item> {
impl MutVisitor for AvoidInterpolatedIdents {
fn visit_tt(&mut self, tt: &mut tokenstream::TokenTree) {
if let tokenstream::TokenTree::Token(token) = tt {
- if let token::Interpolated(nt) = &token.kind {
+ if let token::Interpolated(nt, _) = &token.kind {
if let token::NtIdent(ident, is_raw) = **nt {
*tt = tokenstream::TokenTree::token(
token::Ident(ident.name, is_raw),
/// Error type that denotes indeterminacy.
pub struct Indeterminate;
-pub trait Resolver {
+pub trait ResolverExpand {
fn next_node_id(&mut self) -> NodeId;
fn resolve_dollar_crates(&mut self);
pub ecfg: expand::ExpansionConfig<'a>,
pub reduced_recursion_limit: Option<Limit>,
pub root_path: PathBuf,
- pub resolver: &'a mut dyn Resolver,
+ pub resolver: &'a mut dyn ResolverExpand,
pub current_expansion: ExpansionData,
pub expansions: FxHashMap<Span, Vec<String>>,
/// Called directly after having parsed an external `mod foo;` in expansion.
pub fn new(
parse_sess: &'a ParseSess,
ecfg: expand::ExpansionConfig<'a>,
- resolver: &'a mut dyn Resolver,
+ resolver: &'a mut dyn ResolverExpand,
extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>,
) -> ExtCtxt<'a> {
ExtCtxt {
sym::literal => token.can_begin_literal_maybe_minus(),
sym::vis => match token.kind {
// The follow-set of :vis + "priv" keyword + interpolated
- token::Comma | token::Ident(..) | token::Interpolated(_) => true,
+ token::Comma | token::Ident(..) | token::Interpolated(..) => true,
_ => token.can_begin_type(),
},
sym::block => match token.kind {
token::OpenDelim(token::Brace) => true,
- token::Interpolated(ref nt) => match **nt {
+ token::Interpolated(ref nt, _) => match **nt {
token::NtItem(_)
| token::NtPat(_)
| token::NtTy(_)
},
sym::path | sym::meta => match token.kind {
token::ModSep | token::Ident(..) => true,
- token::Interpolated(ref nt) => match **nt {
+ token::Interpolated(ref nt, _) => match **nt {
token::NtPath(_) | token::NtMeta(_) => true,
_ => may_be_ident(&nt),
},
token::ModSep | // path
token::Lt | // path (UFCS constant)
token::BinOp(token::Shl) => true, // path (double UFCS)
- token::Interpolated(ref nt) => may_be_ident(nt),
+ token::Interpolated(ref nt, _) => may_be_ident(nt),
_ => false,
},
sym::lifetime => match token.kind {
token::Lifetime(_) => true,
- token::Interpolated(ref nt) => match **nt {
+ token::Interpolated(ref nt, _) => match **nt {
token::NtLifetime(_) | token::NtTT(_) => true,
_ => false,
},
}
fn parse_nt_inner<'a>(p: &mut Parser<'a>, sp: Span, name: Symbol) -> PResult<'a, Nonterminal> {
+ // Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`)
+ // needs to have them force-captured here.
+ // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
+ // which requires having captured tokens available. Since we cannot determine
+ // in advance whether or not a proc-macro will be (transitively) invoked,
+ // we always capture tokens for any `Nonterminal` which needs them.
Ok(match name {
- sym::item => match p.parse_item()? {
- Some(i) => token::NtItem(i),
- None => return Err(p.struct_span_err(p.token.span, "expected an item keyword")),
+ sym::item => match p.collect_tokens(|this| this.parse_item())? {
+ (Some(mut item), tokens) => {
+ // If we captured tokens during parsing (due to outer attributes),
+ // use those.
+ if item.tokens.is_none() {
+ item.tokens = Some(tokens);
+ }
+ token::NtItem(item)
+ }
+ (None, _) => return Err(p.struct_span_err(p.token.span, "expected an item keyword")),
},
sym::block => token::NtBlock(p.parse_block()?),
sym::stmt => match p.parse_stmt()? {
None => return Err(p.struct_span_err(p.token.span, "expected a statement")),
},
sym::pat => token::NtPat(p.parse_pat(None)?),
- sym::expr => token::NtExpr(p.parse_expr()?),
+ sym::expr => {
+ let (mut expr, tokens) = p.collect_tokens(|this| this.parse_expr())?;
+ // If we captured tokens during parsing (due to outer attributes),
+ // use those.
+ if expr.tokens.is_none() {
+ expr.tokens = Some(tokens);
+ }
+ token::NtExpr(expr)
+ }
sym::literal => token::NtLiteral(p.parse_literal_maybe_minus()?),
sym::ty => token::NtTy(p.parse_ty()?),
// this could be handled like a token, since it is one
use rustc_ast::ast::MacCall;
use rustc_ast::mut_visit::{self, MutVisitor};
-use rustc_ast::token::{self, NtTT, Token};
+use rustc_ast::token::{self, FlattenGroup, NtTT, Token};
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
result.push(tt.clone().into());
} else {
marker.visit_span(&mut sp);
- let token = TokenTree::token(token::Interpolated(nt.clone()), sp);
+ let token = TokenTree::token(
+ token::Interpolated(nt.clone(), FlattenGroup::No),
+ sp,
+ );
result.push(token.into());
}
} else {
use crate::proc_macro_server;
use rustc_ast::ast::{self, ItemKind, MetaItemKind, NestedMetaItem};
-use rustc_ast::token;
+use rustc_ast::token::{self, FlattenGroup};
use rustc_ast::tokenstream::{self, TokenStream};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, ErrorReported};
}
}
- let token = token::Interpolated(Lrc::new(token::NtItem(item)));
+ let token = token::Interpolated(Lrc::new(token::NtItem(item)), FlattenGroup::Yes);
let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
let server = proc_macro_server::Rustc::new(ecx);
use crate::base::ExtCtxt;
use rustc_ast::ast;
-use rustc_ast::token;
+use rustc_ast::token::{self, FlattenGroup};
use rustc_ast::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
use rustc_ast::util::comments;
use rustc_ast_pretty::pprust;
let Token { kind, span } = match tree {
tokenstream::TokenTree::Delimited(span, delim, tts) => {
let delimiter = Delimiter::from_internal(delim);
- return TokenTree::Group(Group { delimiter, stream: tts, span });
+ return TokenTree::Group(Group {
+ delimiter,
+ stream: tts,
+ span,
+ flatten: FlattenGroup::No,
+ });
}
tokenstream::TokenTree::Token(token) => token,
};
delimiter: Delimiter::Bracket,
stream,
span: DelimSpan::from_single(span),
+ flatten: FlattenGroup::No,
}));
if style == ast::AttrStyle::Inner {
stack.push(tt!(Punct::new('!', false)));
tt!(Punct::new('#', false))
}
- Interpolated(nt) => {
+ Interpolated(nt, flatten) => {
let stream = nt_to_tokenstream(&nt, sess, span);
TokenTree::Group(Group {
delimiter: Delimiter::None,
stream,
span: DelimSpan::from_single(span),
+ flatten,
})
}
let (ch, joint, span) = match self {
TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
- TokenTree::Group(Group { delimiter, stream, span }) => {
+ TokenTree::Group(Group { delimiter, stream, span, .. }) => {
return tokenstream::TokenTree::Delimited(span, delimiter.to_internal(), stream)
.into();
}
delimiter: Delimiter,
stream: TokenStream,
span: DelimSpan,
+ /// A hack used to pass AST fragments to attribute and derive macros
+ /// as a single nonterminal token instead of a token stream.
+ /// FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
+ flatten: FlattenGroup,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
let next = iter.cursor.next_with_joint()?;
Some(TokenTree::from_internal((next, self.sess, &mut iter.stack)))
})?;
- // HACK: The condition "dummy span + group with empty delimiter" represents an AST
- // fragment approximately converted into a token stream. This may happen, for
- // example, with inputs to proc macro attributes, including derives. Such "groups"
- // need to flattened during iteration over stream's token trees.
- // Eventually this needs to be removed in favor of keeping original token trees
- // and not doing the roundtrip through AST.
+ // A hack used to pass AST fragments to attribute and derive macros
+ // as a single nonterminal token instead of a token stream.
+ // Such token needs to be "unwrapped" and not represented as a delimited group.
+ // FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
if let TokenTree::Group(ref group) = tree {
- if group.delimiter == Delimiter::None && group.span.entire().is_dummy() {
+ if matches!(group.flatten, FlattenGroup::Yes) {
iter.cursor.append(group.stream.clone());
continue;
}
impl server::Group for Rustc<'_> {
fn new(&mut self, delimiter: Delimiter, stream: Self::TokenStream) -> Self::Group {
- Group { delimiter, stream, span: DelimSpan::from_single(server::Span::call_site(self)) }
+ Group {
+ delimiter,
+ stream,
+ span: DelimSpan::from_single(server::Span::call_site(self)),
+ flatten: FlattenGroup::No,
+ }
}
fn delimiter(&mut self, group: &Self::Group) -> Delimiter {
group.delimiter
(accepted, transparent_enums, "1.42.0", Some(60405), None),
/// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`.
(accepted, slice_patterns, "1.42.0", Some(62254), None),
+ /// Allows the use of `if` and `match` in constants.
+ (accepted, const_if_match, "1.45.0", Some(49146), None),
+ /// Allows the use of `loop` and `while` in constants.
+ (accepted, const_loop, "1.45.0", Some(52000), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features
/// Allows dereferencing raw pointers during const eval.
(active, const_raw_ptr_deref, "1.27.0", Some(51911), None),
- /// Allows comparing raw pointers during const eval.
- (active, const_compare_raw_pointers, "1.27.0", Some(53020), None),
-
/// Allows `#[doc(alias = "...")]`.
(active, doc_alias, "1.27.0", Some(50146), None),
/// Allows using the `#[register_tool]` attribute.
(active, register_tool, "1.41.0", Some(66079), None),
- /// Allows the use of `if` and `match` in constants.
- (active, const_if_match, "1.41.0", Some(49146), None),
-
/// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used.
(active, cfg_sanitize, "1.41.0", Some(39699), None),
/// Allows using `&mut` in constant functions.
(active, const_mut_refs, "1.41.0", Some(57349), None),
- /// Allows the use of `loop` and `while` in constants.
- (active, const_loop, "1.41.0", Some(52000), None),
-
/// Allows bindings in the subpattern of a binding pattern.
/// For example, you can write `x @ Some(y)`.
(active, bindings_after_at, "1.41.0", Some(65490), None),
sym::raw_dylib,
sym::const_trait_impl,
sym::const_trait_bound_opt_out,
+ sym::specialization,
];
Some("removed in favor of `#![feature(marker_trait_attr)]`")),
/// Allows `#[no_debug]`.
(removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
+
+ /// Allows comparing raw pointers during const eval.
+ (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
+ Some("cannot be allowed in const eval in any meaningful way")),
+
// -------------------------------------------------------------------------
// feature-group-end: removed features
// -------------------------------------------------------------------------
use crate::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use crate::hir;
-use rustc_ast::ast;
use rustc_ast::crate_disambiguator::CrateDisambiguator;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_index::vec::IndexVec;
use rustc_span::hygiene::ExpnId;
use rustc_span::symbol::{sym, Symbol};
-use rustc_span::Span;
use log::debug;
use std::fmt::Write;
}
/// The definition table containing node definitions.
-/// It holds the `DefPathTable` for local `DefId`s/`DefPath`s and it also stores a
-/// mapping from `NodeId`s to local `DefId`s.
-#[derive(Clone, Default)]
+/// It holds the `DefPathTable` for `LocalDefId`s/`DefPath`s.
+/// It also stores mappings to convert `LocalDefId`s to/from `HirId`s.
+#[derive(Clone)]
pub struct Definitions {
table: DefPathTable,
- def_id_to_span: IndexVec<LocalDefId, Span>,
-
- // FIXME(eddyb) don't go through `ast::NodeId` to convert between `HirId`
- // and `LocalDefId` - ideally all `LocalDefId`s would be HIR owners.
- node_id_to_def_id: FxHashMap<ast::NodeId, LocalDefId>,
- def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>,
-
- pub(super) node_id_to_hir_id: IndexVec<ast::NodeId, Option<hir::HirId>>,
- /// The reverse mapping of `node_id_to_hir_id`.
- pub(super) hir_id_to_node_id: FxHashMap<hir::HirId, ast::NodeId>,
+ // FIXME(eddyb) ideally all `LocalDefId`s would be HIR owners.
+ pub(super) def_id_to_hir_id: IndexVec<LocalDefId, Option<hir::HirId>>,
+ /// The reverse mapping of `def_id_to_hir_id`.
+ pub(super) hir_id_to_def_id: FxHashMap<hir::HirId, LocalDefId>,
/// If `ExpnId` is an ID of some macro expansion,
/// then `DefId` is the normal module (`mod`) in which the expanded macro was defined.
parent_modules_of_macro_defs: FxHashMap<ExpnId, DefId>,
/// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
expansions_that_defined: FxHashMap<LocalDefId, ExpnId>,
- next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
- /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
- /// we know what parent node that fragment should be attached to thanks to this table.
- invocation_parents: FxHashMap<ExpnId, LocalDefId>,
- /// Indices of unnamed struct or variant fields with unresolved attributes.
- placeholder_field_indices: FxHashMap<ast::NodeId, usize>,
}
/// A unique identifier that we can use to lookup a definition
})
}
- #[inline]
- pub fn opt_local_def_id(&self, node: ast::NodeId) -> Option<LocalDefId> {
- self.node_id_to_def_id.get(&node).copied()
- }
-
- #[inline]
- pub fn local_def_id(&self, node: ast::NodeId) -> LocalDefId {
- self.opt_local_def_id(node).unwrap_or_else(|| {
- panic!("no entry for node id: `{:?}` / `{:?}`", node, self.opt_node_id_to_hir_id(node))
- })
- }
-
#[inline]
pub fn as_local_hir_id(&self, def_id: LocalDefId) -> hir::HirId {
self.local_def_id_to_hir_id(def_id)
}
- #[inline]
- pub fn hir_id_to_node_id(&self, hir_id: hir::HirId) -> ast::NodeId {
- self.hir_id_to_node_id[&hir_id]
- }
-
- #[inline]
- pub fn node_id_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId {
- self.node_id_to_hir_id[node_id].unwrap()
- }
-
- #[inline]
- pub fn opt_node_id_to_hir_id(&self, node_id: ast::NodeId) -> Option<hir::HirId> {
- self.node_id_to_hir_id[node_id]
- }
-
#[inline]
pub fn local_def_id_to_hir_id(&self, id: LocalDefId) -> hir::HirId {
- let node_id = self.def_id_to_node_id[id];
- self.node_id_to_hir_id[node_id].unwrap()
+ self.def_id_to_hir_id[id].unwrap()
}
#[inline]
pub fn opt_local_def_id_to_hir_id(&self, id: LocalDefId) -> Option<hir::HirId> {
- let node_id = self.def_id_to_node_id[id];
- self.node_id_to_hir_id[node_id]
+ self.def_id_to_hir_id[id]
}
#[inline]
pub fn opt_hir_id_to_local_def_id(&self, hir_id: hir::HirId) -> Option<LocalDefId> {
- let node_id = self.hir_id_to_node_id(hir_id);
- self.opt_local_def_id(node_id)
- }
-
- /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
- #[inline]
- pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
- if let Some(def_id) = def_id.as_local() { Some(self.def_id_to_span[def_id]) } else { None }
+ self.hir_id_to_def_id.get(&hir_id).copied()
}
/// Adds a root definition (no parent) and a few other reserved definitions.
- pub fn create_root_def(
- &mut self,
- crate_name: &str,
- crate_disambiguator: CrateDisambiguator,
- ) -> LocalDefId {
+ pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> Definitions {
let key = DefKey {
parent: None,
disambiguated_data: DisambiguatedDefPathData {
let parent_hash = DefKey::root_parent_stable_hash(crate_name, crate_disambiguator);
let def_path_hash = key.compute_stable_hash(parent_hash);
- // Create the definition.
- let root = LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) };
+ // Create the root definition.
+ let mut table = DefPathTable::default();
+ let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) };
assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
- assert_eq!(self.def_id_to_node_id.push(ast::CRATE_NODE_ID), root);
- assert_eq!(self.def_id_to_span.push(rustc_span::DUMMY_SP), root);
-
- self.node_id_to_def_id.insert(ast::CRATE_NODE_ID, root);
- self.set_invocation_parent(ExpnId::root(), root);
+ Definitions {
+ table,
+ def_id_to_hir_id: Default::default(),
+ hir_id_to_def_id: Default::default(),
+ expansions_that_defined: Default::default(),
+ parent_modules_of_macro_defs: Default::default(),
+ }
+ }
- root
+ /// Retrieves the root definition.
+ pub fn get_root_def(&self) -> LocalDefId {
+ LocalDefId { local_def_index: CRATE_DEF_INDEX }
}
/// Adds a definition with a parent definition.
- pub fn create_def_with_parent(
+ pub fn create_def(
&mut self,
parent: LocalDefId,
- node_id: ast::NodeId,
data: DefPathData,
expn_id: ExpnId,
- span: Span,
+ mut next_disambiguator: impl FnMut(LocalDefId, DefPathData) -> u32,
) -> LocalDefId {
- debug!(
- "create_def_with_parent(parent={:?}, node_id={:?}, data={:?})",
- parent, node_id, data
- );
-
- assert!(
- !self.node_id_to_def_id.contains_key(&node_id),
- "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
- node_id,
- data,
- self.table.def_key(self.node_id_to_def_id[&node_id].local_def_index),
- );
+ debug!("create_def(parent={:?}, data={:?}, expn_id={:?})", parent, data, expn_id);
// The root node must be created with `create_root_def()`.
assert!(data != DefPathData::CrateRoot);
- // Find the next free disambiguator for this key.
- let disambiguator = {
- let next_disamb = self.next_disambiguator.entry((parent, data)).or_insert(0);
- let disambiguator = *next_disamb;
- *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
- disambiguator
- };
-
+ let disambiguator = next_disambiguator(parent, data);
let key = DefKey {
parent: Some(parent.local_def_index),
disambiguated_data: DisambiguatedDefPathData { data, disambiguator },
let parent_hash = self.table.def_path_hash(parent.local_def_index);
let def_path_hash = key.compute_stable_hash(parent_hash);
- debug!("create_def_with_parent: after disambiguation, key = {:?}", key);
+ debug!("create_def: after disambiguation, key = {:?}", key);
// Create the definition.
let def_id = LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) };
- assert_eq!(self.def_id_to_node_id.push(node_id), def_id);
- assert_eq!(self.def_id_to_span.push(span), def_id);
-
- // Some things for which we allocate `LocalDefId`s don't correspond to
- // anything in the AST, so they don't have a `NodeId`. For these cases
- // we don't need a mapping from `NodeId` to `LocalDefId`.
- if node_id != ast::DUMMY_NODE_ID {
- debug!("create_def_with_parent: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
- self.node_id_to_def_id.insert(node_id, def_id);
- }
-
if expn_id != ExpnId::root() {
self.expansions_that_defined.insert(def_id, expn_id);
}
def_id
}
- /// Initializes the `ast::NodeId` to `HirId` mapping once it has been generated during
+ /// Initializes the `LocalDefId` to `HirId` mapping once it has been generated during
/// AST to HIR lowering.
- pub fn init_node_id_to_hir_id_mapping(
+ pub fn init_def_id_to_hir_id_mapping(
&mut self,
- mapping: IndexVec<ast::NodeId, Option<hir::HirId>>,
+ mapping: IndexVec<LocalDefId, Option<hir::HirId>>,
) {
assert!(
- self.node_id_to_hir_id.is_empty(),
- "trying to initialize `NodeId` -> `HirId` mapping twice"
+ self.def_id_to_hir_id.is_empty(),
+ "trying to initialize `LocalDefId` <-> `HirId` mappings twice"
);
- self.node_id_to_hir_id = mapping;
- // Build the reverse mapping of `node_id_to_hir_id`.
- self.hir_id_to_node_id = self
- .node_id_to_hir_id
+ // Build the reverse mapping of `def_id_to_hir_id`.
+ self.hir_id_to_def_id = mapping
.iter_enumerated()
- .filter_map(|(node_id, &hir_id)| hir_id.map(|hir_id| (hir_id, node_id)))
+ .filter_map(|(def_id, hir_id)| hir_id.map(|hir_id| (hir_id, def_id)))
.collect();
+
+ self.def_id_to_hir_id = mapping;
}
pub fn expansion_that_defined(&self, id: LocalDefId) -> ExpnId {
pub fn add_parent_module_of_macro_def(&mut self, expn_id: ExpnId, module: DefId) {
self.parent_modules_of_macro_defs.insert(expn_id, module);
}
-
- pub fn invocation_parent(&self, invoc_id: ExpnId) -> LocalDefId {
- self.invocation_parents[&invoc_id]
- }
-
- pub fn set_invocation_parent(&mut self, invoc_id: ExpnId, parent: LocalDefId) {
- let old_parent = self.invocation_parents.insert(invoc_id, parent);
- assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation");
- }
-
- pub fn placeholder_field_index(&self, node_id: ast::NodeId) -> usize {
- self.placeholder_field_indices[&node_id]
- }
-
- pub fn set_placeholder_field_index(&mut self, node_id: ast::NodeId, index: usize) {
- let old_index = self.placeholder_field_indices.insert(node_id, index);
- assert!(old_index.is_none(), "placeholder field index is reset for a node ID");
- }
-
- pub fn lint_node_id(&mut self, expn_id: ExpnId) -> ast::NodeId {
- self.invocation_parents
- .get(&expn_id)
- .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[*id])
- }
}
impl DefPathData {
use rustc_ast::util::parser::ExprPrecedence;
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
use rustc_macros::HashStable_Generic;
+use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::{SourceMap, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{MultiSpan, Span, DUMMY_SP};
/// A list of proc macro HirIds, written out in the order in which
/// they are declared in the static array generated by proc_macro_harness.
pub proc_macros: Vec<HirId>,
+
+ pub trait_map: BTreeMap<HirId, Vec<TraitCandidate>>,
}
impl Crate<'hir> {
// Check whether a span corresponding to a range expression is a
// range literal, rather than an explicit struct or `new()` call.
fn is_lit(sm: &SourceMap, span: &Span) -> bool {
- let end_point = sm.end_point(*span);
-
- if let Ok(end_string) = sm.span_to_snippet(end_point) {
- !(end_string.ends_with('}') || end_string.ends_with(')'))
- } else {
- false
- }
+ sm.span_to_snippet(*span).map(|range_src| range_src.contains("..")).unwrap_or(false)
};
match expr.kind {
// The TraitCandidate's import_ids is empty if the trait is defined in the same module, and
// has length > 0 if the trait is found through an chain of imports, starting with the
// import/use statement in the scope where the trait is used.
-#[derive(Clone, Debug)]
-pub struct TraitCandidate<ID = HirId> {
+#[derive(RustcEncodable, RustcDecodable, Clone, Debug)]
+pub struct TraitCandidate {
pub def_id: DefId,
- pub import_ids: SmallVec<[ID; 1]>,
-}
-
-impl<ID> TraitCandidate<ID> {
- pub fn map_import_ids<F, T>(self, f: F) -> TraitCandidate<T>
- where
- F: Fn(ID) -> T,
- {
- let TraitCandidate { def_id, import_ids } = self;
- let import_ids = import_ids.into_iter().map(f).collect();
- TraitCandidate { def_id, import_ids }
- }
+ pub import_ids: SmallVec<[LocalDefId; 1]>,
}
-// Trait method resolution
-pub type TraitMap<ID = HirId> = NodeMap<Vec<TraitCandidate<ID>>>;
-
#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum Node<'hir> {
Param(&'hir Param<'hir>),
}
}
+ pub fn body_id(&self) -> Option<BodyId> {
+ match self {
+ Node::TraitItem(TraitItem {
+ kind: TraitItemKind::Fn(_, TraitFn::Provided(body_id)),
+ ..
+ })
+ | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })
+ | Node::Item(Item { kind: ItemKind::Fn(.., body_id), .. }) => Some(*body_id),
+ _ => None,
+ }
+ }
+
pub fn generics(&self) -> Option<&Generics<'_>> {
match self {
Node::TraitItem(TraitItem { generics, .. })
- | Node::ImplItem(ImplItem { generics, .. })
- | Node::Item(Item {
- kind:
- ItemKind::Trait(_, _, generics, ..)
- | ItemKind::Impl { generics, .. }
- | ItemKind::Fn(_, generics, _),
- ..
- }) => Some(generics),
+ | Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
+ Node::Item(item) => item.kind.generics(),
_ => None,
}
}
use lazy_static::lazy_static;
+pub enum LangItemGroup {
+ Op,
+}
+
+const NUM_GROUPS: usize = 1;
+
+macro_rules! expand_group {
+ () => {
+ None
+ };
+ ($group:expr) => {
+ Some($group)
+ };
+}
+
// The actual lang items defined come at the end of this file in one handy table.
// So you probably just want to nip down to the end.
macro_rules! language_item_table {
(
- $( $variant:ident, $name:expr, $method:ident, $target:path; )*
+ $( $variant:ident $($group:expr)?, $name:expr, $method:ident, $target:expr; )*
) => {
enum_from_u32! {
$( $variant => $name, )*
}
}
+
+ pub fn group(self) -> Option<LangItemGroup> {
+ use LangItemGroup::*;
+ match self {
+ $( $variant => expand_group!($($group)*), )*
+ }
+ }
}
#[derive(HashStable_Generic)]
pub items: Vec<Option<DefId>>,
/// Lang items that were not found during collection.
pub missing: Vec<LangItem>,
+ /// Mapping from `LangItemGroup` discriminants to all
+ /// `DefId`s of lang items in that group.
+ pub groups: [Vec<DefId>; NUM_GROUPS],
}
impl LanguageItems {
Self {
items: vec![$(init_none($variant)),*],
missing: Vec::new(),
+ groups: [vec![]; NUM_GROUPS],
}
}
self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name()))
}
+ pub fn group(&self, group: LangItemGroup) -> &[DefId] {
+ self.groups[group as usize].as_ref()
+ }
+
$(
/// Returns the corresponding `DefId` for the lang item
#[doc = $name]
CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait, Target::Trait;
DispatchFromDynTraitLangItem,"dispatch_from_dyn", dispatch_from_dyn_trait, Target::Trait;
- AddTraitLangItem, "add", add_trait, Target::Trait;
- SubTraitLangItem, "sub", sub_trait, Target::Trait;
- MulTraitLangItem, "mul", mul_trait, Target::Trait;
- DivTraitLangItem, "div", div_trait, Target::Trait;
- RemTraitLangItem, "rem", rem_trait, Target::Trait;
- NegTraitLangItem, "neg", neg_trait, Target::Trait;
- NotTraitLangItem, "not", not_trait, Target::Trait;
- BitXorTraitLangItem, "bitxor", bitxor_trait, Target::Trait;
- BitAndTraitLangItem, "bitand", bitand_trait, Target::Trait;
- BitOrTraitLangItem, "bitor", bitor_trait, Target::Trait;
- ShlTraitLangItem, "shl", shl_trait, Target::Trait;
- ShrTraitLangItem, "shr", shr_trait, Target::Trait;
- AddAssignTraitLangItem, "add_assign", add_assign_trait, Target::Trait;
- SubAssignTraitLangItem, "sub_assign", sub_assign_trait, Target::Trait;
- MulAssignTraitLangItem, "mul_assign", mul_assign_trait, Target::Trait;
- DivAssignTraitLangItem, "div_assign", div_assign_trait, Target::Trait;
- RemAssignTraitLangItem, "rem_assign", rem_assign_trait, Target::Trait;
- BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait, Target::Trait;
- BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait, Target::Trait;
- BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait, Target::Trait;
- ShlAssignTraitLangItem, "shl_assign", shl_assign_trait, Target::Trait;
- ShrAssignTraitLangItem, "shr_assign", shr_assign_trait, Target::Trait;
- IndexTraitLangItem, "index", index_trait, Target::Trait;
- IndexMutTraitLangItem, "index_mut", index_mut_trait, Target::Trait;
+ AddTraitLangItem(Op), "add", add_trait, Target::Trait;
+ SubTraitLangItem(Op), "sub", sub_trait, Target::Trait;
+ MulTraitLangItem(Op), "mul", mul_trait, Target::Trait;
+ DivTraitLangItem(Op), "div", div_trait, Target::Trait;
+ RemTraitLangItem(Op), "rem", rem_trait, Target::Trait;
+ NegTraitLangItem(Op), "neg", neg_trait, Target::Trait;
+ NotTraitLangItem(Op), "not", not_trait, Target::Trait;
+ BitXorTraitLangItem(Op), "bitxor", bitxor_trait, Target::Trait;
+ BitAndTraitLangItem(Op), "bitand", bitand_trait, Target::Trait;
+ BitOrTraitLangItem(Op), "bitor", bitor_trait, Target::Trait;
+ ShlTraitLangItem(Op), "shl", shl_trait, Target::Trait;
+ ShrTraitLangItem(Op), "shr", shr_trait, Target::Trait;
+ AddAssignTraitLangItem(Op), "add_assign", add_assign_trait, Target::Trait;
+ SubAssignTraitLangItem(Op), "sub_assign", sub_assign_trait, Target::Trait;
+ MulAssignTraitLangItem(Op), "mul_assign", mul_assign_trait, Target::Trait;
+ DivAssignTraitLangItem(Op), "div_assign", div_assign_trait, Target::Trait;
+ RemAssignTraitLangItem(Op), "rem_assign", rem_assign_trait, Target::Trait;
+ BitXorAssignTraitLangItem(Op),"bitxor_assign", bitxor_assign_trait, Target::Trait;
+ BitAndAssignTraitLangItem(Op),"bitand_assign", bitand_assign_trait, Target::Trait;
+ BitOrAssignTraitLangItem(Op),"bitor_assign", bitor_assign_trait, Target::Trait;
+ ShlAssignTraitLangItem(Op), "shl_assign", shl_assign_trait, Target::Trait;
+ ShrAssignTraitLangItem(Op), "shr_assign", shr_assign_trait, Target::Trait;
+ IndexTraitLangItem(Op), "index", index_trait, Target::Trait;
+ IndexMutTraitLangItem(Op), "index_mut", index_mut_trait, Target::Trait;
UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type, Target::Struct;
VaListTypeLangItem, "va_list", va_list, Target::Struct;
FnMutTraitLangItem, "fn_mut", fn_mut_trait, Target::Trait;
FnOnceTraitLangItem, "fn_once", fn_once_trait, Target::Trait;
+ FnOnceOutputLangItem, "fn_once_output", fn_once_output, Target::AssocTy;
+
FutureTraitLangItem, "future_trait", future_trait, Target::Trait;
GeneratorStateLangItem, "generator_state", gen_state, Target::Enum;
GeneratorTraitLangItem, "generator", gen_trait, Target::Trait;
StartFnLangItem, "start", start_fn, Target::Fn;
+ CountCodeRegionFnLangItem, "count_code_region", count_code_region_fn, Target::Fn;
+
EhPersonalityLangItem, "eh_personality", eh_personality, Target::Fn;
EhCatchTypeinfoLangItem, "eh_catch_typeinfo", eh_catch_typeinfo, Target::Static;
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
#![feature(crate_visibility_modifier)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_fn)] // For the unsizing cast on `&[]`
#![feature(const_panic)]
#![feature(in_band_lifetimes)]
///
/// All operations that involve a row and/or column index will panic if the
/// index exceeds the relevant bound.
-#[derive(Clone, Debug, Eq, PartialEq, RustcDecodable, RustcEncodable)]
+#[derive(Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct BitMatrix<R: Idx, C: Idx> {
num_rows: usize,
num_columns: usize,
}
}
+impl<R: Idx, C: Idx> fmt::Debug for BitMatrix<R, C> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// Forces its contents to print in regular mode instead of alternate mode.
+ struct OneLinePrinter<T>(T);
+ impl<T: fmt::Debug> fmt::Debug for OneLinePrinter<T> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(fmt, "{:?}", self.0)
+ }
+ }
+
+ write!(fmt, "BitMatrix({}x{}) ", self.num_rows, self.num_columns)?;
+ let items = self.rows().flat_map(|r| self.iter(r).map(move |c| (r, c)));
+ fmt.debug_set().entries(items.map(OneLinePrinter)).finish()
+ }
+}
+
/// A fixed-column-size, variable-row-size 2D bit matrix with a moderately
/// sparse representation.
///
#![feature(allow_internal_unstable)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(extend_one)]
}
ty::ReVar(vid) => {
- let r = self
+ let resolved_vid = self
.infcx
.unwrap()
.inner
.borrow_mut()
.unwrap_region_constraints()
- .opportunistic_resolve_var(self.tcx, vid);
+ .opportunistic_resolve_var(vid);
debug!(
"canonical: region var found with vid {:?}, \
opportunistically resolved to {:?}",
vid, r
);
+ let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
self.canonicalize_region_mode.canonicalize_free_region(self, r)
}
| ty::Float(..)
| ty::Adt(..)
| ty::Str
- | ty::Error
+ | ty::Error(_)
| ty::Array(..)
| ty::Slice(..)
| ty::RawPtr(..)
self.tcx
.mk_const(ty::Const {
val: ty::ConstKind::Placeholder(placeholder_mapped),
- ty: self.tcx.types.err, // FIXME(const_generics)
+ ty: self.tcx.ty_error(), // FIXME(const_generics)
})
.into()
}
(ty::FnDef(did1, substs1), ty::FnPtr(sig2)) => {
let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
let mut values = self.cmp_fn_sig(&sig1, sig2);
- values.0.push_normal(format!(
+ values.0.push_highlighted(format!(
" {{{}}}",
self.tcx.def_path_str_with_substs(*did1, substs1)
));
self.tcx.sess,
var_origin.span(),
E0495,
- "cannot infer an appropriate lifetime{} \
- due to conflicting requirements",
+ "cannot infer an appropriate lifetime{} due to conflicting requirements",
var_description
)
}
if let (None, Some(ty)) =
(self.found_local_pattern, self.node_ty_contains_target(local.hir_id))
{
+ // FIXME: There's a trade-off here - we can either check that our target span
+ // is contained in `local.span` or not. If we choose to check containment
+ // we can avoid some spurious suggestions (see #72690), but we lose
+ // the ability to report on things like:
+ //
+ // ```
+ // let x = vec![];
+ // ```
+ //
+ // because the target span will be in the macro expansion of `vec![]`.
+ // At present we choose not to check containment.
self.found_local_pattern = Some(&*local.pat);
self.found_node_ty = Some(ty);
}
if let (None, Some(ty)) =
(self.found_arg_pattern, self.node_ty_contains_target(param.hir_id))
{
- self.found_arg_pattern = Some(&*param.pat);
- self.found_node_ty = Some(ty);
+ if self.target_span.contains(param.pat.span) {
+ self.found_arg_pattern = Some(&*param.pat);
+ self.found_node_ty = Some(ty);
+ }
}
}
intravisit::walk_body(self, body);
&self,
region: Region<'tcx>,
br: &ty::BoundRegion,
- ) -> Option<(&hir::Ty<'_>, &hir::FnDecl<'_>)> {
+ ) -> Option<(&hir::Ty<'tcx>, &hir::FnDecl<'tcx>)> {
if let Some(anon_reg) = self.tcx().is_suitable_region(region) {
- let def_id = anon_reg.def_id;
- if let Some(def_id) = def_id.as_local() {
- let hir_id = self.tcx().hir().as_local_hir_id(def_id);
- let fndecl = match self.tcx().hir().get(hir_id) {
- Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. })
- | Node::TraitItem(&hir::TraitItem {
- kind: hir::TraitItemKind::Fn(ref m, ..),
- ..
- })
- | Node::ImplItem(&hir::ImplItem {
- kind: hir::ImplItemKind::Fn(ref m, ..),
- ..
- }) => &m.decl,
- _ => return None,
- };
+ let hir_id = self.tcx().hir().as_local_hir_id(anon_reg.def_id);
+ let fndecl = match self.tcx().hir().get(hir_id) {
+ Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. })
+ | Node::TraitItem(&hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(ref m, ..),
+ ..
+ })
+ | Node::ImplItem(&hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(ref m, ..), ..
+ }) => &m.decl,
+ _ => return None,
+ };
- return fndecl
- .inputs
- .iter()
- .find_map(|arg| self.find_component_for_bound_region(arg, br))
- .map(|ty| (ty, &**fndecl));
- }
+ fndecl
+ .inputs
+ .iter()
+ .find_map(|arg| self.find_component_for_bound_region(arg, br))
+ .map(|ty| (ty, &**fndecl))
+ } else {
+ None
}
- None
}
// This method creates a FindNestedTypeVisitor which returns the type corresponding
//! where one region is named and the other is anonymous.
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
-use rustc_hir::{FnRetTy, TyKind};
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::FnRetTy;
use rustc_middle::ty;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
if let Some((_, fndecl)) = self.find_anon_type(anon, &br) {
- let is_self_anon = self.is_self_anon(is_first, scope_def_id);
- if is_self_anon {
+ if self.is_self_anon(is_first, scope_def_id) {
return None;
}
if let FnRetTy::Return(ty) = &fndecl.output {
- let mut v = ty::TraitObjectVisitor(vec![]);
- rustc_hir::intravisit::walk_ty(&mut v, ty);
+ let mut v = ty::TraitObjectVisitor(vec![], self.tcx().hir());
+ v.visit_ty(ty);
debug!("try_report_named_anon_conflict: ret ty {:?}", ty);
if sub == &ty::ReStatic
- && (matches!(ty.kind, TyKind::OpaqueDef(_, _)) || v.0.len() == 1)
+ && v.0
+ .into_iter()
+ .filter(|t| t.span.desugaring_kind().is_none())
+ .next()
+ .is_some()
{
+ // If the failure is due to a `'static` requirement coming from a `dyn` or
+ // `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case
+ // better in `static_impl_trait`.
debug!("try_report_named_anon_conflict: impl Trait + 'static");
- // This is an `impl Trait` or `dyn Trait` return that evaluates de need of
- // `'static`. We handle this case better in `static_impl_trait`.
return None;
}
}
//! Error Reporting for static impl Traits.
-use crate::infer::error_reporting::msg_span_from_free_region;
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
-use rustc_errors::{Applicability, ErrorReported};
+use rustc_errors::{struct_span_err, Applicability, ErrorReported};
+use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};
use rustc_middle::ty::RegionKind;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Print the error message for lifetime errors when the return type is a static impl Trait.
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
- if let Some(ref error) = self.error {
- if let RegionResolutionError::SubSupConflict(
- _,
- var_origin,
- sub_origin,
- sub_r,
- sup_origin,
- sup_r,
- ) = error.clone()
- {
- let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
- let (fn_return_span, is_dyn) =
- self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
- if sub_r == &RegionKind::ReStatic {
- let sp = var_origin.span();
- let return_sp = sub_origin.span();
- let mut err =
- self.tcx().sess.struct_span_err(sp, "cannot infer an appropriate lifetime");
- let param_info = self.find_param_with_region(sup_r, sub_r)?;
- err.span_label(param_info.param_ty_span, "data with this lifetime...");
+ debug!("try_report_static_impl_trait(error={:?})", self.error);
+ if let Some(RegionResolutionError::SubSupConflict(
+ _,
+ var_origin,
+ ref sub_origin,
+ sub_r,
+ ref sup_origin,
+ sup_r,
+ )) = self.error
+ {
+ debug!(
+ "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
+ var_origin, sub_origin, sub_r, sup_origin, sup_r
+ );
+ let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
+ debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
+ let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
+ if fn_returns.is_empty() {
+ return None;
+ }
+ debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
+ if *sub_r == RegionKind::ReStatic {
+ let sp = var_origin.span();
+ let return_sp = sub_origin.span();
+ let param_info = self.find_param_with_region(sup_r, sub_r)?;
+ let (lifetime_name, lifetime) = if sup_r.has_name() {
+ (sup_r.to_string(), format!("lifetime `{}`", sup_r))
+ } else {
+ ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
+ };
+ let mut err = struct_span_err!(
+ self.tcx().sess,
+ sp,
+ E0759,
+ "cannot infer an appropriate lifetime"
+ );
+ err.span_label(
+ param_info.param_ty_span,
+ &format!("this data with {}...", lifetime),
+ );
+ debug!("try_report_static_impl_trait: param_info={:?}", param_info);
- // We try to make the output have fewer overlapping spans if possible.
- if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
- && sup_origin.span() != return_sp
- {
- // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
+ // We try to make the output have fewer overlapping spans if possible.
+ if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
+ && sup_origin.span() != return_sp
+ {
+ // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
- // Customize the spans and labels depending on their relative order so
- // that split sentences flow correctly.
- if sup_origin.span().shrink_to_hi() <= return_sp.shrink_to_lo() {
- err.span_label(sup_origin.span(), "...is captured here...");
- err.span_label(return_sp, "...and required to be `'static` by this");
- } else {
- err.span_label(return_sp, "...is required to be `'static` by this...");
- err.span_label(sup_origin.span(), "...and is captured here");
- }
- } else {
+ // Customize the spans and labels depending on their relative order so
+ // that split sentences flow correctly.
+ if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
+ // Avoid the following:
+ //
+ // error: cannot infer an appropriate lifetime
+ // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+ // |
+ // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+ // | ---- ---------^-
+ //
+ // and instead show:
+ //
+ // error: cannot infer an appropriate lifetime
+ // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+ // |
+ // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+ // | ---- ^
err.span_label(
- return_sp,
- "...is captured and required to be `'static` here",
+ sup_origin.span(),
+ "...is captured here, requiring it to live as long as `'static`",
);
+ } else {
+ err.span_label(sup_origin.span(), "...is captured here...");
+ if return_sp < sup_origin.span() {
+ err.span_note(
+ return_sp,
+ "...and is required to live as long as `'static` here",
+ );
+ } else {
+ err.span_label(
+ return_sp,
+ "...and is required to live as long as `'static` here",
+ );
+ }
}
+ } else {
+ err.span_label(
+ return_sp,
+ "...is captured and required to live as long as `'static` here",
+ );
+ }
- let (lifetime, _) = msg_span_from_free_region(self.tcx(), sup_r);
+ // FIXME: account for the need of parens in `&(dyn Trait + '_)`
+ let consider = "consider changing the";
+ let declare = "to declare that the";
+ let arg = match param_info.param.pat.simple_ident() {
+ Some(simple_ident) => format!("argument `{}`", simple_ident),
+ None => "the argument".to_string(),
+ };
+ let explicit =
+ format!("you can add an explicit `{}` lifetime bound", lifetime_name);
+ let explicit_static =
+ format!("explicit `'static` bound to the lifetime of {}", arg);
+ let captures = format!("captures data from {}", arg);
+ let add_static_bound =
+ "alternatively, add an explicit `'static` bound to this reference";
+ let plus_lt = format!(" + {}", lifetime_name);
+ for fn_return in fn_returns {
+ if fn_return.span.desugaring_kind().is_some() {
+ // Skip `async` desugaring `impl Future`.
+ continue;
+ }
+ match fn_return.kind {
+ TyKind::OpaqueDef(item_id, _) => {
+ let item = self.tcx().hir().item(item_id.id);
+ let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
+ opaque
+ } else {
+ err.emit();
+ return Some(ErrorReported);
+ };
- let lifetime_name =
- if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
- // only apply this suggestion onto functions with
- // explicit non-desugar'able return.
- if fn_return_span.desugaring_kind().is_none() {
- let msg = format!(
- "to permit non-static references in {} `{} Trait` value, you can add \
- an explicit bound for {}",
- if is_dyn { "a" } else { "an" },
- if is_dyn { "dyn" } else { "impl" },
- lifetime,
- );
- // FIXME: account for the need of parens in `&(dyn Trait + '_)`
- err.span_suggestion_verbose(
- fn_return_span.shrink_to_hi(),
- &msg,
- format!(" + {}", lifetime_name),
- Applicability::MaybeIncorrect,
- );
+ if let Some(span) = opaque
+ .bounds
+ .iter()
+ .filter_map(|arg| match arg {
+ GenericBound::Outlives(Lifetime {
+ name: LifetimeName::Static,
+ span,
+ ..
+ }) => Some(*span),
+ _ => None,
+ })
+ .next()
+ {
+ err.span_suggestion_verbose(
+ span,
+ &format!("{} `impl Trait`'s {}", consider, explicit_static),
+ lifetime_name.clone(),
+ Applicability::MaybeIncorrect,
+ );
+ err.span_suggestion_verbose(
+ param_info.param_ty_span,
+ add_static_bound,
+ param_info.param_ty.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ } else if let Some(_) = opaque
+ .bounds
+ .iter()
+ .filter_map(|arg| match arg {
+ GenericBound::Outlives(Lifetime { name, span, .. })
+ if name.ident().to_string() == lifetime_name =>
+ {
+ Some(*span)
+ }
+ _ => None,
+ })
+ .next()
+ {
+ } else {
+ err.span_suggestion_verbose(
+ fn_return.span.shrink_to_hi(),
+ &format!(
+ "{declare} `impl Trait` {captures}, {explicit}",
+ declare = declare,
+ captures = captures,
+ explicit = explicit,
+ ),
+ plus_lt.clone(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ TyKind::TraitObject(_, lt) => match lt.name {
+ LifetimeName::ImplicitObjectLifetimeDefault => {
+ err.span_suggestion_verbose(
+ fn_return.span.shrink_to_hi(),
+ &format!(
+ "{declare} trait object {captures}, {explicit}",
+ declare = declare,
+ captures = captures,
+ explicit = explicit,
+ ),
+ plus_lt.clone(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ name if name.ident().to_string() != lifetime_name => {
+ // With this check we avoid suggesting redundant bounds. This
+ // would happen if there are nested impl/dyn traits and only
+ // one of them has the bound we'd suggest already there, like
+ // in `impl Foo<X = dyn Bar> + '_`.
+ err.span_suggestion_verbose(
+ lt.span,
+ &format!("{} trait object's {}", consider, explicit_static),
+ lifetime_name.clone(),
+ Applicability::MaybeIncorrect,
+ );
+ err.span_suggestion_verbose(
+ param_info.param_ty_span,
+ add_static_bound,
+ param_info.param_ty.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {}
+ },
+ _ => {}
}
- err.emit();
- return Some(ErrorReported);
}
+ err.emit();
+ return Some(ErrorReported);
}
}
None
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
use rustc_middle::ty::{self, DefIdTree, Region, Ty};
use rustc_span::Span;
// FIXME(#42703) - Need to handle certain cases here.
pub(super) fn is_return_type_anon(
&self,
- scope_def_id: DefId,
+ scope_def_id: LocalDefId,
br: ty::BoundRegion,
decl: &hir::FnDecl<'_>,
) -> Option<Span> {
// corresponds to self and if yes, we display E0312.
// FIXME(#42700) - Need to format self properly to
// enable E0621 for it.
- pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: DefId) -> bool {
+ pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: LocalDefId) -> bool {
is_first
- && self.tcx().opt_associated_item(scope_def_id).map(|i| i.fn_has_self_parameter)
+ && self
+ .tcx()
+ .opt_associated_item(scope_def_id.to_def_id())
+ .map(|i| i.fn_has_self_parameter)
== Some(true)
}
}
| ty::Float(..)
| ty::Adt(..)
| ty::Str
- | ty::Error
+ | ty::Error(_)
| ty::Array(..)
| ty::Slice(..)
| ty::RawPtr(..)
ty::ConstKind::Param(_)
| ty::ConstKind::Value(_)
| ty::ConstKind::Unevaluated(..)
- | ty::ConstKind::Error => {}
+ | ty::ConstKind::Error(_) => {}
}
ct.super_fold_with(self)
let span = self.trace.cause.span;
- self.infcx.commit_if_ok(|snapshot| {
+ self.infcx.commit_if_ok(|_| {
// First, we instantiate each bound region in the supertype with a
// fresh placeholder region.
- let (b_prime, placeholder_map) = self.infcx.replace_bound_vars_with_placeholders(b);
+ let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b);
// Next, we instantiate each bound region in the subtype
// with a fresh region variable. These region variables --
// Compare types now that bound regions have been replaced.
let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
- self.infcx.leak_check(!a_is_expected, &placeholder_map, snapshot)?;
-
debug!("higher_ranked_sub: OK result={:?}", result);
Ok(ty::Binder::bind(result))
/// placeholder region. This is the first step of checking subtyping
/// when higher-ranked things are involved.
///
- /// **Important:** you must call this function from within a snapshot.
- /// Moreover, before committing the snapshot, you must eventually call
- /// either `plug_leaks` or `pop_placeholders` to remove the placeholder
- /// regions. If you rollback the snapshot (or are using a probe), then
- /// the pop occurs as part of the rollback, so an explicit call is not
- /// needed (but is also permitted).
- ///
- /// For more information about how placeholders and HRTBs work, see
+ /// **Important:** You have to be careful to not leak these placeholders,
+ /// for more information about how placeholders and HRTBs work, see
/// the [rustc dev guide].
///
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
where
T: TypeFoldable<'tcx>,
{
- let next_universe = self.create_next_universe();
+ // Figure out what the next universe will be, but don't actually create
+ // it until after we've done the substitution (in particular there may
+ // be no bound variables). This is a performance optimization, since the
+ // leak check for example can be skipped if no new universes are created
+ // (i.e., if there are no placeholders).
+ let next_universe = self.universe().next_universe();
let fld_r = |br| {
self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion {
let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t, fld_c);
+ // If there were higher-ranked regions to replace, then actually create
+ // the next universe (this avoids needlessly creating universes).
+ if !map.is_empty() {
+ let n_u = self.create_next_universe();
+ assert_eq!(n_u, next_universe);
+ }
+
debug!(
"replace_bound_vars_with_placeholders(\
next_universe={:?}, \
pub fn leak_check(
&self,
overly_polymorphic: bool,
- placeholder_map: &PlaceholderMap<'tcx>,
snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> RelateResult<'tcx, ()> {
// If the user gave `-Zno-leak-check`, or we have been
self.inner.borrow_mut().unwrap_region_constraints().leak_check(
self.tcx,
overly_polymorphic,
- placeholder_map,
+ self.universe(),
snapshot,
)
}
/// Necessary because we can't write the following bound:
/// `F: for<'b, 'tcx> where 'tcx FnOnce(InferCtxt<'b, 'tcx>)`.
pub struct InferCtxtBuilder<'tcx> {
- global_tcx: TyCtxt<'tcx>,
+ tcx: TyCtxt<'tcx>,
fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
}
impl TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
- InferCtxtBuilder { global_tcx: self, fresh_tables: None }
+ InferCtxtBuilder { tcx: self, fresh_tables: None }
}
}
}
pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
- let InferCtxtBuilder { global_tcx, ref fresh_tables } = *self;
+ let InferCtxtBuilder { tcx, ref fresh_tables } = *self;
let in_progress_tables = fresh_tables.as_ref();
- global_tcx.enter_local(|tcx| {
- f(InferCtxt {
- tcx,
- in_progress_tables,
- inner: RefCell::new(InferCtxtInner::new()),
- lexical_region_resolutions: RefCell::new(None),
- selection_cache: Default::default(),
- evaluation_cache: Default::default(),
- reported_trait_errors: Default::default(),
- reported_closure_mismatch: Default::default(),
- tainted_by_errors_flag: Cell::new(false),
- err_count_on_creation: tcx.sess.err_count(),
- in_snapshot: Cell::new(false),
- skip_leak_check: Cell::new(false),
- universe: Cell::new(ty::UniverseIndex::ROOT),
- })
+ f(InferCtxt {
+ tcx,
+ in_progress_tables,
+ inner: RefCell::new(InferCtxtInner::new()),
+ lexical_region_resolutions: RefCell::new(None),
+ selection_cache: Default::default(),
+ evaluation_cache: Default::default(),
+ reported_trait_errors: Default::default(),
+ reported_closure_mismatch: Default::default(),
+ tainted_by_errors_flag: Cell::new(false),
+ err_count_on_creation: tcx.sess.err_count(),
+ in_snapshot: Cell::new(false),
+ skip_leak_check: Cell::new(false),
+ universe: Cell::new(ty::UniverseIndex::ROOT),
})
}
}
return None;
}
- Some(self.commit_if_ok(|snapshot| {
- let (ty::SubtypePredicate { a_is_expected, a, b }, placeholder_map) =
+ Some(self.commit_if_ok(|_snapshot| {
+ let (ty::SubtypePredicate { a_is_expected, a, b }, _) =
self.replace_bound_vars_with_placeholders(&predicate);
let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
- self.leak_check(false, &placeholder_map, snapshot)?;
-
Ok(ok.unit())
}))
}
cause: &traits::ObligationCause<'tcx>,
predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
) -> UnitResult<'tcx> {
- self.commit_if_ok(|snapshot| {
- let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
+ self.commit_if_ok(|_snapshot| {
+ let (ty::OutlivesPredicate(r_a, r_b), _) =
self.replace_bound_vars_with_placeholders(&predicate);
let origin = SubregionOrigin::from_obligation_cause(cause, || {
RelateRegionParamBound(cause.span)
});
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
- self.leak_check(false, &placeholder_map, snapshot)?;
Ok(())
})
}
}
pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> {
+ let err = tcx.ty_error();
TypeTrace {
cause: ObligationCause::dummy(),
- values: Types(ExpectedFound { expected: tcx.types.err, found: tcx.types.err }),
+ values: Types(ExpectedFound { expected: err, found: err }),
}
}
}
}
if a == b {
- return Ok(a);
+ // Subtle: if a or b has a bound variable that we are lazilly
+ // substituting, then even if a == b, it could be that the values we
+ // will substitute for those bound variables are *not* the same, and
+ // hence returning `Ok(a)` is incorrect.
+ if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
+ return Ok(a);
+ }
}
match (&a.kind, &b.kind) {
use crate::infer::outlives::env::RegionBoundPairs;
use crate::infer::{GenericKind, VerifyBound};
-use crate::traits;
use rustc_data_structures::captures::Captures;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
use rustc_middle::ty::{self, Ty, TyCtxt};
/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
fn region_bounds_declared_on_associated_item(
&self,
assoc_item_def_id: DefId,
- ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
+ ) -> impl Iterator<Item = ty::Region<'tcx>> {
let tcx = self.tcx;
- let assoc_item = tcx.associated_item(assoc_item_def_id);
- let trait_def_id = assoc_item.container.assert_trait();
- let trait_predicates = tcx.predicates_of(trait_def_id).predicates.iter().map(|(p, _)| *p);
- let identity_substs = InternalSubsts::identity_for_item(tcx, assoc_item_def_id);
- let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs);
- self.collect_outlives_from_predicate_list(
- move |ty| ty == identity_proj,
- traits::elaborate_predicates(tcx, trait_predicates).map(|o| o.predicate),
- )
- .map(|b| b.1)
+ let predicates = tcx.projection_predicates(assoc_item_def_id);
+ predicates
+ .into_iter()
+ .filter_map(|p| p.to_opt_type_outlives())
+ .filter_map(|p| p.no_bound_vars())
+ .map(|b| b.1)
}
/// Searches through a predicate list for a predicate `T: 'a`.
use super::*;
-use crate::infer::{CombinedSnapshot, PlaceholderMap};
-use rustc_data_structures::undo_log::UndoLogs;
+use crate::infer::CombinedSnapshot;
+use rustc_data_structures::{
+ graph::{scc::Sccs, vec_graph::VecGraph},
+ undo_log::UndoLogs,
+};
+use rustc_index::vec::Idx;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::RelateResult;
impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
- /// Searches region constraints created since `snapshot` that
- /// affect one of the placeholders in `placeholder_map`, returning
- /// an error if any of the placeholders are related to another
- /// placeholder or would have to escape into some parent universe
- /// that cannot name them.
+ /// Searches new universes created during `snapshot`, looking for
+ /// placeholders that may "leak" out from the universes they are contained
+ /// in. If any leaking placeholders are found, then an `Err` is returned
+ /// (typically leading to the snapshot being reversed).
///
- /// This is a temporary backwards compatibility measure to try and
- /// retain the older (arguably incorrect) behavior of the
- /// compiler.
+ /// The leak check *used* to be the only way we had to handle higher-ranked
+ /// obligations. Now that we have integrated universes into the region
+ /// solvers, this is no longer the case, but we retain the leak check for
+ /// backwards compatibility purposes. In particular, it lets us make "early"
+ /// decisions about whether a region error will be reported that are used in
+ /// coherence and elsewhere -- see #56105 and #59490 for more details. The
+ /// eventual fate of the leak checker is not yet settled.
///
- /// NB. Although `_snapshot` isn't used, it's passed in to prove
- /// that we are in a snapshot, which guarantees that we can just
- /// search the "undo log" for edges. This is mostly an efficiency
- /// thing -- we could search *all* region constraints, but that'd be
- /// a bigger set and the data structures are not setup for that. If
- /// we wind up keeping some form of this check long term, it would
- /// probably be better to remove the snapshot parameter and to
- /// refactor the constraint set.
+ /// The leak checker works by searching for the following error patterns:
+ ///
+ /// * P1: P2, where P1 != P2
+ /// * P1: R, where R is in some universe that cannot name P1
+ ///
+ /// The idea here is that each of these patterns represents something that
+ /// the region solver would eventually report as an error, so we can detect
+ /// the error early. There is a fly in the ointment, though, in that this is
+ /// not entirely true. In particular, in the future, we may extend the
+ /// environment with implied bounds or other info about how placeholders
+ /// relate to regions in outer universes. In that case, `P1: R` for example
+ /// might become solveable.
+ ///
+ /// # Summary of the implementation
+ ///
+ /// The leak checks as follows. First, we construct a graph where `R2: R1`
+ /// implies `R2 -> R1`, and we compute the SCCs.
+ ///
+ /// For each SCC S, we compute:
+ ///
+ /// * what placeholder P it must be equal to, if any
+ /// * if there are multiple placeholders that must be equal, report an error because `P1: P2`
+ /// * the minimum universe of its constituents
+ ///
+ /// Then we walk the SCCs in dependency order and compute
+ ///
+ /// * what placeholder they must outlive transitively
+ /// * if they must also be equal to a placeholder, report an error because `P1: P2`
+ /// * minimum universe U of all SCCs they must outlive
+ /// * if they must also be equal to a placeholder P, and U cannot name P, report an error, as that
+ /// indicates `P: R` and `R` is in an incompatible universe
+ ///
+ /// # Historical note
+ ///
+ /// Older variants of the leak check used to report errors for these
+ /// patterns, but we no longer do:
+ ///
+ /// * R: P1, even if R cannot name P1, because R = 'static is a valid sol'n
+ /// * R: P1, R: P2, as above
pub fn leak_check(
&mut self,
tcx: TyCtxt<'tcx>,
overly_polymorphic: bool,
- placeholder_map: &PlaceholderMap<'tcx>,
- _snapshot: &CombinedSnapshot<'_, 'tcx>,
+ max_universe: ty::UniverseIndex,
+ snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> RelateResult<'tcx, ()> {
- debug!("leak_check(placeholders={:?})", placeholder_map);
+ debug!(
+ "leak_check(max_universe={:?}, snapshot.universe={:?}, overly_polymorphic={:?})",
+ max_universe, snapshot.universe, overly_polymorphic
+ );
assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
- // Go through each placeholder that we created.
- for &placeholder_region in placeholder_map.values() {
- // Find the universe this placeholder inhabits.
- let placeholder = match placeholder_region {
- ty::RePlaceholder(p) => p,
- _ => bug!("leak_check: expected placeholder found {:?}", placeholder_region,),
- };
-
- // Find all regions that are related to this placeholder
- // in some way. This means any region that either outlives
- // or is outlived by a placeholder.
- let mut taint_set = TaintSet::new(TaintDirections::both(), placeholder_region);
- taint_set.fixed_point(
- tcx,
- self.undo_log.region_constraints(),
- &self.storage.data.verifys,
- );
- let tainted_regions = taint_set.into_set();
-
- // Report an error if two placeholders in the same universe
- // are related to one another, or if a placeholder is related
- // to something from a parent universe.
- for &tainted_region in &tainted_regions {
- if let ty::RePlaceholder(_) = tainted_region {
- // Two placeholders cannot be related:
- if tainted_region == placeholder_region {
- continue;
- }
- } else if self.universe(tainted_region).can_name(placeholder.universe) {
- continue;
- }
-
- return Err(if overly_polymorphic {
- debug!("overly polymorphic!");
- TypeError::RegionsOverlyPolymorphic(placeholder.name, tainted_region)
- } else {
- debug!("not as polymorphic!");
- TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, tainted_region)
- });
- }
+ let universe_at_start_of_snapshot = snapshot.universe;
+ if universe_at_start_of_snapshot == max_universe {
+ return Ok(());
}
+ let mini_graph =
+ &MiniGraph::new(tcx, self.undo_log.region_constraints(), &self.storage.data.verifys);
+
+ let mut leak_check = LeakCheck::new(
+ tcx,
+ universe_at_start_of_snapshot,
+ max_universe,
+ overly_polymorphic,
+ mini_graph,
+ self,
+ );
+ leak_check.assign_placeholder_values()?;
+ leak_check.propagate_scc_value()?;
Ok(())
}
}
-#[derive(Debug)]
-struct TaintSet<'tcx> {
- directions: TaintDirections,
- regions: FxHashSet<ty::Region<'tcx>>,
+struct LeakCheck<'me, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ universe_at_start_of_snapshot: ty::UniverseIndex,
+ overly_polymorphic: bool,
+ mini_graph: &'me MiniGraph<'tcx>,
+ rcc: &'me RegionConstraintCollector<'me, 'tcx>,
+
+ // Initially, for each SCC S, stores a placeholder `P` such that `S = P`
+ // must hold.
+ //
+ // Later, during the [`LeakCheck::propagate_scc_value`] function, this array
+ // is repurposed to store some placeholder `P` such that the weaker
+ // condition `S: P` must hold. (This is true if `S: S1` transitively and `S1
+ // = P`.)
+ scc_placeholders: IndexVec<LeakCheckScc, Option<ty::PlaceholderRegion>>,
+
+ // For each SCC S, track the minimum universe that flows into it. Note that
+ // this is both the minimum of the universes for every region that is a
+ // member of the SCC, but also if you have `R1: R2`, then the universe of
+ // `R2` must be less than the universe of `R1` (i.e., `R1` flows `R2`). To
+ // see that, imagine that you have `P1: R` -- in that case, `R` must be
+ // either the placeholder `P1` or the empty region in that same universe.
+ //
+ // To detect errors, we look for an SCC S where the values in
+ // `scc_values[S]` (if any) cannot be stored into `scc_universes[S]`.
+ scc_universes: IndexVec<LeakCheckScc, SccUniverse<'tcx>>,
}
-impl<'tcx> TaintSet<'tcx> {
- fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self {
- let mut regions = FxHashSet::default();
- regions.insert(initial_region);
- TaintSet { directions, regions }
+impl<'me, 'tcx> LeakCheck<'me, 'tcx> {
+ fn new(
+ tcx: TyCtxt<'tcx>,
+ universe_at_start_of_snapshot: ty::UniverseIndex,
+ max_universe: ty::UniverseIndex,
+ overly_polymorphic: bool,
+ mini_graph: &'me MiniGraph<'tcx>,
+ rcc: &'me RegionConstraintCollector<'me, 'tcx>,
+ ) -> Self {
+ let dummy_scc_universe = SccUniverse { universe: max_universe, region: None };
+ Self {
+ tcx,
+ universe_at_start_of_snapshot,
+ overly_polymorphic,
+ mini_graph,
+ rcc,
+ scc_placeholders: IndexVec::from_elem_n(None, mini_graph.sccs.num_sccs()),
+ scc_universes: IndexVec::from_elem_n(dummy_scc_universe, mini_graph.sccs.num_sccs()),
+ }
+ }
+
+ /// Compute what placeholders (if any) each SCC must be equal to.
+ /// Also compute the minimum universe of all the regions in each SCC.
+ fn assign_placeholder_values(&mut self) -> RelateResult<'tcx, ()> {
+ // First walk: find each placeholder that is from a newly created universe.
+ for (region, leak_check_node) in &self.mini_graph.nodes {
+ let scc = self.mini_graph.sccs.scc(*leak_check_node);
+
+ // Set the universe of each SCC to be the minimum of its constituent universes
+ let universe = self.rcc.universe(region);
+ debug!(
+ "assign_placeholder_values: scc={:?} universe={:?} region={:?}",
+ scc, universe, region
+ );
+ self.scc_universes[scc].take_min(universe, region);
+
+ // Detect those SCCs that directly contain a placeholder
+ if let ty::RePlaceholder(placeholder) = region {
+ if self.universe_at_start_of_snapshot.cannot_name(placeholder.universe) {
+ self.assign_scc_value(scc, *placeholder)?;
+ }
+ }
+ }
+
+ Ok(())
}
- fn fixed_point<'a>(
+ // assign_scc_value(S, P): Update `scc_values` to account for the fact that `P: S` must hold.
+ // This may create an error.
+ fn assign_scc_value(
&mut self,
- tcx: TyCtxt<'tcx>,
- undo_log: impl IntoIterator<Item = &'a UndoLog<'tcx>> + Clone,
- verifys: &[Verify<'tcx>],
- ) where
- 'tcx: 'a,
- {
- let mut prev_len = 0;
- while prev_len < self.len() {
- debug!("tainted: prev_len = {:?} new_len = {:?}", prev_len, self.len());
-
- prev_len = self.len();
-
- for undo_entry in undo_log.clone() {
- match undo_entry {
- &AddConstraint(Constraint::VarSubVar(a, b)) => {
- self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
- }
- &AddConstraint(Constraint::RegSubVar(a, b)) => {
- self.add_edge(a, tcx.mk_region(ReVar(b)));
- }
- &AddConstraint(Constraint::VarSubReg(a, b)) => {
- self.add_edge(tcx.mk_region(ReVar(a)), b);
- }
- &AddConstraint(Constraint::RegSubReg(a, b)) => {
- self.add_edge(a, b);
- }
- &AddGiven(a, b) => {
- self.add_edge(a, tcx.mk_region(ReVar(b)));
- }
- &AddVerify(i) => span_bug!(
- verifys[i].origin.span(),
- "we never add verifications while doing higher-ranked things",
- ),
- &Purged | &AddCombination(..) | &AddVar(..) => {}
+ scc: LeakCheckScc,
+ placeholder: ty::PlaceholderRegion,
+ ) -> RelateResult<'tcx, ()> {
+ match self.scc_placeholders[scc] {
+ Some(p) => {
+ assert_ne!(p, placeholder);
+ return Err(self.placeholder_error(p, placeholder));
+ }
+ None => {
+ self.scc_placeholders[scc] = Some(placeholder);
+ }
+ };
+
+ Ok(())
+ }
+
+ /// For each SCC S, iterate over each successor S1 where `S: S1`:
+ ///
+ /// * Compute
+ /// Iterate over each SCC `S` and ensure that, for each `S1` where `S1: S`,
+ /// `universe(S) <= universe(S1)`. This executes after
+ /// `assign_placeholder_values`, so `universe(S)` is already the minimum
+ /// universe of any of its direct constituents.
+ fn propagate_scc_value(&mut self) -> RelateResult<'tcx, ()> {
+ // Loop invariants:
+ //
+ // On start of the loop iteration for `scc1`:
+ //
+ // * `scc_universes[scc1]` contains the minimum universe of the
+ // constituents of `scc1`
+ // * `scc_placeholder[scc1]` stores the placeholder that `scc1` must
+ // be equal to (if any)
+ //
+ // For each succssor `scc2` where `scc1: scc2`:
+ //
+ // * `scc_placeholder[scc2]` stores some placeholder `P` where
+ // `scc2: P` (if any)
+ // * `scc_universes[scc2]` contains the minimum universe of the
+ // constituents of `scc2` and any of its successors
+ for scc1 in self.mini_graph.sccs.all_sccs() {
+ debug!(
+ "propagate_scc_value: scc={:?} with universe {:?}",
+ scc1, self.scc_universes[scc1]
+ );
+
+ // Walk over each `scc2` such that `scc1: scc2` and compute:
+ //
+ // * `scc1_universe`: the minimum universe of `scc2` and the constituents of `scc1`
+ // * `succ_bound`: placeholder `P` that the successors must outlive, if any (if there are multiple,
+ // we pick one arbitrarily)
+ let mut scc1_universe = self.scc_universes[scc1];
+ let mut succ_bound = None;
+ for &scc2 in self.mini_graph.sccs.successors(scc1) {
+ let SccUniverse { universe: scc2_universe, region: scc2_region } =
+ self.scc_universes[scc2];
+
+ scc1_universe.take_min(scc2_universe, scc2_region.unwrap());
+
+ if let Some(b) = self.scc_placeholders[scc2] {
+ succ_bound = Some(b);
}
}
+
+ // Update minimum universe of scc1.
+ self.scc_universes[scc1] = scc1_universe;
+
+ // At this point, `scc_placholder[scc1]` stores the placeholder that
+ // `scc1` must be equal to, if any.
+ if let Some(scc1_placeholder) = self.scc_placeholders[scc1] {
+ debug!(
+ "propagate_scc_value: scc1={:?} placeholder={:?} scc1_universe={:?}",
+ scc1, scc1_placeholder, scc1_universe
+ );
+
+ // Check if `P1: R` for some `R` in a universe that cannot name
+ // P1. That's an error.
+ if scc1_universe.universe.cannot_name(scc1_placeholder.universe) {
+ return Err(self.error(scc1_placeholder, scc1_universe.region.unwrap()));
+ }
+
+ // Check if we have some placeholder where `S: P2`
+ // (transitively). In that case, since `S = P1`, that implies
+ // `P1: P2`, which is an error condition.
+ if let Some(scc2_placeholder) = succ_bound {
+ assert_ne!(scc1_placeholder, scc2_placeholder);
+ return Err(self.placeholder_error(scc1_placeholder, scc2_placeholder));
+ }
+ } else {
+ // Otherwise, we can reach a placeholder if some successor can.
+ self.scc_placeholders[scc1] = succ_bound;
+ }
+
+ // At this point, `scc_placeholder[scc1]` stores some placeholder that `scc1` must outlive (if any).
}
+ Ok(())
}
- fn into_set(self) -> FxHashSet<ty::Region<'tcx>> {
- self.regions
+ fn placeholder_error(
+ &self,
+ placeholder1: ty::PlaceholderRegion,
+ placeholder2: ty::PlaceholderRegion,
+ ) -> TypeError<'tcx> {
+ self.error(placeholder1, self.tcx.mk_region(ty::RePlaceholder(placeholder2)))
}
- fn len(&self) -> usize {
- self.regions.len()
+ fn error(
+ &self,
+ placeholder: ty::PlaceholderRegion,
+ other_region: ty::Region<'tcx>,
+ ) -> TypeError<'tcx> {
+ debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region);
+ if self.overly_polymorphic {
+ return TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region);
+ } else {
+ return TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, other_region);
+ }
}
+}
- fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) {
- if self.directions.incoming {
- if self.regions.contains(&target) {
- self.regions.insert(source);
- }
+// States we need to distinguish:
+//
+// * must be equal to a placeholder (i.e., a placeholder is in the SCC)
+// * it could conflict with some other regions in the SCC in different universes
+// * or a different placeholder
+// * `P1: S` and `S` must be equal to a placeholder
+// * `P1: S` and `S` is in an incompatible universe
+//
+// So if we
+//
+// (a) compute which placeholder (if any) each SCC must be equal to
+// (b) compute its minimum universe
+// (c) compute *some* placeholder where `S: P1` (any one will do)
+//
+// then we get an error if:
+//
+// - it must be equal to a placeholder `P1` and minimum universe cannot name `P1`
+// - `S: P1` and minimum universe cannot name `P1`
+// - `S: P1` and we must be equal to `P2`
+//
+// So we want to track:
+//
+// * Equal placeholder (if any)
+// * Some bounding placeholder (if any)
+// * Minimum universe
+//
+// * We compute equal placeholder + minimum universe of constituents in first pass
+// * Then we walk in order and compute from our dependencies `S1` where `S: S1` (`S -> S1`)
+// * bounding placeholder (if any)
+// * minimum universe
+// * And if we must be equal to a placeholder then we check it against
+// * minimum universe
+// * no bounding placeholder
+
+/// Tracks the "minimum universe" for each SCC, along with some region that
+/// caused it to change.
+#[derive(Copy, Clone, Debug)]
+struct SccUniverse<'tcx> {
+ /// For some SCC S, the minimum universe of:
+ ///
+ /// * each region R in S
+ /// * each SCC S1 such that S: S1
+ universe: ty::UniverseIndex,
+
+ /// Some region that caused `universe` to be what it is.
+ region: Option<ty::Region<'tcx>>,
+}
+
+impl<'tcx> SccUniverse<'tcx> {
+ /// If `universe` is less than our current universe, then update
+ /// `self.universe` and `self.region`.
+ fn take_min(&mut self, universe: ty::UniverseIndex, region: ty::Region<'tcx>) {
+ if universe < self.universe || self.region.is_none() {
+ self.universe = universe;
+ self.region = Some(region);
}
+ }
+}
+
+rustc_index::newtype_index! {
+ struct LeakCheckNode {
+ DEBUG_FORMAT = "LeakCheckNode({})"
+ }
+}
- if self.directions.outgoing {
- if self.regions.contains(&source) {
- self.regions.insert(target);
+rustc_index::newtype_index! {
+ struct LeakCheckScc {
+ DEBUG_FORMAT = "LeakCheckScc({})"
+ }
+}
+
+/// Represents the graph of constraints. For each `R1: R2` constraint we create
+/// an edge `R1 -> R2` in the graph.
+struct MiniGraph<'tcx> {
+ /// Map from a region to the index of the node in the graph.
+ nodes: FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
+
+ /// Map from node index to SCC, and stores the successors of each SCC. All
+ /// the regions in the same SCC are equal to one another, and if `S1 -> S2`,
+ /// then `S1: S2`.
+ sccs: Sccs<LeakCheckNode, LeakCheckScc>,
+}
+
+impl<'tcx> MiniGraph<'tcx> {
+ fn new<'a>(
+ tcx: TyCtxt<'tcx>,
+ undo_log: impl Iterator<Item = &'a UndoLog<'tcx>>,
+ verifys: &[Verify<'tcx>],
+ ) -> Self
+ where
+ 'tcx: 'a,
+ {
+ let mut nodes = FxHashMap::default();
+ let mut edges = Vec::new();
+
+ // Note that if `R2: R1`, we get a callback `r1, r2`, so `target` is first parameter.
+ Self::iterate_undo_log(tcx, undo_log, verifys, |target, source| {
+ let source_node = Self::add_node(&mut nodes, source);
+ let target_node = Self::add_node(&mut nodes, target);
+ edges.push((source_node, target_node));
+ });
+ let graph = VecGraph::new(nodes.len(), edges);
+ let sccs = Sccs::new(&graph);
+ Self { nodes, sccs }
+ }
+
+ /// Invokes `each_edge(R1, R2)` for each edge where `R2: R1`
+ fn iterate_undo_log<'a>(
+ tcx: TyCtxt<'tcx>,
+ undo_log: impl Iterator<Item = &'a UndoLog<'tcx>>,
+ verifys: &[Verify<'tcx>],
+ mut each_edge: impl FnMut(ty::Region<'tcx>, ty::Region<'tcx>),
+ ) where
+ 'tcx: 'a,
+ {
+ for undo_entry in undo_log {
+ match undo_entry {
+ &AddConstraint(Constraint::VarSubVar(a, b)) => {
+ each_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
+ }
+ &AddConstraint(Constraint::RegSubVar(a, b)) => {
+ each_edge(a, tcx.mk_region(ReVar(b)));
+ }
+ &AddConstraint(Constraint::VarSubReg(a, b)) => {
+ each_edge(tcx.mk_region(ReVar(a)), b);
+ }
+ &AddConstraint(Constraint::RegSubReg(a, b)) => {
+ each_edge(a, b);
+ }
+ &AddGiven(a, b) => {
+ each_edge(a, tcx.mk_region(ReVar(b)));
+ }
+ &AddVerify(i) => span_bug!(
+ verifys[i].origin.span(),
+ "we never add verifications while doing higher-ranked things",
+ ),
+ &AddCombination(..) | &AddVar(..) => {}
}
}
}
+
+ fn add_node(
+ nodes: &mut FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
+ r: ty::Region<'tcx>,
+ ) -> LeakCheckNode {
+ let l = nodes.len();
+ *nodes.entry(r).or_insert(LeakCheckNode::new(l))
+ }
}
/// R1 <= R2 and R2 <= R1 and (b) we unify the two regions in this
/// table. You can then call `opportunistic_resolve_var` early
/// which will map R1 and R2 to some common region (i.e., either
- /// R1 or R2). This is important when dropck and other such code
- /// is iterating to a fixed point, because otherwise we sometimes
- /// would wind up with a fresh stream of region variables that
- /// have been equated but appear distinct.
+ /// R1 or R2). This is important when fulfillment, dropck and other such
+ /// code is iterating to a fixed point, because otherwise we sometimes
+ /// would wind up with a fresh stream of region variables that have been
+ /// equated but appear distinct.
pub(super) unification_table: ut::UnificationTableStorage<ty::RegionVid>,
/// a flag set to true when we perform any unifications; this is used
/// We added a GLB/LUB "combination variable".
AddCombination(CombineMapType, TwoRegions<'tcx>),
-
- /// During skolemization, we sometimes purge entries from the undo
- /// log in a kind of minisnapshot (unlike other snapshots, this
- /// purging actually takes place *on success*). In that case, we
- /// replace the corresponding entry with `Noop` so as to avoid the
- /// need to do a bunch of swapping. (We can't use `swap_remove` as
- /// the order of the vector is important.)
- Purged,
}
#[derive(Copy, Clone, PartialEq)]
fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) {
match undo_entry {
- Purged => {
- // nothing to do here
- }
AddVar(vid) => {
self.var_infos.pop().unwrap();
assert_eq!(self.var_infos.len(), vid.index() as usize);
self.var_infos[vid].origin
}
- /// Removes all the edges to/from the placeholder regions that are
- /// in `skols`. This is used after a higher-ranked operation
- /// completes to remove all trace of the placeholder regions
- /// created in that time.
- pub fn pop_placeholders(&mut self, placeholders: &FxHashSet<ty::Region<'tcx>>) {
- debug!("pop_placeholders(placeholders={:?})", placeholders);
-
- assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
-
- let constraints_to_kill: Vec<usize> = self
- .undo_log
- .iter()
- .enumerate()
- .rev()
- .filter(|&(_, undo_entry)| match undo_entry {
- super::UndoLog::RegionConstraintCollector(undo_entry) => {
- kill_constraint(placeholders, undo_entry)
- }
- _ => false,
- })
- .map(|(index, _)| index)
- .collect();
-
- for index in constraints_to_kill {
- let undo_entry = match &mut self.undo_log[index] {
- super::UndoLog::RegionConstraintCollector(undo_entry) => {
- mem::replace(undo_entry, Purged)
- }
- _ => unreachable!(),
- };
- self.rollback_undo_entry(undo_entry);
- }
-
- return;
-
- fn kill_constraint<'tcx>(
- placeholders: &FxHashSet<ty::Region<'tcx>>,
- undo_entry: &UndoLog<'tcx>,
- ) -> bool {
- match undo_entry {
- &AddConstraint(Constraint::VarSubVar(..)) => false,
- &AddConstraint(Constraint::RegSubVar(a, _)) => placeholders.contains(&a),
- &AddConstraint(Constraint::VarSubReg(_, b)) => placeholders.contains(&b),
- &AddConstraint(Constraint::RegSubReg(a, b)) => {
- placeholders.contains(&a) || placeholders.contains(&b)
- }
- &AddGiven(..) => false,
- &AddVerify(_) => false,
- &AddCombination(_, ref two_regions) => {
- placeholders.contains(&two_regions.a) || placeholders.contains(&two_regions.b)
- }
- &AddVar(..) | &Purged => false,
- }
- }
- }
-
fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) {
// cannot add constraints once regions are resolved
debug!("RegionConstraintCollector: add_constraint({:?})", constraint);
}
}
- pub fn opportunistic_resolve_var(
- &mut self,
- tcx: TyCtxt<'tcx>,
- rid: RegionVid,
- ) -> ty::Region<'tcx> {
- let vid = self.unification_table().probe_value(rid).min_vid;
- tcx.mk_region(ty::ReVar(vid))
+ pub fn opportunistic_resolve_var(&mut self, rid: RegionVid) -> ty::RegionVid {
+ self.unification_table().probe_value(rid).min_vid
}
fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> {
}
}
-/// The opportunistic type and region resolver is similar to the
-/// opportunistic type resolver, but also opportunistically resolves
-/// regions. It is useful for canonicalization.
-pub struct OpportunisticTypeAndRegionResolver<'a, 'tcx> {
+/// The opportunistic region resolver opportunistically resolves regions
+/// variables to the variable with the least variable id. It is used when
+/// normlizing projections to avoid hitting the recursion limit by creating
+/// many versions of a predicate for types that in the end have to unify.
+///
+/// If you want to resolve type and const variables as well, call
+/// [InferCtxt::resolve_vars_if_possible] first.
+pub struct OpportunisticRegionResolver<'a, 'tcx> {
infcx: &'a InferCtxt<'a, 'tcx>,
}
-impl<'a, 'tcx> OpportunisticTypeAndRegionResolver<'a, 'tcx> {
+impl<'a, 'tcx> OpportunisticRegionResolver<'a, 'tcx> {
pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
- OpportunisticTypeAndRegionResolver { infcx }
+ OpportunisticRegionResolver { infcx }
}
}
-impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticTypeAndRegionResolver<'a, 'tcx> {
+impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if !t.needs_infer() {
+ if !t.has_infer_regions() {
t // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
- let t0 = self.infcx.shallow_resolve(t);
- t0.super_fold_with(self)
+ t.super_fold_with(self)
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
- ty::ReVar(rid) => self
- .infcx
- .inner
- .borrow_mut()
- .unwrap_region_constraints()
- .opportunistic_resolve_var(self.tcx(), rid),
+ ty::ReVar(rid) => {
+ let resolved = self
+ .infcx
+ .inner
+ .borrow_mut()
+ .unwrap_region_constraints()
+ .opportunistic_resolve_var(rid);
+ self.tcx().reuse_or_mk_region(r, ty::ReVar(resolved))
+ }
_ => r,
}
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- if !ct.needs_infer() {
+ if !ct.has_infer_regions() {
ct // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
- let c0 = self.infcx.shallow_resolve(ct);
- c0.super_fold_with(self)
+ ct.super_fold_with(self)
}
}
}
match t.kind {
ty::Infer(ty::TyVar(vid)) => {
self.err = Some(FixupError::UnresolvedTy(vid));
- self.tcx().types.err
+ self.tcx().ty_error()
}
ty::Infer(ty::IntVar(vid)) => {
self.err = Some(FixupError::UnresolvedIntTy(vid));
- self.tcx().types.err
+ self.tcx().ty_error()
}
ty::Infer(ty::FloatVar(vid)) => {
self.err = Some(FixupError::UnresolvedFloatTy(vid));
- self.tcx().types.err
+ self.tcx().ty_error()
}
ty::Infer(_) => {
bug!("Unexpected type in full type resolver: {:?}", t);
match c.val {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
self.err = Some(FixupError::UnresolvedConst(vid));
- return self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: c.ty });
+ return self.tcx().const_error(c.ty);
}
ty::ConstKind::Infer(InferConst::Fresh(_)) => {
bug!("Unexpected const in full const resolver: {:?}", c);
Ok(a)
}
- (&ty::Error, _) | (_, &ty::Error) => {
+ (&ty::Error(_), _) | (_, &ty::Error(_)) => {
infcx.set_tainted_by_errors();
- Ok(self.tcx().types.err)
+ Ok(self.tcx().ty_error())
}
_ => {
assert!(self.logs.len() >= snapshot.undo_len);
assert!(self.num_open_snapshots > 0);
}
-
- pub(crate) fn iter(&self) -> std::slice::Iter<'_, UndoLog<'tcx>> {
- self.logs.iter()
- }
}
impl<'tcx> std::ops::Index<usize> for InferCtxtUndoLogs<'tcx> {
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
+#![feature(const_fn)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
+#![feature(const_panic)]
#![feature(extend_one)]
#![feature(never_type)]
#![feature(or_patterns)]
Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey,
ProjectionCacheStorage, Reveal,
};
-crate use self::util::elaborate_predicates;
-
pub use rustc_middle::traits::*;
-/// An `Obligation` represents some trait reference (e.g., `int: Eq`) for
+/// An `Obligation` represents some trait reference (e.g., `i32: Eq`) for
/// which the "impl_source" must be found. The process of finding a "impl_source" is
/// called "resolving" the `Obligation`. This process consists of
-/// either identifying an `impl` (e.g., `impl Eq for int`) that
+/// either identifying an `impl` (e.g., `impl Eq for i32`) that
/// satisfies the obligation, or else finding a bound that is in
/// scope. The eventual result is usually a `Selection` (defined below).
#[derive(Clone, PartialEq, Eq, Hash)]
fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool {
// We have to be careful here because we want
//
- // for<'a> Foo<&'a int>
+ // for<'a> Foo<&'a i32>
//
// and
//
- // for<'b> Foo<&'b int>
+ // for<'b> Foo<&'b i32>
//
// to be considered equivalent. So normalize all late-bound
// regions before we throw things into the underlying set.
}
pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
+ log::trace!("run_compiler");
let stderr = config.stderr.take();
util::spawn_thread_pool(
config.opts.edition,
krate: ast::Crate,
crate_name: &str,
) -> Result<(ast::Crate, BoxedResolver)> {
+ log::trace!("configure_and_expand");
// Currently, we ignore the name resolution data structures for the purposes of dependency
// tracking. Instead we will run name resolution and include its output in the hash of each
// item, much like we do for macro expansion. In other words, the hash reflects not just
resolver_arenas: &'a ResolverArenas<'a>,
metadata_loader: &'a MetadataLoaderDyn,
) -> Result<(ast::Crate, Resolver<'a>)> {
+ log::trace!("configure_and_expand_inner");
pre_expansion_lint(sess, lint_store, &krate);
let mut resolver = Resolver::new(sess, &krate, crate_name, metadata_loader, &resolver_arenas);
should_loop |= true;
}
if should_loop {
+ log::debug!("replacing bodies with loop {{}}");
util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate);
}
filename.to_string().replace(" ", "\\ ")
}
+// Makefile comments only need escaping newlines and `\`.
+// The result can be unescaped by anything that can unescape `escape_default` and friends.
+fn escape_dep_env(symbol: Symbol) -> String {
+ let s = symbol.as_str();
+ let mut escaped = String::with_capacity(s.len());
+ for c in s.chars() {
+ match c {
+ '\n' => escaped.push_str(r"\n"),
+ '\r' => escaped.push_str(r"\r"),
+ '\\' => escaped.push_str(r"\\"),
+ _ => escaped.push(c),
+ }
+ }
+ escaped
+}
+
fn write_out_deps(
sess: &Session,
boxed_resolver: &Steal<Rc<RefCell<BoxedResolver>>>,
for path in files {
writeln!(file, "{}:", path)?;
}
+
+ // Emit special comments with information about accessed environment variables.
+ let env_depinfo = sess.parse_sess.env_depinfo.borrow();
+ if !env_depinfo.is_empty() {
+ let mut envs: Vec<_> = env_depinfo
+ .iter()
+ .map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env)))
+ .collect();
+ envs.sort_unstable();
+ writeln!(file)?;
+ for (k, v) in envs {
+ write!(file, "# env-dep:{}", k)?;
+ if let Some(v) = v {
+ write!(file, "={}", v)?;
+ }
+ writeln!(file)?;
+ }
+ }
+
Ok(())
})();
arena: &'tcx WorkerLocal<Arena<'tcx>>,
) -> QueryContext<'tcx> {
let sess = &compiler.session();
- let defs: &'tcx Definitions = arena.alloc(mem::take(&mut resolver_outputs.definitions));
+ let defs: &'tcx Definitions = arena.alloc(mem::replace(
+ &mut resolver_outputs.definitions,
+ Definitions::new(crate_name, sess.local_crate_disambiguator()),
+ ));
let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
pub fn expansion(
&self,
) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> {
+ log::trace!("expansion");
self.expansion.compute(|| {
let crate_name = self.crate_name()?.peek().clone();
let (krate, lint_store) = self.register_plugins()?.take();
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
-use rustc_session::config::{Externs, OutputType, OutputTypes, Sanitizer, SymbolManglingVersion};
+use rustc_session::config::{
+ Externs, OutputType, OutputTypes, SanitizerSet, SymbolManglingVersion,
+};
use rustc_session::lint::Level;
use rustc_session::search_paths::SearchPath;
use rustc_session::utils::NativeLibKind;
untracked!(ast_json_noexpand, true);
untracked!(borrowck, String::from("other"));
untracked!(borrowck_stats, true);
- untracked!(control_flow_guard, CFGuard::Checks);
untracked!(deduplicate_diagnostics, true);
untracked!(dep_tasks, true);
untracked!(dont_buffer_diagnostics, true);
tracked!(binary_dep_depinfo, true);
tracked!(chalk, true);
tracked!(codegen_backend, Some("abc".to_string()));
+ tracked!(control_flow_guard, CFGuard::Checks);
tracked!(crate_attr, vec!["abc".to_string()]);
tracked!(debug_macros, true);
tracked!(dep_info_omit_d_target, true);
tracked!(human_readable_cgu_names, true);
tracked!(inline_in_all_cgus, Some(true));
tracked!(insert_sideeffect, true);
+ tracked!(instrument_coverage, true);
tracked!(instrument_mcount, true);
tracked!(link_only, true);
tracked!(merge_functions, Some(MergeFunctions::Disabled));
tracked!(relro_level, Some(RelroLevel::Full));
tracked!(report_delayed_bugs, true);
tracked!(run_dsymutil, false);
- tracked!(sanitizer, Some(Sanitizer::Address));
+ tracked!(sanitizer, SanitizerSet::ADDRESS);
tracked!(sanitizer_memory_track_origins, 2);
- tracked!(sanitizer_recover, vec![Sanitizer::Address]);
+ tracked!(sanitizer_recover, SanitizerSet::ADDRESS);
tracked!(saturating_float_casts, Some(true));
tracked!(share_generics, Some(true));
tracked!(show_span, Some(String::from("abc")));
/// but shebang isn't a part of rust syntax.
pub fn strip_shebang(input: &str) -> Option<usize> {
// Shebang must start with `#!` literally, without any preceding whitespace.
- if input.starts_with("#!") {
- let input_tail = &input[2..];
- // Shebang must have something non-whitespace after `#!` on the first line.
- let first_line_tail = input_tail.lines().next()?;
- if first_line_tail.contains(|c| !is_whitespace(c)) {
- // Ok, this is a shebang but if the next non-whitespace token is `[` or maybe
- // a doc comment (due to `TokenKind::(Line,Block)Comment` ambiguity at lexer level),
- // then it may be valid Rust code, so consider it Rust code.
- let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok|
- !matches!(tok, TokenKind::Whitespace | TokenKind::LineComment | TokenKind::BlockComment { .. })
- );
- if next_non_whitespace_token != Some(TokenKind::OpenBracket) {
- // No other choice than to consider this a shebang.
- return Some(2 + first_line_tail.len());
- }
+ // For simplicity we consider any line starting with `#!` a shebang,
+ // regardless of restrictions put on shebangs by specific platforms.
+ if let Some(input_tail) = input.strip_prefix("#!") {
+ // Ok, this is a shebang but if the next non-whitespace token is `[` or maybe
+ // a doc comment (due to `TokenKind::(Line,Block)Comment` ambiguity at lexer level),
+ // then it may be valid Rust code, so consider it Rust code.
+ let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok|
+ !matches!(tok, TokenKind::Whitespace | TokenKind::LineComment | TokenKind::BlockComment { .. })
+ );
+ if next_non_whitespace_token != Some(TokenKind::OpenBracket) {
+ // No other choice than to consider this a shebang.
+ return Some(2 + input_tail.lines().next().unwrap_or_default().len());
}
}
None
[dependencies]
log = "0.4"
-unicode-security = "0.0.3"
+unicode-security = "0.0.5"
rustc_middle = { path = "../librustc_middle" }
rustc_ast_pretty = { path = "../librustc_ast_pretty" }
rustc_attr = { path = "../librustc_attr" }
// Check if the method call actually calls the libcore
// `IntoIterator::into_iter`.
- let def_id = cx.tables.type_dependent_def_id(expr.hir_id).unwrap();
+ let def_id = cx.tables().type_dependent_def_id(expr.hir_id).unwrap();
match cx.tcx.trait_of_item(def_id) {
Some(trait_id) if cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_id) => {}
_ => return,
// `Box` is the only thing that values can be moved out of via
// method call. `Box::new([1]).into_iter()` should trigger this
// lint.
- let mut recv_ty = cx.tables.expr_ty(receiver_arg);
+ let mut recv_ty = cx.tables().expr_ty(receiver_arg);
let mut num_box_derefs = 0;
while recv_ty.is_box() {
num_box_derefs += 1;
// Make sure that there is an autoref coercion at the expected
// position. The first `num_box_derefs` adjustments are the derefs
// of the box.
- match cx.tables.expr_adjustments(receiver_arg).get(num_box_derefs) {
+ match cx.tables().expr_adjustments(receiver_arg).get(num_box_derefs) {
Some(Adjustment { kind: Adjust::Borrow(_), .. }) => {}
_ => return,
}
// Emit lint diagnostic.
- let target = match cx.tables.expr_ty_adjusted(receiver_arg).kind {
+ let target = match cx.tables().expr_ty_adjusted(receiver_arg).kind {
ty::Ref(_, ty::TyS { kind: ty::Array(..), .. }, _) => "[T; N]",
ty::Ref(_, ty::TyS { kind: ty::Slice(..), .. }, _) => "[T]",
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast::visit::{FnCtxt, FnKind};
use rustc_ast_pretty::pprust::{self, expr_to_string};
-use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType};
use rustc_feature::{GateIssue, Stability};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
-use rustc_hir::{GenericParamKind, PatKind};
-use rustc_hir::{HirIdSet, Node};
+use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind};
+use rustc_hir::{HirId, HirIdSet, Node};
use rustc_middle::lint::LintDiagnosticBuilder;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Ty, TyCtxt};
use crate::nonstandard_style::{method_context, MethodLateContext};
-use log::debug;
+use log::{debug, trace};
use std::fmt::Write;
// hardwired lints from librustc_middle
}
fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr<'_>) {
- let ty = cx.tables.node_type(e.hir_id);
+ let ty = cx.tables().node_type(e.hir_id);
self.check_heap_type(cx, e.span, ty);
}
}
fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat<'_>) {
if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind {
let variant = cx
- .tables
+ .tables()
.pat_ty(pat)
.ty_adt_def()
.expect("struct pattern type is not an ADT")
- .variant_of_res(cx.tables.qpath_res(qpath, pat.hir_id));
+ .variant_of_res(cx.tables().qpath_res(qpath, pat.hir_id));
for fieldpat in field_pats {
if fieldpat.is_shorthand {
continue;
}
if let PatKind::Binding(binding_annot, _, ident, None) = fieldpat.pat.kind {
if cx.tcx.find_field_index(ident, &variant)
- == Some(cx.tcx.field_index(fieldpat.hir_id, cx.tables))
+ == Some(cx.tcx.field_index(fieldpat.hir_id, cx.tables()))
{
cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| {
let mut err = lint
return;
}
let param_env = ty::ParamEnv::empty();
- if ty.is_copy_modulo_regions(cx.tcx, param_env, item.span) {
+ if ty.is_copy_modulo_regions(cx.tcx.at(item.span), param_env) {
return;
}
if can_type_implement_copy(cx.tcx, param_env, ty).is_ok() {
expr: &hir::Expr<'_>,
) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
let def = if let hir::ExprKind::Path(ref qpath) = expr.kind {
- cx.tables.qpath_res(qpath, expr.hir_id)
+ cx.tables().qpath_res(qpath, expr.hir_id)
} else {
return None;
};
if !def_id_is_transmute(cx, did) {
return None;
}
- let sig = cx.tables.node_type(expr.hir_id).fn_sig(cx.tcx);
+ let sig = cx.tables().node_type(expr.hir_id).fn_sig(cx.tcx);
let from = sig.inputs().skip_binder()[0];
let to = *sig.output().skip_binder();
return Some((from, to));
if let hir::ExprKind::Call(ref path_expr, ref args) = expr.kind {
// Find calls to `mem::{uninitialized,zeroed}` methods.
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
- let def_id = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
+ let def_id = cx.tables().qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
if cx.tcx.is_diagnostic_item(sym::mem_zeroed, def_id) {
return Some(InitKind::Zeroed);
}
} else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
// Find problematic calls to `MaybeUninit::assume_init`.
- let def_id = cx.tables.type_dependent_def_id(expr.hir_id)?;
+ let def_id = cx.tables().type_dependent_def_id(expr.hir_id)?;
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
// This is a call to *some* method named `assume_init`.
// See if the `self` parameter is one of the dangerous constructors.
if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind {
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
let def_id =
- cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
+ cx.tables().qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
if cx.tcx.is_diagnostic_item(sym::maybe_uninit_zeroed, def_id) {
return Some(InitKind::Zeroed);
// This conjures an instance of a type out of nothing,
// using zeroed or uninitialized memory.
// We are extremely conservative with what we warn about.
- let conjured_ty = cx.tables.expr_ty(expr);
+ let conjured_ty = cx.tables().expr_ty(expr);
if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty, init) {
cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
let mut err = lint.build(&format!(
}
}
}
+
+declare_lint! {
+ pub CLASHING_EXTERN_DECLARATIONS,
+ Warn,
+ "detects when an extern fn has been declared with the same name but different types"
+}
+
+pub struct ClashingExternDeclarations {
+ seen_decls: FxHashMap<Symbol, HirId>,
+}
+
+/// Differentiate between whether the name for an extern decl came from the link_name attribute or
+/// just from declaration itself. This is important because we don't want to report clashes on
+/// symbol name if they don't actually clash because one or the other links against a symbol with a
+/// different name.
+enum SymbolName {
+ /// The name of the symbol + the span of the annotation which introduced the link name.
+ Link(Symbol, Span),
+ /// No link name, so just the name of the symbol.
+ Normal(Symbol),
+}
+
+impl SymbolName {
+ fn get_name(&self) -> Symbol {
+ match self {
+ SymbolName::Link(s, _) | SymbolName::Normal(s) => *s,
+ }
+ }
+}
+
+impl ClashingExternDeclarations {
+ crate fn new() -> Self {
+ ClashingExternDeclarations { seen_decls: FxHashMap::default() }
+ }
+ /// Insert a new foreign item into the seen set. If a symbol with the same name already exists
+ /// for the item, return its HirId without updating the set.
+ fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> {
+ let hid = fi.hir_id;
+
+ let name =
+ &tcx.codegen_fn_attrs(tcx.hir().local_def_id(hid)).link_name.unwrap_or(fi.ident.name);
+
+ if self.seen_decls.contains_key(name) {
+ // Avoid updating the map with the new entry when we do find a collision. We want to
+ // make sure we're always pointing to the first definition as the previous declaration.
+ // This lets us avoid emitting "knock-on" diagnostics.
+ Some(*self.seen_decls.get(name).unwrap())
+ } else {
+ self.seen_decls.insert(*name, hid)
+ }
+ }
+
+ /// Get the name of the symbol that's linked against for a given extern declaration. That is,
+ /// the name specified in a #[link_name = ...] attribute if one was specified, else, just the
+ /// symbol's name.
+ fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName {
+ let did = tcx.hir().local_def_id(fi.hir_id);
+ if let Some((overridden_link_name, overridden_link_name_span)) =
+ tcx.codegen_fn_attrs(did).link_name.map(|overridden_link_name| {
+ // FIXME: Instead of searching through the attributes again to get span
+ // information, we could have codegen_fn_attrs also give span information back for
+ // where the attribute was defined. However, until this is found to be a
+ // bottleneck, this does just fine.
+ (
+ overridden_link_name,
+ tcx.get_attrs(did.to_def_id())
+ .iter()
+ .find(|at| at.check_name(sym::link_name))
+ .unwrap()
+ .span,
+ )
+ })
+ {
+ SymbolName::Link(overridden_link_name, overridden_link_name_span)
+ } else {
+ SymbolName::Normal(fi.ident.name)
+ }
+ }
+
+ /// Checks whether two types are structurally the same enough that the declarations shouldn't
+ /// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
+ /// with the same members (as the declarations shouldn't clash).
+ fn structurally_same_type<'a, 'tcx>(
+ cx: &LateContext<'a, 'tcx>,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>,
+ ) -> bool {
+ let tcx = cx.tcx;
+ if a == b || rustc_middle::ty::TyS::same_type(a, b) {
+ // All nominally-same types are structurally same, too.
+ true
+ } else {
+ // Do a full, depth-first comparison between the two.
+ use rustc_middle::ty::TyKind::*;
+ let a_kind = &a.kind;
+ let b_kind = &b.kind;
+
+ match (a_kind, b_kind) {
+ (Adt(..), Adt(..)) => {
+ // Adts are pretty straightforward: just compare the layouts.
+ use rustc_target::abi::LayoutOf;
+ let a_layout = cx.layout_of(a).unwrap().layout;
+ let b_layout = cx.layout_of(b).unwrap().layout;
+ a_layout == b_layout
+ }
+ (Array(a_ty, a_const), Array(b_ty, b_const)) => {
+ // For arrays, we also check the constness of the type.
+ a_const.val == b_const.val
+ && Self::structurally_same_type(cx, a_const.ty, b_const.ty)
+ && Self::structurally_same_type(cx, a_ty, b_ty)
+ }
+ (Slice(a_ty), Slice(b_ty)) => Self::structurally_same_type(cx, a_ty, b_ty),
+ (RawPtr(a_tymut), RawPtr(b_tymut)) => {
+ a_tymut.mutbl == a_tymut.mutbl
+ && Self::structurally_same_type(cx, &a_tymut.ty, &b_tymut.ty)
+ }
+ (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
+ // For structural sameness, we don't need the region to be same.
+ a_mut == b_mut && Self::structurally_same_type(cx, a_ty, b_ty)
+ }
+ (FnDef(..), FnDef(..)) => {
+ // As we don't compare regions, skip_binder is fine.
+ let a_poly_sig = a.fn_sig(tcx);
+ let b_poly_sig = b.fn_sig(tcx);
+
+ let a_sig = a_poly_sig.skip_binder();
+ let b_sig = b_poly_sig.skip_binder();
+
+ (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
+ == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
+ && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
+ Self::structurally_same_type(cx, a, b)
+ })
+ && Self::structurally_same_type(cx, a_sig.output(), b_sig.output())
+ }
+ (Tuple(a_substs), Tuple(b_substs)) => {
+ a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| {
+ Self::structurally_same_type(cx, a_ty, b_ty)
+ })
+ }
+ // For these, it's not quite as easy to define structural-sameness quite so easily.
+ // For the purposes of this lint, take the conservative approach and mark them as
+ // not structurally same.
+ (Dynamic(..), Dynamic(..))
+ | (Error(..), Error(..))
+ | (Closure(..), Closure(..))
+ | (Generator(..), Generator(..))
+ | (GeneratorWitness(..), GeneratorWitness(..))
+ | (Projection(..), Projection(..))
+ | (Opaque(..), Opaque(..)) => false,
+ // These definitely should have been caught above.
+ (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
+ _ => false,
+ }
+ }
+ }
+}
+
+impl_lint_pass!(ClashingExternDeclarations => [CLASHING_EXTERN_DECLARATIONS]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ClashingExternDeclarations {
+ fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, this_fi: &hir::ForeignItem<'_>) {
+ trace!("ClashingExternDeclarations: check_foreign_item: {:?}", this_fi);
+ if let ForeignItemKind::Fn(..) = this_fi.kind {
+ let tcx = *&cx.tcx;
+ if let Some(existing_hid) = self.insert(tcx, this_fi) {
+ let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid));
+ let this_decl_ty = tcx.type_of(tcx.hir().local_def_id(this_fi.hir_id));
+ debug!(
+ "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
+ existing_hid, existing_decl_ty, this_fi.hir_id, this_decl_ty
+ );
+ // Check that the declarations match.
+ if !Self::structurally_same_type(cx, existing_decl_ty, this_decl_ty) {
+ let orig_fi = tcx.hir().expect_foreign_item(existing_hid);
+ let orig = Self::name_of_extern_decl(tcx, orig_fi);
+
+ // We want to ensure that we use spans for both decls that include where the
+ // name was defined, whether that was from the link_name attribute or not.
+ let get_relevant_span =
+ |fi: &hir::ForeignItem<'_>| match Self::name_of_extern_decl(tcx, fi) {
+ SymbolName::Normal(_) => fi.span,
+ SymbolName::Link(_, annot_span) => fi.span.to(annot_span),
+ };
+ // Finally, emit the diagnostic.
+ tcx.struct_span_lint_hir(
+ CLASHING_EXTERN_DECLARATIONS,
+ this_fi.hir_id,
+ get_relevant_span(this_fi),
+ |lint| {
+ let mut expected_str = DiagnosticStyledString::new();
+ expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false);
+ let mut found_str = DiagnosticStyledString::new();
+ found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true);
+
+ lint.build(&format!(
+ "`{}` redeclare{} with a different signature",
+ this_fi.ident.name,
+ if orig.get_name() == this_fi.ident.name {
+ "d".to_string()
+ } else {
+ format!("s `{}`", orig.get_name())
+ }
+ ))
+ .span_label(
+ get_relevant_span(orig_fi),
+ &format!("`{}` previously declared here", orig.get_name()),
+ )
+ .span_label(
+ get_relevant_span(this_fi),
+ "this signature doesn't match the previous declaration",
+ )
+ .note_expected_found(&"", expected_str, &"", found_str)
+ .emit()
+ },
+ );
+ }
+ }
+ }
+ }
+}
use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
use rustc_target::abi::LayoutOf;
+use std::cell::Cell;
use std::slice;
/// Information about the registered lints.
/// Type context we're checking in.
pub tcx: TyCtxt<'tcx>,
- /// Side-tables for the body we are in.
- // FIXME: Make this lazy to avoid running the TypeckTables query?
- pub tables: &'a ty::TypeckTables<'tcx>,
+ /// Current body, or `None` if outside a body.
+ pub enclosing_body: Option<hir::BodyId>,
+
+ /// Type-checking side-tables for the current body. Access using the
+ /// `tables` method, which handles querying the tables on demand.
+ // FIXME(eddyb) move all the code accessing internal fields like this,
+ // to this module, to avoid exposing it to lint logic.
+ pub(super) cached_typeck_tables: Cell<Option<&'tcx ty::TypeckTables<'tcx>>>,
+
+ // HACK(eddyb) replace this with having `Option` around `&TypeckTables`.
+ pub(super) empty_typeck_tables: &'a ty::TypeckTables<'tcx>,
/// Parameter environment for the item we are in.
pub param_env: ty::ParamEnv<'tcx>,
}
impl<'a, 'tcx> LateContext<'a, 'tcx> {
+ /// Gets the type-checking side-tables for the current body,
+ /// or empty `TypeckTables` if outside a body.
+ // FIXME(eddyb) return `Option<&'tcx ty::TypeckTables<'tcx>>`,
+ // where `None` indicates we're outside a body.
+ pub fn tables(&self) -> &'a ty::TypeckTables<'tcx> {
+ if let Some(body) = self.enclosing_body {
+ self.cached_typeck_tables.get().unwrap_or_else(|| {
+ let tables = self.tcx.body_tables(body);
+ self.cached_typeck_tables.set(Some(tables));
+ tables
+ })
+ } else {
+ self.empty_typeck_tables
+ }
+ }
+
pub fn current_lint_root(&self) -> hir::HirId {
self.last_node_with_lint_attrs
}
where
F: FnOnce(&mut Self),
{
- let push = self.context.builder.push(attrs, &self.context.lint_store);
+ let is_crate_node = id == ast::CRATE_NODE_ID;
+ let push = self.context.builder.push(attrs, &self.context.lint_store, is_crate_node);
self.check_id(id);
self.enter_attrs(attrs);
f(self);
use log::debug;
use std::any::Any;
+use std::cell::Cell;
use std::slice;
/// Extract the `LintStore` from the query context.
hir_visit::NestedVisitorMap::All(self.context.tcx.hir())
}
- fn visit_nested_body(&mut self, body: hir::BodyId) {
- let old_tables = self.context.tables;
- self.context.tables = self.context.tcx.body_tables(body);
- let body = self.context.tcx.hir().body(body);
+ fn visit_nested_body(&mut self, body_id: hir::BodyId) {
+ let old_enclosing_body = self.context.enclosing_body.replace(body_id);
+ let old_cached_typeck_tables = self.context.cached_typeck_tables.get();
+
+ // HACK(eddyb) avoid trashing `cached_typeck_tables` when we're
+ // nested in `visit_fn`, which may have already resulted in them
+ // being queried.
+ if old_enclosing_body != Some(body_id) {
+ self.context.cached_typeck_tables.set(None);
+ }
+
+ let body = self.context.tcx.hir().body(body_id);
self.visit_body(body);
- self.context.tables = old_tables;
+ self.context.enclosing_body = old_enclosing_body;
+
+ // See HACK comment above.
+ if old_enclosing_body != Some(body_id) {
+ self.context.cached_typeck_tables.set(old_cached_typeck_tables);
+ }
}
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
) {
// Wrap in tables here, not just in visit_nested_body,
// in order for `check_fn` to be able to use them.
- let old_tables = self.context.tables;
- self.context.tables = self.context.tcx.body_tables(body_id);
+ let old_enclosing_body = self.context.enclosing_body.replace(body_id);
+ let old_cached_typeck_tables = self.context.cached_typeck_tables.take();
let body = self.context.tcx.hir().body(body_id);
lint_callback!(self, check_fn, fk, decl, body, span, id);
hir_visit::walk_fn(self, fk, decl, body_id, span, id);
lint_callback!(self, check_fn_post, fk, decl, body, span, id);
- self.context.tables = old_tables;
+ self.context.enclosing_body = old_enclosing_body;
+ self.context.cached_typeck_tables.set(old_cached_typeck_tables);
}
fn visit_variant_data(
let context = LateContext {
tcx,
- tables: &ty::TypeckTables::empty(None),
+ enclosing_body: None,
+ cached_typeck_tables: Cell::new(None),
+ empty_typeck_tables: &ty::TypeckTables::empty(None),
param_env: ty::ParamEnv::empty(),
access_levels,
lint_store: unerased_lint_store(tcx),
let context = LateContext {
tcx,
- tables: &ty::TypeckTables::empty(None),
+ enclosing_body: None,
+ cached_typeck_tables: Cell::new(None),
+ empty_typeck_tables: &ty::TypeckTables::empty(None),
param_env: ty::ParamEnv::empty(),
access_levels,
lint_store: unerased_lint_store(tcx),
let mut builder = LintLevelMapBuilder { levels, tcx, store };
let krate = tcx.hir().krate();
- let push = builder.levels.push(&krate.item.attrs, &store);
+ let push = builder.levels.push(&krate.item.attrs, &store, true);
builder.levels.register_id(hir::CRATE_HIR_ID);
for macro_def in krate.exported_macros {
builder.levels.register_id(macro_def.hir_id);
/// `#[allow]`
///
/// Don't forget to call `pop`!
- pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush {
+ pub fn push(
+ &mut self,
+ attrs: &[ast::Attribute],
+ store: &LintStore,
+ is_crate_node: bool,
+ ) -> BuilderPush {
let mut specs = FxHashMap::default();
let sess = self.sess;
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
}
}
+ if !is_crate_node {
+ for (id, &(level, ref src)) in specs.iter() {
+ if !id.lint.crate_level_only {
+ continue;
+ }
+
+ let (lint_attr_name, lint_attr_span) = match *src {
+ LintSource::Node(name, span, _) => (name, span),
+ _ => continue,
+ };
+
+ let lint = builtin::UNUSED_ATTRIBUTES;
+ let (lint_level, lint_src) =
+ self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
+ struct_lint_level(
+ self.sess,
+ lint,
+ lint_level,
+ lint_src,
+ Some(lint_attr_span.into()),
+ |lint| {
+ let mut db = lint.build(&format!(
+ "{}({}) is ignored unless specified at crate level",
+ level.as_str(),
+ lint_attr_name
+ ));
+ db.emit();
+ },
+ );
+ // don't set a separate error for every lint in the group
+ break;
+ }
+ }
+
for (id, &(level, ref src)) in specs.iter() {
if level == Level::Forbid {
continue;
where
F: FnOnce(&mut Self),
{
- let push = self.levels.push(attrs, self.store);
+ let is_crate_hir = id == hir::CRATE_HIR_ID;
+ let push = self.levels.push(attrs, self.store, is_crate_hir);
if push.changed {
self.levels.register_id(id);
}
#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
+#![feature(iter_order_by)]
#![feature(never_type)]
#![feature(nll)]
#![feature(or_patterns)]
// and change this to a module lint pass
MissingDebugImplementations: MissingDebugImplementations::default(),
ArrayIntoIter: ArrayIntoIter,
+ ClashingExternDeclarations: ClashingExternDeclarations::new(),
]
);
};
$args,
[
HardwiredLints: HardwiredLints,
- ImproperCTypes: ImproperCTypes,
+ ImproperCTypesDeclarations: ImproperCTypesDeclarations,
+ ImproperCTypesDefinitions: ImproperCTypesDefinitions,
VariantSizeDifferences: VariantSizeDifferences,
BoxPointers: BoxPointers,
PathStatements: PathStatements,
use crate::{EarlyContext, EarlyLintPass, LintContext};
use rustc_ast::ast;
use rustc_data_structures::fx::FxHashMap;
-use rustc_span::symbol::{Ident, SymbolStr};
-use std::hash::{Hash, Hasher};
-use std::ops::Deref;
+use rustc_span::symbol::SymbolStr;
declare_lint! {
pub NON_ASCII_IDENTS,
Allow,
- "detects non-ASCII identifiers"
+ "detects non-ASCII identifiers",
+ crate_level_only
}
declare_lint! {
pub UNCOMMON_CODEPOINTS,
Warn,
- "detects uncommon Unicode codepoints in identifiers"
+ "detects uncommon Unicode codepoints in identifiers",
+ crate_level_only
}
-// FIXME: Change this to warn.
declare_lint! {
pub CONFUSABLE_IDENTS,
- Allow,
- "detects visually confusable pairs between identifiers"
-}
-
-declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS]);
-
-enum CowBoxSymStr {
- Interned(SymbolStr),
- Owned(Box<str>),
-}
-
-impl Deref for CowBoxSymStr {
- type Target = str;
-
- fn deref(&self) -> &str {
- match self {
- CowBoxSymStr::Interned(interned) => interned,
- CowBoxSymStr::Owned(ref owned) => owned,
- }
- }
-}
-
-impl Hash for CowBoxSymStr {
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- Hash::hash(&**self, state)
- }
-}
-
-impl PartialEq<CowBoxSymStr> for CowBoxSymStr {
- #[inline]
- fn eq(&self, other: &CowBoxSymStr) -> bool {
- PartialEq::eq(&**self, &**other)
- }
-}
-
-impl Eq for CowBoxSymStr {}
-
-fn calc_skeleton(symbol_str: SymbolStr, buffer: &'_ mut String) -> CowBoxSymStr {
- use std::mem::swap;
- use unicode_security::confusable_detection::skeleton;
- buffer.clear();
- buffer.extend(skeleton(&symbol_str));
- if symbol_str == *buffer {
- CowBoxSymStr::Interned(symbol_str)
- } else {
- let mut owned = String::new();
- swap(buffer, &mut owned);
- CowBoxSymStr::Owned(owned.into_boxed_str())
- }
+ Warn,
+ "detects visually confusable pairs between identifiers",
+ crate_level_only
}
-fn is_in_ascii_confusable_closure(c: char) -> bool {
- // FIXME: move this table to `unicode_security` crate.
- // data here corresponds to Unicode 13.
- const ASCII_CONFUSABLE_CLOSURE: &[(u64, u64)] = &[(0x00, 0x7f), (0xba, 0xba), (0x2080, 0x2080)];
- let c = c as u64;
- for &(range_start, range_end) in ASCII_CONFUSABLE_CLOSURE {
- if c >= range_start && c <= range_end {
- return true;
- }
- }
- false
+declare_lint! {
+ pub MIXED_SCRIPT_CONFUSABLES,
+ Warn,
+ "detects Unicode scripts whose mixed script confusables codepoints are solely used",
+ crate_level_only
}
-fn is_in_ascii_confusable_closure_relevant_list(c: char) -> bool {
- // FIXME: move this table to `unicode_security` crate.
- // data here corresponds to Unicode 13.
- const ASCII_CONFUSABLE_CLOSURE_RELEVANT_LIST: &[u64] = &[
- 0x22, 0x25, 0x27, 0x2f, 0x30, 0x31, 0x49, 0x4f, 0x60, 0x6c, 0x6d, 0x6e, 0x72, 0x7c, 0xba,
- 0x2080,
- ];
- let c = c as u64;
- for &item in ASCII_CONFUSABLE_CLOSURE_RELEVANT_LIST {
- if c == item {
- return true;
- }
- }
- false
-}
+declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS, MIXED_SCRIPT_CONFUSABLES]);
impl EarlyLintPass for NonAsciiIdents {
fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
use rustc_session::lint::Level;
- if cx.builder.lint_level(CONFUSABLE_IDENTS).0 == Level::Allow {
+ use rustc_span::Span;
+ use std::collections::BTreeMap;
+ use unicode_security::GeneralSecurityProfile;
+ use utils::CowBoxSymStr;
+
+ let check_non_ascii_idents = cx.builder.lint_level(NON_ASCII_IDENTS).0 != Level::Allow;
+ let check_uncommon_codepoints =
+ cx.builder.lint_level(UNCOMMON_CODEPOINTS).0 != Level::Allow;
+ let check_confusable_idents = cx.builder.lint_level(CONFUSABLE_IDENTS).0 != Level::Allow;
+ let check_mixed_script_confusables =
+ cx.builder.lint_level(MIXED_SCRIPT_CONFUSABLES).0 != Level::Allow;
+
+ if !check_non_ascii_idents
+ && !check_uncommon_codepoints
+ && !check_confusable_idents
+ && !check_mixed_script_confusables
+ {
return;
}
+
+ let mut has_non_ascii_idents = false;
let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock();
- let mut symbol_strs_and_spans = Vec::with_capacity(symbols.len());
- let mut in_fast_path = true;
- for (symbol, sp) in symbols.iter() {
- // fast path
+ for (symbol, &sp) in symbols.iter() {
let symbol_str = symbol.as_str();
- if !symbol_str.chars().all(is_in_ascii_confusable_closure) {
- // fallback to slow path.
- symbol_strs_and_spans.clear();
- in_fast_path = false;
- break;
+ if symbol_str.is_ascii() {
+ continue;
}
- if symbol_str.chars().any(is_in_ascii_confusable_closure_relevant_list) {
- symbol_strs_and_spans.push((symbol_str, *sp));
+ has_non_ascii_idents = true;
+ cx.struct_span_lint(NON_ASCII_IDENTS, sp, |lint| {
+ lint.build("identifier contains non-ASCII characters").emit()
+ });
+ if check_uncommon_codepoints
+ && !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed)
+ {
+ cx.struct_span_lint(UNCOMMON_CODEPOINTS, sp, |lint| {
+ lint.build("identifier contains uncommon Unicode codepoints").emit()
+ })
}
}
- if !in_fast_path {
- // slow path
- for (symbol, sp) in symbols.iter() {
+
+ if has_non_ascii_idents && check_confusable_idents {
+ let mut skeleton_map: FxHashMap<CowBoxSymStr, (SymbolStr, Span, bool)> =
+ FxHashMap::with_capacity_and_hasher(symbols.len(), Default::default());
+ let mut str_buf = String::new();
+ for (symbol, &sp) in symbols.iter() {
+ fn calc_skeleton(symbol_str: &SymbolStr, buffer: &mut String) -> CowBoxSymStr {
+ use std::mem::replace;
+ use unicode_security::confusable_detection::skeleton;
+ buffer.clear();
+ buffer.extend(skeleton(symbol_str));
+ if *symbol_str == *buffer {
+ CowBoxSymStr::Interned(symbol_str.clone())
+ } else {
+ let owned = replace(buffer, String::new());
+ CowBoxSymStr::Owned(owned.into_boxed_str())
+ }
+ }
let symbol_str = symbol.as_str();
- symbol_strs_and_spans.push((symbol_str, *sp));
+ let is_ascii = symbol_str.is_ascii();
+ let skeleton = calc_skeleton(&symbol_str, &mut str_buf);
+ skeleton_map
+ .entry(skeleton)
+ .and_modify(|(existing_symbolstr, existing_span, existing_is_ascii)| {
+ if !*existing_is_ascii || !is_ascii {
+ cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| {
+ lint.build(&format!(
+ "identifier pair considered confusable between `{}` and `{}`",
+ existing_symbolstr, symbol_str
+ ))
+ .span_label(
+ *existing_span,
+ "this is where the previous identifier occurred",
+ )
+ .emit();
+ });
+ }
+ if *existing_is_ascii && !is_ascii {
+ *existing_symbolstr = symbol_str.clone();
+ *existing_span = sp;
+ *existing_is_ascii = is_ascii;
+ }
+ })
+ .or_insert((symbol_str, sp, is_ascii));
}
}
- drop(symbols);
- symbol_strs_and_spans.sort_by_key(|x| x.0.clone());
- let mut skeleton_map =
- FxHashMap::with_capacity_and_hasher(symbol_strs_and_spans.len(), Default::default());
- let mut str_buf = String::new();
- for (symbol_str, sp) in symbol_strs_and_spans {
- let skeleton = calc_skeleton(symbol_str.clone(), &mut str_buf);
- skeleton_map
- .entry(skeleton)
- .and_modify(|(existing_symbolstr, existing_span)| {
- cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| {
- lint.build(&format!(
- "identifier pair considered confusable between `{}` and `{}`",
- existing_symbolstr, symbol_str
- ))
- .span_label(
- *existing_span,
- "this is where the previous identifier occurred",
- )
- .emit();
+
+ if has_non_ascii_idents && check_mixed_script_confusables {
+ use unicode_security::is_potential_mixed_script_confusable_char;
+ use unicode_security::mixed_script::AugmentedScriptSet;
+
+ #[derive(Clone)]
+ enum ScriptSetUsage {
+ Suspicious(Vec<char>, Span),
+ Verified,
+ }
+
+ let mut script_states: FxHashMap<AugmentedScriptSet, ScriptSetUsage> =
+ FxHashMap::default();
+ let latin_augmented_script_set = AugmentedScriptSet::for_char('A');
+ script_states.insert(latin_augmented_script_set, ScriptSetUsage::Verified);
+
+ let mut has_suspicous = false;
+ for (symbol, &sp) in symbols.iter() {
+ let symbol_str = symbol.as_str();
+ for ch in symbol_str.chars() {
+ if ch.is_ascii() {
+ // all ascii characters are covered by exception.
+ continue;
+ }
+ if !GeneralSecurityProfile::identifier_allowed(ch) {
+ // this character is covered by `uncommon_codepoints` lint.
+ continue;
+ }
+ let augmented_script_set = AugmentedScriptSet::for_char(ch);
+ script_states
+ .entry(augmented_script_set)
+ .and_modify(|existing_state| {
+ if let ScriptSetUsage::Suspicious(ch_list, _) = existing_state {
+ if is_potential_mixed_script_confusable_char(ch) {
+ ch_list.push(ch);
+ } else {
+ *existing_state = ScriptSetUsage::Verified;
+ }
+ }
+ })
+ .or_insert_with(|| {
+ if !is_potential_mixed_script_confusable_char(ch) {
+ ScriptSetUsage::Verified
+ } else {
+ has_suspicous = true;
+ ScriptSetUsage::Suspicious(vec![ch], sp)
+ }
+ });
+ }
+ }
+
+ if has_suspicous {
+ let verified_augmented_script_sets = script_states
+ .iter()
+ .flat_map(|(k, v)| match v {
+ ScriptSetUsage::Verified => Some(*k),
+ _ => None,
+ })
+ .collect::<Vec<_>>();
+
+ // we're sorting the output here.
+ let mut lint_reports: BTreeMap<(Span, Vec<char>), AugmentedScriptSet> =
+ BTreeMap::new();
+
+ 'outerloop: for (augment_script_set, usage) in script_states {
+ let (mut ch_list, sp) = match usage {
+ ScriptSetUsage::Verified => continue,
+ ScriptSetUsage::Suspicious(ch_list, sp) => (ch_list, sp),
+ };
+
+ if augment_script_set.is_all() {
+ continue;
+ }
+
+ for existing in verified_augmented_script_sets.iter() {
+ if existing.is_all() {
+ continue;
+ }
+ let mut intersect = *existing;
+ intersect.intersect_with(augment_script_set);
+ if !intersect.is_empty() && !intersect.is_all() {
+ continue 'outerloop;
+ }
+ }
+
+ ch_list.sort();
+ ch_list.dedup();
+ lint_reports.insert((sp, ch_list), augment_script_set);
+ }
+
+ for ((sp, ch_list), script_set) in lint_reports {
+ cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| {
+ let message = format!(
+ "The usage of Script Group `{}` in this crate consists solely of mixed script confusables",
+ script_set);
+ let mut note = "The usage includes ".to_string();
+ for (idx, ch) in ch_list.into_iter().enumerate() {
+ if idx != 0 {
+ note += ", ";
+ }
+ let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
+ note += &char_info;
+ }
+ note += ".";
+ lint.build(&message).note(¬e).note("Please recheck to make sure their usages are indeed what you want.").emit()
});
- })
- .or_insert((symbol_str, sp));
+ }
+ }
}
}
- fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
- use unicode_security::GeneralSecurityProfile;
- let name_str = ident.name.as_str();
- if name_str.is_ascii() {
- return;
+}
+
+mod utils {
+ use rustc_span::symbol::SymbolStr;
+ use std::hash::{Hash, Hasher};
+ use std::ops::Deref;
+
+ pub(super) enum CowBoxSymStr {
+ Interned(SymbolStr),
+ Owned(Box<str>),
+ }
+
+ impl Deref for CowBoxSymStr {
+ type Target = str;
+
+ fn deref(&self) -> &str {
+ match self {
+ CowBoxSymStr::Interned(interned) => interned,
+ CowBoxSymStr::Owned(ref owned) => owned,
+ }
}
- cx.struct_span_lint(NON_ASCII_IDENTS, ident.span, |lint| {
- lint.build("identifier contains non-ASCII characters").emit()
- });
- if !name_str.chars().all(GeneralSecurityProfile::identifier_allowed) {
- cx.struct_span_lint(UNCOMMON_CODEPOINTS, ident.span, |lint| {
- lint.build("identifier contains uncommon Unicode codepoints").emit()
- })
+ }
+
+ impl Hash for CowBoxSymStr {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ Hash::hash(&**self, state)
}
}
+
+ impl PartialEq<CowBoxSymStr> for CowBoxSymStr {
+ #[inline]
+ fn eq(&self, other: &CowBoxSymStr) -> bool {
+ PartialEq::eq(&**self, &**other)
+ }
+ }
+
+ impl Eq for CowBoxSymStr {}
}
use rustc_middle::mir::interpret::{sign_extend, truncate};
use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton};
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
use rustc_span::source_map;
use rustc_span::symbol::sym;
-use rustc_span::Span;
-use rustc_target::abi::{DiscriminantKind, Integer, LayoutOf, VariantIdx, Variants};
+use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants};
use rustc_target::spec::abi::Abi;
use log::debug;
the type `{}` and will become `{}{}`",
repr_str, val, t, actually, t
));
- if let Some(sugg_ty) = get_type_suggestion(&cx.tables.node_type(expr.hir_id), val, negative)
+ if let Some(sugg_ty) =
+ get_type_suggestion(&cx.tables().node_type(expr.hir_id), val, negative)
{
if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
let (sans_suffix, _) = repr_str.split_at(pos);
if let Node::Expr(par_e) = cx.tcx.hir().get(parent_id) {
match par_e.kind {
hir::ExprKind::Cast(..) => {
- if let ty::Char = cx.tables.expr_ty(par_e).kind {
+ if let ty::Char = cx.tables().expr_ty(par_e).kind {
cx.struct_span_lint(OVERFLOWING_LITERALS, par_e.span, |lint| {
lint.build("only `u8` can be cast into `char`")
.span_suggestion(
e: &'tcx hir::Expr<'tcx>,
lit: &hir::Lit,
) {
- match cx.tables.node_type(e.hir_id).kind {
+ match cx.tables().node_type(e.hir_id).kind {
ty::Int(t) => {
match lit.node {
ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => {
// Normalize the binop so that the literal is always on the RHS in
// the comparison
let norm_binop = if swap { rev_binop(binop) } else { binop };
- match cx.tables.node_type(expr.hir_id).kind {
+ match cx.tables().node_type(expr.hir_id).kind {
ty::Int(int_ty) => {
let (min, max) = int_ty_range(int_ty);
let lit_val: i128 = match lit.kind {
"proper use of libc types in foreign modules"
}
-declare_lint_pass!(ImproperCTypes => [IMPROPER_CTYPES]);
+declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]);
+
+declare_lint! {
+ IMPROPER_CTYPES_DEFINITIONS,
+ Warn,
+ "proper use of libc types in foreign item definitions"
+}
+
+declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]);
+
+enum ImproperCTypesMode {
+ Declarations,
+ Definitions,
+}
struct ImproperCTypesVisitor<'a, 'tcx> {
cx: &'a LateContext<'a, 'tcx>,
+ mode: ImproperCTypesMode,
}
enum FfiResult<'tcx> {
FfiSafe,
FfiPhantom(Ty<'tcx>),
- FfiUnsafe { ty: Ty<'tcx>, reason: &'static str, help: Option<&'static str> },
+ FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> },
}
-fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
- match ty.kind {
- ty::FnPtr(_) => true,
- ty::Ref(..) => true,
- ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => {
- for field in field_def.all_fields() {
- let field_ty =
- tcx.normalize_erasing_regions(ParamEnv::reveal_all(), field.ty(tcx, substs));
- if field_ty.is_zst(tcx, field.did) {
- continue;
- }
+impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
+ /// Is type known to be non-null?
+ fn ty_is_known_nonnull(&self, ty: Ty<'tcx>) -> bool {
+ match ty.kind {
+ ty::FnPtr(_) => true,
+ ty::Ref(..) => true,
+ ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => {
+ for field in field_def.all_fields() {
+ let field_ty = self.cx.tcx.normalize_erasing_regions(
+ self.cx.param_env,
+ field.ty(self.cx.tcx, substs),
+ );
+ if field_ty.is_zst(self.cx.tcx, field.did) {
+ continue;
+ }
- let attrs = tcx.get_attrs(field_def.did);
- if attrs.iter().any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed))
- || ty_is_known_nonnull(tcx, field_ty)
- {
- return true;
+ let attrs = self.cx.tcx.get_attrs(field_def.did);
+ if attrs
+ .iter()
+ .any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed))
+ || self.ty_is_known_nonnull(field_ty)
+ {
+ return true;
+ }
}
- }
- false
+ false
+ }
+ _ => false,
}
- _ => false,
}
-}
-/// Check if this enum can be safely exported based on the
-/// "nullable pointer optimization". Currently restricted
-/// to function pointers, references, core::num::NonZero*,
-/// core::ptr::NonNull, and #[repr(transparent)] newtypes.
-/// FIXME: This duplicates code in codegen.
-fn is_repr_nullable_ptr<'tcx>(
- tcx: TyCtxt<'tcx>,
- ty: Ty<'tcx>,
- ty_def: &'tcx ty::AdtDef,
- substs: SubstsRef<'tcx>,
-) -> bool {
- if ty_def.variants.len() != 2 {
- return false;
- }
+ /// Check if this enum can be safely exported based on the "nullable pointer optimization".
+ /// Currently restricted to function pointers, references, `core::num::NonZero*`,
+ /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
+ fn is_repr_nullable_ptr(
+ &self,
+ ty: Ty<'tcx>,
+ ty_def: &'tcx ty::AdtDef,
+ substs: SubstsRef<'tcx>,
+ ) -> bool {
+ if ty_def.variants.len() != 2 {
+ return false;
+ }
- let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields;
- let variant_fields = [get_variant_fields(0), get_variant_fields(1)];
- let fields = if variant_fields[0].is_empty() {
- &variant_fields[1]
- } else if variant_fields[1].is_empty() {
- &variant_fields[0]
- } else {
- return false;
- };
+ let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields;
+ let variant_fields = [get_variant_fields(0), get_variant_fields(1)];
+ let fields = if variant_fields[0].is_empty() {
+ &variant_fields[1]
+ } else if variant_fields[1].is_empty() {
+ &variant_fields[0]
+ } else {
+ return false;
+ };
- if fields.len() != 1 {
- return false;
- }
+ if fields.len() != 1 {
+ return false;
+ }
- let field_ty = fields[0].ty(tcx, substs);
- if !ty_is_known_nonnull(tcx, field_ty) {
- return false;
- }
+ let field_ty = fields[0].ty(self.cx.tcx, substs);
+ if !self.ty_is_known_nonnull(field_ty) {
+ return false;
+ }
- // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
- // If the computed size for the field and the enum are different, the nonnull optimization isn't
- // being applied (and we've got a problem somewhere).
- let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, ParamEnv::reveal_all()).unwrap();
- if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) {
- bug!("improper_ctypes: Option nonnull optimization not applied?");
- }
+ // At this point, the field's type is known to be nonnull and the parent enum is
+ // Option-like. If the computed size for the field and the enum are different, the non-null
+ // optimization isn't being applied (and we've got a problem somewhere).
+ let compute_size_skeleton =
+ |t| SizeSkeleton::compute(t, self.cx.tcx, self.cx.param_env).unwrap();
+ if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) {
+ bug!("improper_ctypes: Option nonnull optimization not applied?");
+ }
- true
-}
+ true
+ }
-impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
/// Check if the type is array and emit an unsafe type lint.
fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
if let ty::Array(..) = ty.kind {
}
}
+ /// Checks if the given field's type is "ffi-safe".
+ fn check_field_type_for_ffi(
+ &self,
+ cache: &mut FxHashSet<Ty<'tcx>>,
+ field: &ty::FieldDef,
+ substs: SubstsRef<'tcx>,
+ ) -> FfiResult<'tcx> {
+ let field_ty = field.ty(self.cx.tcx, substs);
+ if field_ty.has_opaque_types() {
+ self.check_type_for_ffi(cache, field_ty)
+ } else {
+ let field_ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, field_ty);
+ self.check_type_for_ffi(cache, field_ty)
+ }
+ }
+
+ /// Checks if the given `VariantDef`'s field types are "ffi-safe".
+ fn check_variant_for_ffi(
+ &self,
+ cache: &mut FxHashSet<Ty<'tcx>>,
+ ty: Ty<'tcx>,
+ def: &ty::AdtDef,
+ variant: &ty::VariantDef,
+ substs: SubstsRef<'tcx>,
+ ) -> FfiResult<'tcx> {
+ use FfiResult::*;
+
+ if def.repr.transparent() {
+ // Can assume that only one field is not a ZST, so only check
+ // that field's type for FFI-safety.
+ if let Some(field) = variant.transparent_newtype_field(self.cx.tcx) {
+ self.check_field_type_for_ffi(cache, field, substs)
+ } else {
+ bug!("malformed transparent type");
+ }
+ } else {
+ // We can't completely trust repr(C) markings; make sure the fields are
+ // actually safe.
+ let mut all_phantom = !variant.fields.is_empty();
+ for field in &variant.fields {
+ match self.check_field_type_for_ffi(cache, &field, substs) {
+ FfiSafe => {
+ all_phantom = false;
+ }
+ FfiPhantom(..) if def.is_enum() => {
+ return FfiUnsafe {
+ ty,
+ reason: "this enum contains a PhantomData field".into(),
+ help: None,
+ };
+ }
+ FfiPhantom(..) => {}
+ r => return r,
+ }
+ }
+
+ if all_phantom { FfiPhantom(ty) } else { FfiSafe }
+ }
+ }
+
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
/// representation which can be exported to C code).
fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> FfiResult<'tcx> {
return FfiPhantom(ty);
}
match def.adt_kind() {
- AdtKind::Struct => {
+ AdtKind::Struct | AdtKind::Union => {
+ let kind = if def.is_struct() { "struct" } else { "union" };
+
if !def.repr.c() && !def.repr.transparent() {
return FfiUnsafe {
ty,
- reason: "this struct has unspecified layout",
- help: Some(
+ reason: format!("this {} has unspecified layout", kind),
+ help: Some(format!(
"consider adding a `#[repr(C)]` or \
- `#[repr(transparent)]` attribute to this struct",
- ),
+ `#[repr(transparent)]` attribute to this {}",
+ kind
+ )),
};
}
if is_non_exhaustive && !def.did.is_local() {
return FfiUnsafe {
ty,
- reason: "this struct is non-exhaustive",
+ reason: format!("this {} is non-exhaustive", kind),
help: None,
};
}
if def.non_enum_variant().fields.is_empty() {
return FfiUnsafe {
ty,
- reason: "this struct has no fields",
- help: Some("consider adding a member to this struct"),
+ reason: format!("this {} has no fields", kind),
+ help: Some(format!("consider adding a member to this {}", kind)),
};
}
- if def.repr.transparent() {
- // Can assume that only one field is not a ZST, so only check
- // that field's type for FFI-safety.
- if let Some(field) =
- def.transparent_newtype_field(cx, self.cx.param_env)
- {
- let field_ty = cx.normalize_erasing_regions(
- self.cx.param_env,
- field.ty(cx, substs),
- );
- self.check_type_for_ffi(cache, field_ty)
- } else {
- FfiSafe
- }
- } else {
- // We can't completely trust repr(C) markings; make sure the fields are
- // actually safe.
- let mut all_phantom = true;
- for field in &def.non_enum_variant().fields {
- let field_ty = cx.normalize_erasing_regions(
- self.cx.param_env,
- field.ty(cx, substs),
- );
- let r = self.check_type_for_ffi(cache, field_ty);
- match r {
- FfiSafe => {
- all_phantom = false;
- }
- FfiPhantom(..) => {}
- FfiUnsafe { .. } => {
- return r;
- }
- }
- }
-
- if all_phantom { FfiPhantom(ty) } else { FfiSafe }
- }
- }
- AdtKind::Union => {
- if !def.repr.c() && !def.repr.transparent() {
- return FfiUnsafe {
- ty,
- reason: "this union has unspecified layout",
- help: Some(
- "consider adding a `#[repr(C)]` or \
- `#[repr(transparent)]` attribute to this union",
- ),
- };
- }
-
- if def.non_enum_variant().fields.is_empty() {
- return FfiUnsafe {
- ty,
- reason: "this union has no fields",
- help: Some("consider adding a field to this union"),
- };
- }
-
- let mut all_phantom = true;
- for field in &def.non_enum_variant().fields {
- let field_ty = cx.normalize_erasing_regions(
- ParamEnv::reveal_all(),
- field.ty(cx, substs),
- );
- // repr(transparent) types are allowed to have arbitrary ZSTs, not just
- // PhantomData -- skip checking all ZST fields.
- if def.repr.transparent() && field_ty.is_zst(cx, field.did) {
- continue;
- }
- let r = self.check_type_for_ffi(cache, field_ty);
- match r {
- FfiSafe => {
- all_phantom = false;
- }
- FfiPhantom(..) => {}
- FfiUnsafe { .. } => {
- return r;
- }
- }
- }
-
- if all_phantom { FfiPhantom(ty) } else { FfiSafe }
+ self.check_variant_for_ffi(cache, ty, def, def.non_enum_variant(), substs)
}
AdtKind::Enum => {
if def.variants.is_empty() {
// discriminant.
if !def.repr.c() && !def.repr.transparent() && def.repr.int.is_none() {
// Special-case types like `Option<extern fn()>`.
- if !is_repr_nullable_ptr(cx, ty, def, substs) {
+ if !self.is_repr_nullable_ptr(ty, def, substs) {
return FfiUnsafe {
ty,
- reason: "enum has no representation hint",
+ reason: "enum has no representation hint".into(),
help: Some(
"consider adding a `#[repr(C)]`, \
`#[repr(transparent)]`, or integer `#[repr(...)]` \
- attribute to this enum",
+ attribute to this enum"
+ .into(),
),
};
}
if def.is_variant_list_non_exhaustive() && !def.did.is_local() {
return FfiUnsafe {
ty,
- reason: "this enum is non-exhaustive",
+ reason: "this enum is non-exhaustive".into(),
help: None,
};
}
if is_non_exhaustive && !variant.def_id.is_local() {
return FfiUnsafe {
ty,
- reason: "this enum has non-exhaustive variants",
+ reason: "this enum has non-exhaustive variants".into(),
help: None,
};
}
- for field in &variant.fields {
- let field_ty = cx.normalize_erasing_regions(
- ParamEnv::reveal_all(),
- field.ty(cx, substs),
- );
- // repr(transparent) types are allowed to have arbitrary ZSTs, not
- // just PhantomData -- skip checking all ZST fields.
- if def.repr.transparent() && field_ty.is_zst(cx, field.did) {
- continue;
- }
- let r = self.check_type_for_ffi(cache, field_ty);
- match r {
- FfiSafe => {}
- FfiUnsafe { .. } => {
- return r;
- }
- FfiPhantom(..) => {
- return FfiUnsafe {
- ty,
- reason: "this enum contains a PhantomData field",
- help: None,
- };
- }
- }
+ match self.check_variant_for_ffi(cache, ty, def, variant, substs) {
+ FfiSafe => (),
+ r => return r,
}
}
+
FfiSafe
}
}
ty::Char => FfiUnsafe {
ty,
- reason: "the `char` type has no C equivalent",
- help: Some("consider using `u32` or `libc::wchar_t` instead"),
+ reason: "the `char` type has no C equivalent".into(),
+ help: Some("consider using `u32` or `libc::wchar_t` instead".into()),
},
ty::Int(ast::IntTy::I128) | ty::Uint(ast::UintTy::U128) => FfiUnsafe {
ty,
- reason: "128-bit integers don't currently have a known stable ABI",
+ reason: "128-bit integers don't currently have a known stable ABI".into(),
help: None,
},
ty::Slice(_) => FfiUnsafe {
ty,
- reason: "slices have no C equivalent",
- help: Some("consider using a raw pointer instead"),
+ reason: "slices have no C equivalent".into(),
+ help: Some("consider using a raw pointer instead".into()),
},
ty::Dynamic(..) => {
- FfiUnsafe { ty, reason: "trait objects have no C equivalent", help: None }
+ FfiUnsafe { ty, reason: "trait objects have no C equivalent".into(), help: None }
}
ty::Str => FfiUnsafe {
ty,
- reason: "string slices have no C equivalent",
- help: Some("consider using `*const u8` and a length instead"),
+ reason: "string slices have no C equivalent".into(),
+ help: Some("consider using `*const u8` and a length instead".into()),
},
ty::Tuple(..) => FfiUnsafe {
ty,
- reason: "tuples have unspecified layout",
- help: Some("consider using a struct instead"),
+ reason: "tuples have unspecified layout".into(),
+ help: Some("consider using a struct instead".into()),
},
+ ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _)
+ if {
+ matches!(self.mode, ImproperCTypesMode::Definitions)
+ && ty.is_sized(self.cx.tcx.at(DUMMY_SP), self.cx.param_env)
+ } =>
+ {
+ FfiSafe
+ }
+
ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
self.check_type_for_ffi(cache, ty)
}
ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, inner_ty),
ty::FnPtr(sig) => {
- match sig.abi() {
- Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
- return FfiUnsafe {
- ty,
- reason: "this function pointer has Rust-specific calling convention",
- help: Some(
- "consider using an `extern fn(...) -> ...` \
- function pointer instead",
- ),
- };
- }
- _ => {}
+ if self.is_internal_abi(sig.abi()) {
+ return FfiUnsafe {
+ ty,
+ reason: "this function pointer has Rust-specific calling convention".into(),
+ help: Some(
+ "consider using an `extern fn(...) -> ...` \
+ function pointer instead"
+ .into(),
+ ),
+ };
}
let sig = cx.erase_late_bound_regions(&sig);
ty::Foreign(..) => FfiSafe,
+ // While opaque types are checked for earlier, if a projection in a struct field
+ // normalizes to an opaque type, then it will reach this branch.
+ ty::Opaque(..) => {
+ FfiUnsafe { ty, reason: "opaque types have no C equivalent".into(), help: None }
+ }
+
+ // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
+ // so they are currently ignored for the purposes of this lint.
+ ty::Param(..) | ty::Projection(..)
+ if matches!(self.mode, ImproperCTypesMode::Definitions) =>
+ {
+ FfiSafe
+ }
+
ty::Param(..)
+ | ty::Projection(..)
| ty::Infer(..)
| ty::Bound(..)
- | ty::Error
+ | ty::Error(_)
| ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
| ty::Placeholder(..)
- | ty::Projection(..)
- | ty::Opaque(..)
| ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
}
}
note: &str,
help: Option<&str>,
) {
- self.cx.struct_span_lint(IMPROPER_CTYPES, sp, |lint| {
- let mut diag =
- lint.build(&format!("`extern` block uses type `{}`, which is not FFI-safe", ty));
+ let lint = match self.mode {
+ ImproperCTypesMode::Declarations => IMPROPER_CTYPES,
+ ImproperCTypesMode::Definitions => IMPROPER_CTYPES_DEFINITIONS,
+ };
+
+ self.cx.struct_span_lint(lint, sp, |lint| {
+ let item_description = match self.mode {
+ ImproperCTypesMode::Declarations => "block",
+ ImproperCTypesMode::Definitions => "fn",
+ };
+ let mut diag = lint.build(&format!(
+ "`extern` {} uses type `{}`, which is not FFI-safe",
+ item_description, ty
+ ));
diag.span_label(sp, "not FFI-safe");
if let Some(help) = help {
diag.help(help);
}
fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
- use rustc_middle::ty::TypeFoldable;
-
- struct ProhibitOpaqueTypes<'tcx> {
+ struct ProhibitOpaqueTypes<'a, 'tcx> {
+ cx: &'a LateContext<'a, 'tcx>,
ty: Option<Ty<'tcx>>,
};
- impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'tcx> {
+ impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
- if let ty::Opaque(..) = ty.kind {
- self.ty = Some(ty);
- true
- } else {
- ty.super_visit_with(self)
+ match ty.kind {
+ ty::Opaque(..) => {
+ self.ty = Some(ty);
+ true
+ }
+ // Consider opaque types within projections FFI-safe if they do not normalize
+ // to more opaque types.
+ ty::Projection(..) => {
+ let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
+
+ // If `ty` is a opaque type directly then `super_visit_with` won't invoke
+ // this function again.
+ if ty.has_opaque_types() { self.visit_ty(ty) } else { false }
+ }
+ _ => ty.super_visit_with(self),
}
}
}
- let mut visitor = ProhibitOpaqueTypes { ty: None };
+ let mut visitor = ProhibitOpaqueTypes { cx: self.cx, ty: None };
ty.visit_with(&mut visitor);
if let Some(ty) = visitor.ty {
self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None);
// it is only OK to use this function because extern fns cannot have
// any generic types right now:
- let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
+ let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
// C doesn't really support passing arrays by value - the only way to pass an array by value
// is through a struct. So, first test that the top level isn't an array, and then
// argument, which after substitution, is `()`, then this branch can be hit.
FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => return,
FfiResult::FfiUnsafe { ty, reason, help } => {
- self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
+ self.emit_ffi_unsafe_type_lint(ty, sp, &reason, help.as_deref());
}
}
}
let ty = self.cx.tcx.type_of(def_id);
self.check_type_for_ffi_and_report_errors(span, ty, true, false);
}
+
+ fn is_internal_abi(&self, abi: Abi) -> bool {
+ if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
+ true
+ } else {
+ false
+ }
+ }
}
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypesDeclarations {
fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::ForeignItem<'_>) {
- let mut vis = ImproperCTypesVisitor { cx };
+ let mut vis = ImproperCTypesVisitor { cx, mode: ImproperCTypesMode::Declarations };
let abi = cx.tcx.hir().get_foreign_abi(it.hir_id);
- if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
- // Don't worry about types in internal ABIs.
- } else {
+
+ if !vis.is_internal_abi(abi) {
match it.kind {
hir::ForeignItemKind::Fn(ref decl, _, _) => {
vis.check_foreign_fn(it.hir_id, decl);
}
}
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypesDefinitions {
+ fn check_fn(
+ &mut self,
+ cx: &LateContext<'a, 'tcx>,
+ kind: hir::intravisit::FnKind<'tcx>,
+ decl: &'tcx hir::FnDecl<'_>,
+ _: &'tcx hir::Body<'_>,
+ _: Span,
+ hir_id: hir::HirId,
+ ) {
+ use hir::intravisit::FnKind;
+
+ let abi = match kind {
+ FnKind::ItemFn(_, _, header, ..) => header.abi,
+ FnKind::Method(_, sig, ..) => sig.header.abi,
+ _ => return,
+ };
+
+ let mut vis = ImproperCTypesVisitor { cx, mode: ImproperCTypesMode::Definitions };
+ if !vis.is_internal_abi(abi) {
+ vis.check_foreign_fn(hir_id, decl);
+ }
+ }
+}
+
declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
};
let (variants, tag) = match layout.variants {
Variants::Multiple {
- discr_kind: DiscriminantKind::Tag,
- ref discr,
+ tag_encoding: TagEncoding::Direct,
+ ref tag,
ref variants,
..
- } => (variants, discr),
+ } => (variants, tag),
_ => return,
};
- let discr_size = tag.value.size(&cx.tcx).bytes();
+ let tag_size = tag.value.size(&cx.tcx).bytes();
debug!(
"enum `{}` is {} bytes large with layout:\n{:#?}",
.iter()
.zip(variants)
.map(|(variant, variant_layout)| {
- // Subtract the size of the enum discriminant.
- let bytes = variant_layout.size.bytes().saturating_sub(discr_size);
+ // Subtract the size of the enum tag.
+ let bytes = variant_layout.size.bytes().saturating_sub(tag_size);
debug!("- variant `{}` is {} bytes large", variant.ident, bytes);
bytes
return;
}
- let ty = cx.tables.expr_ty(&expr);
+ let ty = cx.tables().expr_ty(&expr);
let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", 1);
let mut fn_warned = false;
hir::ExprKind::Call(ref callee, _) => {
match callee.kind {
hir::ExprKind::Path(ref qpath) => {
- match cx.tables.qpath_res(qpath, callee.hir_id) {
+ match cx.tables().qpath_res(qpath, callee.hir_id) {
Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => Some(def_id),
// `Res::Local` if it was a closure, for which we
// do not currently support must-use linting
_ => None,
}
}
- hir::ExprKind::MethodCall(..) => cx.tables.type_dependent_def_id(expr.hir_id),
+ hir::ExprKind::MethodCall(..) => cx.tables().type_dependent_def_id(expr.hir_id),
_ => None,
};
if let Some(def_id) = maybe_def_id {
_ => return,
}
- for adj in cx.tables.expr_adjustments(e) {
+ for adj in cx.tables().expr_adjustments(e) {
if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| {
let msg = match m {
}
}
- // LLVM requires symbols from this library, but apparently they're not printed
- // during llvm-config?
+ // Libstdc++ depends on pthread which Rust doesn't link on MinGW
+ // since nothing else requires it.
if target.contains("windows-gnu") {
- println!("cargo:rustc-link-lib=static-nobundle=gcc_s");
println!("cargo:rustc-link-lib=static-nobundle=pthread");
- println!("cargo:rustc-link-lib=dylib=uuid");
}
}
/// Appending to a Rust string -- used by RawRustStringOstream.
#[no_mangle]
+#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
pub unsafe extern "C" fn LLVMRustStringWriteImpl(
sr: &RustString,
ptr: *const c_char,
use rustc_data_structures::sync::Lrc;
use rustc_errors::struct_span_err;
use rustc_expand::base::SyntaxExtension;
-use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE};
use rustc_hir::definitions::Definitions;
use rustc_index::vec::IndexVec;
use rustc_middle::middle::cstore::DepKind;
if dep.is_none() {
self.used_extern_options.insert(name);
}
+ if !name.as_str().is_ascii() {
+ self.sess
+ .struct_span_err(
+ span,
+ &format!("cannot load a crate with a non-ascii name `{}`", name,),
+ )
+ .emit();
+ }
self.maybe_resolve_crate(name, span, dep_kind, dep).unwrap_or_else(|err| err.report())
}
}
fn inject_profiler_runtime(&mut self) {
- if (self.sess.opts.debugging_opts.profile || self.sess.opts.cg.profile_generate.enabled())
+ if (self.sess.opts.debugging_opts.instrument_coverage
+ || self.sess.opts.debugging_opts.profile
+ || self.sess.opts.cg.profile_generate.enabled())
&& !self.sess.opts.debugging_opts.no_profiler_runtime
{
info!("loading profiler");
&mut self,
item: &ast::Item,
definitions: &Definitions,
+ def_id: LocalDefId,
) -> CrateNum {
match item.kind {
ast::ItemKind::ExternCrate(orig_name) => {
let cnum = self.resolve_crate(name, item.span, dep_kind, None);
- let def_id = definitions.opt_local_def_id(item.id).unwrap();
let path_len = definitions.def_path(def_id).data.len();
self.update_extern_crate(
cnum,
&& self.triple != TargetTriple::from_triple(config::host_triple())
{
err.note(&format!("the `{}` target may not be installed", self.triple));
+ } else if self.crate_name == sym::profiler_builtins {
+ err.note(&"the compiler may have been built without the profiler runtime");
}
err.span_label(self.span, "can't find crate");
err
let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand };
- if let Some(&ty) = tcx.rcache.borrow().get(&key) {
+ if let Some(&ty) = tcx.ty_rcache.borrow().get(&key) {
return Ok(ty);
}
let ty = or_insert_with(self)?;
- tcx.rcache.borrow_mut().insert(key, ty);
+ tcx.ty_rcache.borrow_mut().insert(key, ty);
Ok(ty)
}
+ fn cached_predicate_for_shorthand<F>(
+ &mut self,
+ shorthand: usize,
+ or_insert_with: F,
+ ) -> Result<ty::Predicate<'tcx>, Self::Error>
+ where
+ F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>,
+ {
+ let tcx = self.tcx();
+
+ let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand };
+
+ if let Some(&pred) = tcx.pred_rcache.borrow().get(&key) {
+ return Ok(pred);
+ }
+
+ let pred = or_insert_with(self)?;
+ tcx.pred_rcache.borrow_mut().insert(key, pred);
+ Ok(pred)
+ }
+
fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
impl EntryKind {
fn def_kind(&self) -> DefKind {
match *self {
+ EntryKind::AnonConst(..) => DefKind::AnonConst,
EntryKind::Const(..) => DefKind::Const,
EntryKind::AssocConst(..) => DefKind::AssocConst,
EntryKind::ImmStatic
fn mir_const_qualif(&self, id: DefIndex) -> mir::ConstQualifs {
match self.kind(id) {
- EntryKind::Const(qualif, _)
+ EntryKind::AnonConst(qualif, _)
+ | EntryKind::Const(qualif, _)
| EntryKind::AssocConst(
AssocContainer::ImplDefault
| AssocContainer::ImplFinal
fn get_rendered_const(&self, id: DefIndex) -> String {
match self.kind(id) {
- EntryKind::Const(_, data) | EntryKind::AssocConst(_, _, data) => data.decode(self).0,
+ EntryKind::AnonConst(_, data)
+ | EntryKind::Const(_, data)
+ | EntryKind::AssocConst(_, _, data) => data.decode(self).0,
_ => bug!(),
}
}
}
}
+impl<'b, 'tcx> SpecializedEncoder<ty::Predicate<'b>> for EncodeContext<'tcx> {
+ fn specialized_encode(&mut self, predicate: &ty::Predicate<'b>) -> Result<(), Self::Error> {
+ debug_assert!(self.tcx.lift(predicate).is_some());
+ let predicate =
+ unsafe { std::mem::transmute::<&ty::Predicate<'b>, &ty::Predicate<'tcx>>(predicate) };
+ ty_codec::encode_with_shorthand(self, predicate, |encoder| {
+ &mut encoder.predicate_shorthands
+ })
+ }
+}
+
impl<'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'tcx> {
fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
use std::collections::hash_map::Entry;
}
}
-impl<'a, 'b, 'tcx> SpecializedEncoder<&'a [(ty::Predicate<'b>, Span)]> for EncodeContext<'tcx> {
- fn specialized_encode(
- &mut self,
- predicates: &&'a [(ty::Predicate<'b>, Span)],
- ) -> Result<(), Self::Error> {
- debug_assert!(self.tcx.lift(*predicates).is_some());
- let predicates = unsafe {
- std::mem::transmute::<
- &&'a [(ty::Predicate<'b>, Span)],
- &&'tcx [(ty::Predicate<'tcx>, Span)],
- >(predicates)
- };
- ty_codec::encode_spanned_predicates(self, &predicates, |ecx| &mut ecx.predicate_shorthands)
- }
-}
-
impl<'tcx> SpecializedEncoder<Fingerprint> for EncodeContext<'tcx> {
fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> {
f.encode_opaque(&mut self.opaque)
let const_data = self.encode_rendered_const_for_body(body_id);
let qualifs = self.tcx.mir_const_qualif(def_id);
- record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Const(qualifs, const_data));
+ record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::AnonConst(qualifs, const_data));
record!(self.tables.visibility[def_id.to_def_id()] <- ty::Visibility::Public);
record!(self.tables.span[def_id.to_def_id()] <- self.tcx.def_span(def_id));
self.encode_item_type(def_id.to_def_id());
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
enum EntryKind {
+ AnonConst(mir::ConstQualifs, Lazy<RenderedConst>),
Const(mir::ConstQualifs, Lazy<RenderedConst>),
ImmStatic,
MutStatic,
rustc_ast = { path = "../librustc_ast" }
rustc_span = { path = "../librustc_span" }
byteorder = { version = "1.3" }
-chalk-ir = "0.10.0"
+chalk-ir = "0.14.0"
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
measureme = "0.7.1"
rustc_session = { path = "../librustc_session" }
// Interned types
[] tys: rustc_middle::ty::TyS<$tcx>, rustc_middle::ty::TyS<'_x>;
+ [] predicates: rustc_middle::ty::PredicateInner<$tcx>, rustc_middle::ty::PredicateInner<'_x>;
// HIR query types
[few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>, rustc_middle::hir::map::IndexedHir<'_x>;
// This is used to decode the &'tcx [Span] for InlineAsm's line_spans.
[decode] span: rustc_span::Span, rustc_span::Span;
+ [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>, rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>;
], $tcx);
)
}
body_ids: _,
modules: _,
proc_macros: _,
+ trait_map: _,
} = *krate;
hash_body(&mut hcx, root_mod_def_path_hash, item, &mut hir_body_nodes)
// Make sure that the DepNode of some node coincides with the HirId
// owner of that node.
if cfg!(debug_assertions) {
- let node_id = self.definitions.hir_id_to_node_id(hir_id);
- assert_eq!(self.definitions.node_id_to_hir_id(node_id), hir_id);
-
if hir_id.owner != self.current_dep_node_owner {
- let node_str = match self.definitions.opt_local_def_id(node_id) {
+ let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) {
Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate(),
None => format!("{:?}", node),
};
debug!("visit_item: {:?}", i);
debug_assert_eq!(
i.hir_id.owner,
- self.definitions
- .opt_local_def_id(self.definitions.hir_id_to_node_id(i.hir_id))
- .unwrap()
+ self.definitions.opt_hir_id_to_local_def_id(i.hir_id).unwrap()
);
self.with_dep_node_owner(i.hir_id.owner, i, |this, hash| {
this.insert_with_hash(i.span, i.hir_id, Node::Item(i), hash);
fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
debug_assert_eq!(
ti.hir_id.owner,
- self.definitions
- .opt_local_def_id(self.definitions.hir_id_to_node_id(ti.hir_id))
- .unwrap()
+ self.definitions.opt_hir_id_to_local_def_id(ti.hir_id).unwrap()
);
self.with_dep_node_owner(ti.hir_id.owner, ti, |this, hash| {
this.insert_with_hash(ti.span, ti.hir_id, Node::TraitItem(ti), hash);
fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
debug_assert_eq!(
ii.hir_id.owner,
- self.definitions
- .opt_local_def_id(self.definitions.hir_id_to_node_id(ii.hir_id))
- .unwrap()
+ self.definitions.opt_hir_id_to_local_def_id(ii.hir_id).unwrap()
);
self.with_dep_node_owner(ii.hir_id.owner, ii, |this, hash| {
this.insert_with_hash(ii.span, ii.hir_id, Node::ImplItem(ii), hash);
}
}
-fn associated_body<'hir>(node: Node<'hir>) -> Option<BodyId> {
+pub fn associated_body<'hir>(node: Node<'hir>) -> Option<BodyId> {
match node {
Node::Item(Item {
kind: ItemKind::Const(_, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body),
}
}
- pub fn visit_item_likes_in_module<V>(&self, module: DefId, visitor: &mut V)
+ pub fn visit_item_likes_in_module<V>(&self, module: LocalDefId, visitor: &mut V)
where
V: ItemLikeVisitor<'hir>,
{
- let module = self.tcx.hir_module_items(module.expect_local());
+ let module = self.tcx.hir_module_items(module);
for id in &module.items {
visitor.visit_item(self.expect_item(*id));
/// Don't use it for anything else or you'll run the risk of
/// leaking data out of the tracking system.
#[inline]
- pub fn new(
+ fn new_with_or_without_spans(
sess: &'a Session,
krate: &'a hir::Crate<'a>,
definitions: &'a Definitions,
cstore: &'a dyn CrateStore,
+ always_ignore_spans: bool,
) -> Self {
- let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans;
+ let hash_spans_initial =
+ !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans;
StableHashingContext {
sess,
}
}
+ #[inline]
+ pub fn new(
+ sess: &'a Session,
+ krate: &'a hir::Crate<'a>,
+ definitions: &'a Definitions,
+ cstore: &'a dyn CrateStore,
+ ) -> Self {
+ Self::new_with_or_without_spans(
+ sess,
+ krate,
+ definitions,
+ cstore,
+ /*always_ignore_spans=*/ false,
+ )
+ }
+
+ #[inline]
+ pub fn ignore_spans(
+ sess: &'a Session,
+ krate: &'a hir::Crate<'a>,
+ definitions: &'a Definitions,
+ cstore: &'a dyn CrateStore,
+ ) -> Self {
+ let always_ignore_spans = true;
+ Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans)
+ }
+
#[inline]
pub fn sess(&self) -> &'a Session {
self.sess
}
impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate {
- type KeyType = (DefPathHash, SmallVec<[(DefPathHash, hir::ItemLocalId); 1]>);
+ type KeyType = (DefPathHash, SmallVec<[DefPathHash; 1]>);
fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType {
let hir::TraitCandidate { def_id, import_ids } = self;
- let import_keys = import_ids
- .iter()
- .map(|hir_id| (hcx.local_def_path_hash(hir_id.owner), hir_id.local_id))
- .collect();
- (hcx.def_path_hash(*def_id), import_keys)
+ (
+ hcx.def_path_hash(*def_id),
+ import_ids.iter().map(|def_id| hcx.local_def_path_hash(*def_id)).collect(),
+ )
}
}
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(const_transmute)]
#![feature(drain_filter)]
#![feature(never_type)]
#![feature(exhaustive_patterns)]
-#![feature(marker_trait_attr)]
#![feature(extern_types)]
#![feature(nll)]
#![feature(option_expect_none)]
#![feature(min_specialization)]
#![feature(track_caller)]
#![feature(trusted_len)]
-#![feature(vec_remove_item)]
#![feature(stmt_expr_attributes)]
#![feature(test)]
#![feature(in_band_lifetimes)]
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
let expn_data = span.ctxt().outer_expn_data();
match expn_data.kind {
- ExpnKind::Root
- | ExpnKind::Desugaring(DesugaringKind::ForLoop(_))
- | ExpnKind::Desugaring(DesugaringKind::Operator) => false,
+ ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => false,
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
ExpnKind::Macro(MacroKind::Bang, _) => {
// Dummy span for the `def_site` means it's an external macro.
use crate::mir::mono::Linkage;
use rustc_attr::{InlineAttr, OptimizeAttr};
+use rustc_session::config::SanitizerSet;
use rustc_span::symbol::Symbol;
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
/// The `#[link_section = "..."]` attribute, or what executable section this
/// should be placed in.
pub link_section: Option<Symbol>,
+ /// The `#[no_sanitize(...)]` attribute. Indicates sanitizers for which
+ /// instrumentation should be disabled inside the annotated function.
+ pub no_sanitize: SanitizerSet,
}
bitflags! {
const FFI_RETURNS_TWICE = 1 << 10;
/// `#[track_caller]`: allow access to the caller location
const TRACK_CALLER = 1 << 11;
- /// `#[no_sanitize(address)]`: disables address sanitizer instrumentation
- const NO_SANITIZE_ADDRESS = 1 << 12;
- /// `#[no_sanitize(memory)]`: disables memory sanitizer instrumentation
- const NO_SANITIZE_MEMORY = 1 << 13;
- /// `#[no_sanitize(thread)]`: disables thread sanitizer instrumentation
- const NO_SANITIZE_THREAD = 1 << 14;
- /// All `#[no_sanitize(...)]` attributes.
- const NO_SANITIZE_ANY = Self::NO_SANITIZE_ADDRESS.bits | Self::NO_SANITIZE_MEMORY.bits | Self::NO_SANITIZE_THREAD.bits;
/// #[ffi_pure]: applies clang's `pure` attribute to a foreign function
/// declaration.
- const FFI_PURE = 1 << 15;
+ const FFI_PURE = 1 << 12;
/// #[ffi_const]: applies clang's `const` attribute to a foreign function
/// declaration.
- const FFI_CONST = 1 << 16;
+ const FFI_CONST = 1 << 13;
}
}
target_features: vec![],
linkage: None,
link_section: None,
+ no_sanitize: SanitizerSet::empty(),
}
}
InvalidBool(u8),
/// Using a non-character `u32` as character.
InvalidChar(u32),
- /// An enum discriminant was set to a value which was outside the range of valid values.
- InvalidDiscriminant(Scalar),
+ /// The tag of an enum does not encode an actual discriminant.
+ InvalidTag(Scalar),
/// Using a pointer-not-to-a-function as function pointer.
InvalidFunctionPointer(Pointer),
/// Using a string that is not valid UTF-8,
InvalidChar(c) => {
write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c)
}
- InvalidDiscriminant(val) => write!(f, "enum value has invalid discriminant: {}", val),
+ InvalidTag(val) => write!(f, "enum value has invalid tag: {}", val),
InvalidFunctionPointer(p) => {
write!(f, "using {} as function pointer but it does not point to a function", p)
}
use rustc_serialize::{Decodable, Encodable};
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi;
use rustc_target::asm::InlineAsmRegOrRegClass;
use std::borrow::Cow;
use std::fmt::{self, Debug, Display, Formatter, Write};
/// Debug information pertaining to user variables, including captures.
pub var_debug_info: Vec<VarDebugInfo<'tcx>>,
- /// Mark this MIR of a const context other than const functions as having converted a `&&` or
- /// `||` expression into `&` or `|` respectively. This is problematic because if we ever stop
- /// this conversion from happening and use short circuiting, we will cause the following code
- /// to change the value of `x`: `let mut x = 42; false && { x = 55; true };`
- ///
- /// List of places where control flow was destroyed. Used for error reporting.
- pub control_flow_destroyed: Vec<(Span, String)>,
-
/// A span representing this MIR, for error reporting.
pub span: Span,
/// The user may be writing e.g. `&[(SOME_CELL, 42)][i].1` and this would get promoted, because
/// we'd statically know that no thing with interior mutability will ever be available to the
/// user without some serious unsafe code. Now this means that our promoted is actually
- /// `&[(SOME_CELL, 42)]` and the MIR using it will do the `&promoted[i].1` projection because the
- /// index may be a runtime value. Such a promoted value is illegal because it has reachable
+ /// `&[(SOME_CELL, 42)]` and the MIR using it will do the `&promoted[i].1` projection because
+ /// the index may be a runtime value. Such a promoted value is illegal because it has reachable
/// interior mutability. This flag just makes this situation very obvious where the previous
/// implementation without the flag hid this situation silently.
/// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components.
arg_count: usize,
var_debug_info: Vec<VarDebugInfo<'tcx>>,
span: Span,
- control_flow_destroyed: Vec<(Span, String)>,
generator_kind: Option<GeneratorKind>,
) -> Self {
// We need `arg_count` locals, and one for the return place.
span,
required_consts: Vec::new(),
ignore_interior_mut_in_const_validation: false,
- control_flow_destroyed,
predecessor_cache: PredecessorCache::new(),
}
}
spread_arg: None,
span: DUMMY_SP,
required_consts: Vec::new(),
- control_flow_destroyed: Vec::new(),
generator_kind: None,
var_debug_info: Vec::new(),
ignore_interior_mut_in_const_validation: false,
discr: Operand<'tcx>,
/// The type of value being tested.
+ /// This is always the same as the type of `discr`.
+ /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing.
switch_ty: Ty<'tcx>,
/// Possible values. The locations to branch to in each case
Unreachable,
/// Drop the `Place`.
- Drop { location: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
+ Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
/// Drop the `Place` and assign the new value over it. This ensures
/// that the assignment to `P` occurs *even if* the destructor for
/// }
/// ```
DropAndReplace {
- location: Place<'tcx>,
+ place: Place<'tcx>,
value: Operand<'tcx>,
target: BasicBlock,
unwind: Option<BasicBlock>,
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
pub enum AssertKind<O> {
BoundsCheck { len: O, index: O },
- Overflow(BinOp),
- OverflowNeg,
- DivisionByZero,
- RemainderByZero,
+ Overflow(BinOp, O, O),
+ OverflowNeg(O),
+ DivisionByZero(O),
+ RemainderByZero(O),
ResumedAfterReturn(GeneratorKind),
ResumedAfterPanic(GeneratorKind),
}
pub fn description(&self) -> &'static str {
use AssertKind::*;
match self {
- Overflow(BinOp::Add) => "attempt to add with overflow",
- Overflow(BinOp::Sub) => "attempt to subtract with overflow",
- Overflow(BinOp::Mul) => "attempt to multiply with overflow",
- Overflow(BinOp::Div) => "attempt to divide with overflow",
- Overflow(BinOp::Rem) => "attempt to calculate the remainder with overflow",
- OverflowNeg => "attempt to negate with overflow",
- Overflow(BinOp::Shr) => "attempt to shift right with overflow",
- Overflow(BinOp::Shl) => "attempt to shift left with overflow",
- Overflow(op) => bug!("{:?} cannot overflow", op),
- DivisionByZero => "attempt to divide by zero",
- RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
+ Overflow(BinOp::Add, _, _) => "attempt to add with overflow",
+ Overflow(BinOp::Sub, _, _) => "attempt to subtract with overflow",
+ Overflow(BinOp::Mul, _, _) => "attempt to multiply with overflow",
+ Overflow(BinOp::Div, _, _) => "attempt to divide with overflow",
+ Overflow(BinOp::Rem, _, _) => "attempt to calculate the remainder with overflow",
+ OverflowNeg(_) => "attempt to negate with overflow",
+ Overflow(BinOp::Shr, _, _) => "attempt to shift right with overflow",
+ Overflow(BinOp::Shl, _, _) => "attempt to shift left with overflow",
+ Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
+ DivisionByZero(_) => "attempt to divide by zero",
+ RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero",
ResumedAfterReturn(GeneratorKind::Gen) => "generator resumed after completion",
ResumedAfterReturn(GeneratorKind::Async(_)) => "`async fn` resumed after completion",
ResumedAfterPanic(GeneratorKind::Gen) => "generator resumed after panicking",
where
O: Debug,
{
+ use AssertKind::*;
match self {
- AssertKind::BoundsCheck { ref len, ref index } => write!(
+ BoundsCheck { ref len, ref index } => write!(
f,
"\"index out of bounds: the len is {{}} but the index is {{}}\", {:?}, {:?}",
len, index
),
+
+ OverflowNeg(op) => {
+ write!(f, "\"attempt to negate {{}} which would overflow\", {:?}", op)
+ }
+ DivisionByZero(op) => write!(f, "\"attempt to divide {{}} by zero\", {:?}", op),
+ RemainderByZero(op) => write!(
+ f,
+ "\"attempt to calculate the remainder of {{}} with a divisor of zero\", {:?}",
+ op
+ ),
+ Overflow(BinOp::Add, l, r) => write!(
+ f,
+ "\"attempt to compute `{{}} + {{}}` which would overflow\", {:?}, {:?}",
+ l, r
+ ),
+ Overflow(BinOp::Sub, l, r) => write!(
+ f,
+ "\"attempt to compute `{{}} - {{}}` which would overflow\", {:?}, {:?}",
+ l, r
+ ),
+ Overflow(BinOp::Mul, l, r) => write!(
+ f,
+ "\"attempt to compute `{{}} * {{}}` which would overflow\", {:?}, {:?}",
+ l, r
+ ),
+ Overflow(BinOp::Div, l, r) => write!(
+ f,
+ "\"attempt to compute `{{}} / {{}}` which would overflow\", {:?}, {:?}",
+ l, r
+ ),
+ Overflow(BinOp::Rem, l, r) => write!(
+ f,
+ "\"attempt to compute the remainder of `{{}} % {{}}` which would overflow\", {:?}, {:?}",
+ l, r
+ ),
+ Overflow(BinOp::Shr, _, r) => {
+ write!(f, "\"attempt to shift right by {{}} which would overflow\", {:?}", r)
+ }
+ Overflow(BinOp::Shl, _, r) => {
+ write!(f, "\"attempt to shift left by {{}} which would overflow\", {:?}", r)
+ }
_ => write!(f, "\"{}\"", self.description()),
}
}
BoundsCheck { ref len, ref index } => {
write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index)
}
+ OverflowNeg(op) => write!(f, "attempt to negate {:#?} which would overflow", op),
+ DivisionByZero(op) => write!(f, "attempt to divide {:#?} by zero", op),
+ RemainderByZero(op) => {
+ write!(f, "attempt to calculate the remainder of {:#?} with a divisor of zero", op)
+ }
+ Overflow(BinOp::Add, l, r) => {
+ write!(f, "attempt to compute `{:#?} + {:#?}` which would overflow", l, r)
+ }
+ Overflow(BinOp::Sub, l, r) => {
+ write!(f, "attempt to compute `{:#?} - {:#?}` which would overflow", l, r)
+ }
+ Overflow(BinOp::Mul, l, r) => {
+ write!(f, "attempt to compute `{:#?} * {:#?}` which would overflow", l, r)
+ }
+ Overflow(BinOp::Div, l, r) => {
+ write!(f, "attempt to compute `{:#?} / {:#?}` which would overflow", l, r)
+ }
+ Overflow(BinOp::Rem, l, r) => write!(
+ f,
+ "attempt to compute the remainder of `{:#?} % {:#?}` which would overflow",
+ l, r
+ ),
+ Overflow(BinOp::Shr, _, r) => {
+ write!(f, "attempt to shift right by {:#?} which would overflow", r)
+ }
+ Overflow(BinOp::Shl, _, r) => {
+ write!(f, "attempt to shift left by {:#?} which would overflow", r)
+ }
_ => write!(f, "{}", self.description()),
}
}
Abort => write!(fmt, "abort"),
Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value),
Unreachable => write!(fmt, "unreachable"),
- Drop { location, .. } => write!(fmt, "drop({:?})", location),
- DropAndReplace { location, value, .. } => {
- write!(fmt, "replace({:?} <- {:?})", location, value)
+ Drop { place, .. } => write!(fmt, "drop({:?})", place),
+ DropAndReplace { place, value, .. } => {
+ write!(fmt, "replace({:?} <- {:?})", place, value)
}
Call { func, args, destination, .. } => {
if let Some((destination, _)) = destination {
})
}
+ /// Convenience helper to make a literal-like constant from a given scalar value.
+ /// Since this is used to synthesize MIR, assumes `user_ty` is None.
+ pub fn const_from_scalar(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ val: Scalar,
+ span: Span,
+ ) -> Operand<'tcx> {
+ debug_assert!({
+ let param_env_and_ty = ty::ParamEnv::empty().and(ty);
+ let type_size = tcx
+ .layout_of(param_env_and_ty)
+ .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e))
+ .size;
+ let scalar_size = abi::Size::from_bytes(match val {
+ Scalar::Raw { size, .. } => size,
+ _ => panic!("Invalid scalar type {:?}", val),
+ });
+ scalar_size == type_size
+ });
+ Operand::Constant(box Constant {
+ span,
+ user_ty: None,
+ literal: ty::Const::from_scalar(tcx, val, ty),
+ })
+ }
+
pub fn to_copy(&self) -> Self {
match *self {
Operand::Copy(_) | Operand::Constant(_) => self.clone(),
}
}
}
+
+/// Coverage data associated with each function (MIR) instrumented with coverage counters, when
+/// compiled with `-Zinstrument_coverage`. The query `tcx.coverage_data(DefId)` computes these
+/// values on demand (during code generation). This query is only valid after executing the MIR pass
+/// `InstrumentCoverage`.
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
+pub struct CoverageData {
+ /// A hash value that can be used by the consumer of the coverage profile data to detect
+ /// changes to the instrumented source of the associated MIR body (typically, for an
+ /// individual function).
+ pub hash: u64,
+
+ /// The total number of coverage region counters added to the MIR `Body`.
+ pub num_counters: u32,
+}
match *self {
MonoItem::Fn(ref instance) => {
let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id);
- // If this function isn't inlined or otherwise has explicit
- // linkage, then we'll be creating a globally shared version.
- if self.explicit_linkage(tcx).is_some()
+ // If this function isn't inlined or otherwise has an extern
+ // indicator, then we'll be creating a globally shared version.
+ if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
|| !instance.def.generates_cgu_internal_copy(tcx)
|| Some(instance.def_id()) == entry_def_id.map(LocalDefId::to_def_id)
{
// At this point we don't have explicit linkage and we're an
// inlined function. If we're inlining into all CGUs then we'll
- // be creating a local copy per CGU
+ // be creating a local copy per CGU.
if generate_cgu_internal_copies {
return InstantiationMode::LocalCopy;
}
use rustc_span::{Span, Symbol};
use rustc_target::abi::VariantIdx;
use smallvec::SmallVec;
+use std::cell::Cell;
+use std::fmt::{self, Debug};
use super::{Field, SourceInfo};
}
/// The layout of generator state.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct GeneratorLayout<'tcx> {
/// The type of every local stored inside the generator.
pub field_tys: IndexVec<GeneratorSavedLocal, Ty<'tcx>>,
/// be stored in multiple variants.
pub variant_fields: IndexVec<VariantIdx, IndexVec<Field, GeneratorSavedLocal>>,
+ /// The source that led to each variant being created (usually, a yield or
+ /// await).
+ pub variant_source_info: IndexVec<VariantIdx, SourceInfo>,
+
/// Which saved locals are storage-live at the same time. Locals that do not
/// have conflicts with each other are allowed to overlap in the computed
/// layout.
pub storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
}
+impl Debug for GeneratorLayout<'_> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// Prints an iterator of (key, value) tuples as a map.
+ struct MapPrinter<'a, K, V>(Cell<Option<Box<dyn Iterator<Item = (K, V)> + 'a>>>);
+ impl<'a, K, V> MapPrinter<'a, K, V> {
+ fn new(iter: impl Iterator<Item = (K, V)> + 'a) -> Self {
+ Self(Cell::new(Some(Box::new(iter))))
+ }
+ }
+ impl<'a, K: Debug, V: Debug> Debug for MapPrinter<'a, K, V> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_map().entries(self.0.take().unwrap()).finish()
+ }
+ }
+
+ /// Prints the generator variant name.
+ struct GenVariantPrinter(VariantIdx);
+ impl From<VariantIdx> for GenVariantPrinter {
+ fn from(idx: VariantIdx) -> Self {
+ GenVariantPrinter(idx)
+ }
+ }
+ impl Debug for GenVariantPrinter {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let variant_name = ty::GeneratorSubsts::variant_name(self.0);
+ if fmt.alternate() {
+ write!(fmt, "{:9}({:?})", variant_name, self.0)
+ } else {
+ write!(fmt, "{}", variant_name)
+ }
+ }
+ }
+
+ /// Forces its contents to print in regular mode instead of alternate mode.
+ struct OneLinePrinter<T>(T);
+ impl<T: Debug> Debug for OneLinePrinter<T> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(fmt, "{:?}", self.0)
+ }
+ }
+
+ fmt.debug_struct("GeneratorLayout")
+ .field("field_tys", &MapPrinter::new(self.field_tys.iter_enumerated()))
+ .field(
+ "variant_fields",
+ &MapPrinter::new(
+ self.variant_fields
+ .iter_enumerated()
+ .map(|(k, v)| (GenVariantPrinter(k), OneLinePrinter(v))),
+ ),
+ )
+ .field("storage_conflicts", &self.storage_conflicts)
+ .finish()
+ }
+}
+
#[derive(Debug, RustcEncodable, RustcDecodable, HashStable)]
pub struct BorrowCheckResult<'tcx> {
/// All the opaque types that are restricted to concrete types
/// The constituent parts of an ADT or array.
#[derive(Copy, Clone, Debug, HashStable)]
pub struct DestructuredConst<'tcx> {
- pub variant: VariantIdx,
+ pub variant: Option<VariantIdx>,
pub fields: &'tcx [&'tcx ty::Const<'tcx>],
}
values: values.clone(),
targets: targets.clone(),
},
- Drop { ref location, target, unwind } => {
- Drop { location: location.fold_with(folder), target, unwind }
+ Drop { ref place, target, unwind } => {
+ Drop { place: place.fold_with(folder), target, unwind }
}
- DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace {
- location: location.fold_with(folder),
+ DropAndReplace { ref place, ref value, target, unwind } => DropAndReplace {
+ place: place.fold_with(folder),
value: value.fold_with(folder),
target,
unwind,
Assert { ref cond, expected, ref msg, target, cleanup } => {
use AssertKind::*;
let msg = match msg {
- BoundsCheck { ref len, ref index } => {
+ BoundsCheck { len, index } => {
BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) }
}
- Overflow(_)
- | OverflowNeg
- | DivisionByZero
- | RemainderByZero
- | ResumedAfterReturn(_)
- | ResumedAfterPanic(_) => msg.clone(),
+ Overflow(op, l, r) => Overflow(*op, l.fold_with(folder), r.fold_with(folder)),
+ OverflowNeg(op) => OverflowNeg(op.fold_with(folder)),
+ DivisionByZero(op) => DivisionByZero(op.fold_with(folder)),
+ RemainderByZero(op) => RemainderByZero(op.fold_with(folder)),
+ ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg.clone(),
};
Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup }
}
SwitchInt { ref discr, switch_ty, .. } => {
discr.visit_with(visitor) || switch_ty.visit_with(visitor)
}
- Drop { ref location, .. } => location.visit_with(visitor),
- DropAndReplace { ref location, ref value, .. } => {
- location.visit_with(visitor) || value.visit_with(visitor)
+ Drop { ref place, .. } => place.visit_with(visitor),
+ DropAndReplace { ref place, ref value, .. } => {
+ place.visit_with(visitor) || value.visit_with(visitor)
}
Yield { ref value, .. } => value.visit_with(visitor),
Call { ref func, ref args, ref destination, .. } => {
BoundsCheck { ref len, ref index } => {
len.visit_with(visitor) || index.visit_with(visitor)
}
- Overflow(_)
- | OverflowNeg
- | DivisionByZero
- | RemainderByZero
- | ResumedAfterReturn(_)
- | ResumedAfterPanic(_) => false,
+ Overflow(_, l, r) => l.visit_with(visitor) || r.visit_with(visitor),
+ OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
+ op.visit_with(visitor)
+ }
+ ResumedAfterReturn(_) | ResumedAfterPanic(_) => false,
}
} else {
false
self.super_terminator(terminator, location);
}
- fn visit_terminator_kind(&mut self,
- kind: & $($mutability)? TerminatorKind<'tcx>,
- location: Location) {
- self.super_terminator_kind(kind, location);
- }
-
fn visit_assert_message(&mut self,
msg: & $($mutability)? AssertMessage<'tcx>,
location: Location) {
let Terminator { source_info, kind } = terminator;
self.visit_source_info(source_info);
- self.visit_terminator_kind(kind, location);
- }
-
- fn super_terminator_kind(&mut self,
- kind: & $($mutability)? TerminatorKind<'tcx>,
- source_location: Location) {
match kind {
TerminatorKind::Goto { .. } |
TerminatorKind::Resume |
self.visit_local(
& $($mutability)? local,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
- source_location,
+ location,
);
assert_eq!(
values: _,
targets: _
} => {
- self.visit_operand(discr, source_location);
- self.visit_ty(switch_ty, TyContext::Location(source_location));
+ self.visit_operand(discr, location);
+ self.visit_ty(switch_ty, TyContext::Location(location));
}
TerminatorKind::Drop {
- location,
+ place,
target: _,
unwind: _,
} => {
self.visit_place(
- location,
+ place,
PlaceContext::MutatingUse(MutatingUseContext::Drop),
- source_location
+ location
);
}
TerminatorKind::DropAndReplace {
- location,
+ place,
value,
target: _,
unwind: _,
} => {
self.visit_place(
- location,
+ place,
PlaceContext::MutatingUse(MutatingUseContext::Drop),
- source_location
+ location
);
- self.visit_operand(value, source_location);
+ self.visit_operand(value, location);
}
TerminatorKind::Call {
from_hir_call: _,
fn_span: _
} => {
- self.visit_operand(func, source_location);
+ self.visit_operand(func, location);
for arg in args {
- self.visit_operand(arg, source_location);
+ self.visit_operand(arg, location);
}
if let Some((destination, _)) = destination {
self.visit_place(
destination,
PlaceContext::MutatingUse(MutatingUseContext::Call),
- source_location
+ location
);
}
}
target: _,
cleanup: _,
} => {
- self.visit_operand(cond, source_location);
- self.visit_assert_message(msg, source_location);
+ self.visit_operand(cond, location);
+ self.visit_assert_message(msg, location);
}
TerminatorKind::Yield {
resume_arg,
drop: _,
} => {
- self.visit_operand(value, source_location);
+ self.visit_operand(value, location);
self.visit_place(
resume_arg,
PlaceContext::MutatingUse(MutatingUseContext::Yield),
- source_location,
+ location,
);
}
match op {
InlineAsmOperand::In { value, .. }
| InlineAsmOperand::Const { value } => {
- self.visit_operand(value, source_location);
+ self.visit_operand(value, location);
}
InlineAsmOperand::Out { place, .. } => {
if let Some(place) = place {
self.visit_place(
place,
PlaceContext::MutatingUse(MutatingUseContext::Store),
- source_location,
+ location,
);
}
}
InlineAsmOperand::InOut { in_value, out_place, .. } => {
- self.visit_operand(in_value, source_location);
+ self.visit_operand(in_value, location);
if let Some(out_place) = out_place {
self.visit_place(
out_place,
PlaceContext::MutatingUse(MutatingUseContext::Store),
- source_location,
+ location,
);
}
}
InlineAsmOperand::SymFn { value } => {
- self.visit_constant(value, source_location);
+ self.visit_constant(value, location);
}
InlineAsmOperand::SymStatic { def_id: _ } => {}
}
self.visit_operand(len, location);
self.visit_operand(index, location);
}
- Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero |
+ Overflow(_, l, r) => {
+ self.visit_operand(l, location);
+ self.visit_operand(r, location);
+ }
+ OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
+ self.visit_operand(op, location);
+ }
ResumedAfterReturn(_) | ResumedAfterPanic(_) => {
// Nothing to visit
}
use rustc_span::symbol::Symbol;
use std::borrow::Cow;
-fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
+fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
if def_id.is_top_level_module() {
"top-level module".to_string()
} else {
- format!("module `{}`", tcx.def_path_str(def_id))
+ format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
}
}
cache_on_disk_if { key.is_local() }
}
+ /// Returns the list of predicates that can be used for
+ /// `SelectionCandidate::ProjectionCandidate` and
+ /// `ProjectionTyCandidate::TraitDef`.
+ /// Specifically this is the bounds (equivalent to) those
+ /// written on the trait's type definition, or those
+ /// after the `impl` keyword
+ ///
+ /// type X: Bound + 'lt
+ /// ^^^^^^^^^^^
+ /// impl Debug + Display
+ /// ^^^^^^^^^^^^^^^
+ ///
+ /// `key` is the `DefId` of the associated type or opaque type.
+ query projection_predicates(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
+ desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) }
+ }
+
query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
desc { "looking up the native libraries of a linked crate" }
}
cache_on_disk_if { key.is_local() }
}
+ query coverage_data(key: DefId) -> mir::CoverageData {
+ desc { |tcx| "retrieving coverage data from MIR for `{}`", tcx.def_path_str(key) }
+ storage(ArenaCacheSelector<'tcx>)
+ cache_on_disk_if { key.is_local() }
+ }
+
query promoted_mir(key: DefId) -> IndexVec<mir::Promoted, mir::Body<'tcx>> {
desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) }
storage(ArenaCacheSelector<'tcx>)
Other {
query lint_mod(key: LocalDefId) -> () {
- desc { |tcx| "linting {}", describe_as_module(key.to_def_id(), tcx) }
+ desc { |tcx| "linting {}", describe_as_module(key, tcx) }
}
/// Checks the attributes in the module.
- query check_mod_attrs(key: DefId) -> () {
+ query check_mod_attrs(key: LocalDefId) -> () {
desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) }
}
- query check_mod_unstable_api_usage(key: DefId) -> () {
+ query check_mod_unstable_api_usage(key: LocalDefId) -> () {
desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) }
}
/// Checks the const bodies in the module for illegal operations (e.g. `if` or `loop`).
- query check_mod_const_bodies(key: DefId) -> () {
+ query check_mod_const_bodies(key: LocalDefId) -> () {
desc { |tcx| "checking consts in {}", describe_as_module(key, tcx) }
}
/// Checks the loops in the module.
- query check_mod_loops(key: DefId) -> () {
+ query check_mod_loops(key: LocalDefId) -> () {
desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) }
}
- query check_mod_item_types(key: DefId) -> () {
+ query check_mod_item_types(key: LocalDefId) -> () {
desc { |tcx| "checking item types in {}", describe_as_module(key, tcx) }
}
query check_mod_privacy(key: LocalDefId) -> () {
- desc { |tcx| "checking privacy in {}", describe_as_module(key.to_def_id(), tcx) }
+ desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) }
}
- query check_mod_intrinsics(key: DefId) -> () {
+ query check_mod_intrinsics(key: LocalDefId) -> () {
desc { |tcx| "checking intrinsics in {}", describe_as_module(key, tcx) }
}
- query check_mod_liveness(key: DefId) -> () {
+ query check_mod_liveness(key: LocalDefId) -> () {
desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) }
}
- query check_mod_impl_wf(key: DefId) -> () {
+ query check_mod_impl_wf(key: LocalDefId) -> () {
desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) }
}
- query collect_mod_item_types(key: DefId) -> () {
+ query collect_mod_item_types(key: LocalDefId) -> () {
desc { |tcx| "collecting item types in {}", describe_as_module(key, tcx) }
}
}
Other {
- query used_trait_imports(key: LocalDefId) -> &'tcx DefIdSet {
+ query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet<LocalDefId> {
desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
cache_on_disk_if { true }
}
//! its name suggest, is to provide an abstraction boundary for creating
//! interned Chalk types.
-use chalk_ir::{GoalData, Parameter};
-
-use rustc_middle::mir::Mutability;
+use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
use rustc_hir::def_id::DefId;
+use rustc_target::spec::abi::Abi;
use smallvec::SmallVec;
use std::fmt;
use std::hash::{Hash, Hasher};
-/// Since Chalk doesn't have full support for all Rust builtin types yet, we
-/// need to use an enum here, rather than just `DefId`.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub enum RustDefId {
- Adt(DefId),
- Str,
- Never,
- Slice,
- Array,
- Ref(Mutability),
- RawPtr,
-
- Trait(DefId),
-
- Impl(DefId),
-
- FnDef(DefId),
-
- AssocTy(DefId),
-}
-
#[derive(Copy, Clone)]
pub struct RustInterner<'tcx> {
pub tcx: TyCtxt<'tcx>,
impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> {
type InternedType = Box<chalk_ir::TyData<Self>>;
type InternedLifetime = Box<chalk_ir::LifetimeData<Self>>;
- type InternedParameter = Box<chalk_ir::ParameterData<Self>>;
+ type InternedConst = Box<chalk_ir::ConstData<Self>>;
+ type InternedConcreteConst = ConstValue<'tcx>;
+ type InternedGenericArg = Box<chalk_ir::GenericArgData<Self>>;
type InternedGoal = Box<chalk_ir::GoalData<Self>>;
type InternedGoals = Vec<chalk_ir::Goal<Self>>;
- type InternedSubstitution = Vec<chalk_ir::Parameter<Self>>;
+ type InternedSubstitution = Vec<chalk_ir::GenericArg<Self>>;
type InternedProgramClause = Box<chalk_ir::ProgramClauseData<Self>>;
type InternedProgramClauses = Vec<chalk_ir::ProgramClause<Self>>;
type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>;
- type InternedParameterKinds = Vec<chalk_ir::ParameterKind<()>>;
- type InternedCanonicalVarKinds = Vec<chalk_ir::ParameterKind<chalk_ir::UniverseIndex>>;
- type DefId = RustDefId;
+ type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>;
+ type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>;
+ type DefId = DefId;
+ type InternedAdtId = &'tcx AdtDef;
type Identifier = ();
+ type FnAbi = Abi;
fn debug_program_clause_implication(
pci: &chalk_ir::ProgramClauseImplication<Self>,
&lifetime
}
- fn intern_parameter(
+ fn intern_const(&self, constant: chalk_ir::ConstData<Self>) -> Self::InternedConst {
+ Box::new(constant)
+ }
+
+ fn const_data<'a>(&self, constant: &'a Self::InternedConst) -> &'a chalk_ir::ConstData<Self> {
+ &constant
+ }
+
+ fn const_eq(
&self,
- parameter: chalk_ir::ParameterData<Self>,
- ) -> Self::InternedParameter {
- Box::new(parameter)
+ _ty: &Self::InternedType,
+ c1: &Self::InternedConcreteConst,
+ c2: &Self::InternedConcreteConst,
+ ) -> bool {
+ c1 == c2
+ }
+
+ fn intern_generic_arg(&self, data: chalk_ir::GenericArgData<Self>) -> Self::InternedGenericArg {
+ Box::new(data)
}
- fn parameter_data<'a>(
+ fn generic_arg_data<'a>(
&self,
- parameter: &'a Self::InternedParameter,
- ) -> &'a chalk_ir::ParameterData<Self> {
- ¶meter
+ data: &'a Self::InternedGenericArg,
+ ) -> &'a chalk_ir::GenericArgData<Self> {
+ &data
}
- fn intern_goal(&self, goal: GoalData<Self>) -> Self::InternedGoal {
+ fn intern_goal(&self, goal: chalk_ir::GoalData<Self>) -> Self::InternedGoal {
Box::new(goal)
}
- fn goal_data<'a>(&self, goal: &'a Self::InternedGoal) -> &'a GoalData<Self> {
+ fn goal_data<'a>(&self, goal: &'a Self::InternedGoal) -> &'a chalk_ir::GoalData<Self> {
&goal
}
fn intern_substitution<E>(
&self,
- data: impl IntoIterator<Item = Result<chalk_ir::Parameter<Self>, E>>,
+ data: impl IntoIterator<Item = Result<chalk_ir::GenericArg<Self>, E>>,
) -> Result<Self::InternedSubstitution, E> {
data.into_iter().collect::<Result<Vec<_>, _>>()
}
fn substitution_data<'a>(
&self,
substitution: &'a Self::InternedSubstitution,
- ) -> &'a [Parameter<Self>] {
+ ) -> &'a [chalk_ir::GenericArg<Self>] {
substitution
}
clauses
}
- fn intern_parameter_kinds<E>(
+ fn intern_generic_arg_kinds<E>(
&self,
- data: impl IntoIterator<Item = Result<chalk_ir::ParameterKind<()>, E>>,
- ) -> Result<Self::InternedParameterKinds, E> {
+ data: impl IntoIterator<Item = Result<chalk_ir::VariableKind<Self>, E>>,
+ ) -> Result<Self::InternedVariableKinds, E> {
data.into_iter().collect::<Result<Vec<_>, _>>()
}
- fn parameter_kinds_data<'a>(
+ fn variable_kinds_data<'a>(
&self,
- parameter_kinds: &'a Self::InternedParameterKinds,
- ) -> &'a [chalk_ir::ParameterKind<()>] {
+ parameter_kinds: &'a Self::InternedVariableKinds,
+ ) -> &'a [chalk_ir::VariableKind<Self>] {
parameter_kinds
}
fn intern_canonical_var_kinds<E>(
&self,
- data: impl IntoIterator<Item = Result<chalk_ir::ParameterKind<chalk_ir::UniverseIndex>, E>>,
+ data: impl IntoIterator<Item = Result<chalk_ir::CanonicalVarKind<Self>, E>>,
) -> Result<Self::InternedCanonicalVarKinds, E> {
data.into_iter().collect::<Result<Vec<_>, _>>()
}
fn canonical_var_kinds_data<'a>(
&self,
canonical_var_kinds: &'a Self::InternedCanonicalVarKinds,
- ) -> &'a [chalk_ir::ParameterKind<chalk_ir::UniverseIndex>] {
+ ) -> &'a [chalk_ir::CanonicalVarKind<Self>] {
canonical_var_kinds
}
}
pub use self::SelectionError::*;
pub use self::chalk::{
- ChalkEnvironmentAndGoal, ChalkEnvironmentClause, RustDefId as ChalkRustDefId,
- RustInterner as ChalkRustInterner,
+ ChalkEnvironmentAndGoal, ChalkEnvironmentClause, RustInterner as ChalkRustInterner,
};
/// Depending on the stage of compilation, we want projection to be
/// ```
/// impl<T:Clone> Clone<T> for Option<T> { ... } // Impl_1
/// impl<T:Clone> Clone<T> for Box<T> { ... } // Impl_2
-/// impl Clone for int { ... } // Impl_3
+/// impl Clone for i32 { ... } // Impl_3
///
-/// fn foo<T:Clone>(concrete: Option<Box<int>>,
-/// param: T,
-/// mixed: Option<T>) {
+/// fn foo<T: Clone>(concrete: Option<Box<i32>>, param: T, mixed: Option<T>) {
+/// // Case A: Vtable points at a specific impl. Only possible when
+/// // type is concretely known. If the impl itself has bounded
+/// // type parameters, Vtable will carry resolutions for those as well:
+/// concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])])
///
-/// // Case A: ImplSource points at a specific impl. Only possible when
-/// // type is concretely known. If the impl itself has bounded
-/// // type parameters, ImplSource will carry resolutions for those as well:
-/// concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
+/// // Case A: ImplSource points at a specific impl. Only possible when
+/// // type is concretely known. If the impl itself has bounded
+/// // type parameters, ImplSource will carry resolutions for those as well:
+/// concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
///
-/// // Case B: ImplSource must be provided by caller. This applies when
-/// // type is a type parameter.
-/// param.clone(); // ImplSourceParam
+/// // Case B: ImplSource must be provided by caller. This applies when
+/// // type is a type parameter.
+/// param.clone(); // ImplSourceParam
///
-/// // Case C: A mix of cases A and B.
-/// mixed.clone(); // ImplSource(Impl_1, [ImplSourceParam])
+/// // Case C: A mix of cases A and B.
+/// mixed.clone(); // ImplSource(Impl_1, [ImplSourceParam])
/// }
/// ```
///
| ty::Ref(..)
| ty::Str
| ty::Foreign(..)
- | ty::Error => true,
+ | ty::Error(_) => true,
// [T; N] and [T] have same properties as T.
ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty),
Err(TypeError::Sorts(relate::expected_found(self, &a, &b)))
}
- (&ty::Error, _) | (_, &ty::Error) => Ok(self.tcx().types.err),
+ (&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(self.tcx().ty_error()),
_ => relate::super_relate_tys(self, a, b),
}
use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
use crate::mir::{self, interpret::Allocation};
use crate::ty::subst::SubstsRef;
-use crate::ty::{self, List, ToPredicate, Ty, TyCtxt};
+use crate::ty::{self, List, Ty, TyCtxt};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
Ok(())
}
-pub fn encode_spanned_predicates<'tcx, E, C>(
- encoder: &mut E,
- predicates: &[(ty::Predicate<'tcx>, Span)],
- cache: C,
-) -> Result<(), E::Error>
-where
- E: TyEncoder,
- C: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<ty::Predicate<'tcx>, usize>,
-{
- predicates.len().encode(encoder)?;
- for (predicate, span) in predicates {
- encode_with_shorthand(encoder, predicate, &cache)?;
- span.encode(encoder)?;
- }
- Ok(())
-}
-
pub trait TyDecoder<'tcx>: Decoder {
fn tcx(&self) -> TyCtxt<'tcx>;
where
F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>;
+ fn cached_predicate_for_shorthand<F>(
+ &mut self,
+ shorthand: usize,
+ or_insert_with: F,
+ ) -> Result<ty::Predicate<'tcx>, Self::Error>
+ where
+ F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>;
+
fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
where
F: FnOnce(&mut Self) -> R;
}
}
+#[inline]
+pub fn decode_predicate<D>(decoder: &mut D) -> Result<ty::Predicate<'tcx>, D::Error>
+where
+ D: TyDecoder<'tcx>,
+{
+ // Handle shorthands first, if we have an usize > 0x80.
+ if decoder.positioned_at_shorthand() {
+ let pos = decoder.read_usize()?;
+ assert!(pos >= SHORTHAND_OFFSET);
+ let shorthand = pos - SHORTHAND_OFFSET;
+
+ decoder.cached_predicate_for_shorthand(shorthand, |decoder| {
+ decoder.with_position(shorthand, ty::Predicate::decode)
+ })
+ } else {
+ let tcx = decoder.tcx();
+ Ok(tcx.mk_predicate(ty::PredicateKind::decode(decoder)?))
+ }
+}
+
#[inline]
pub fn decode_spanned_predicates<D>(
decoder: &mut D,
let tcx = decoder.tcx();
Ok(tcx.arena.alloc_from_iter(
(0..decoder.read_usize()?)
- .map(|_| {
- // Handle shorthands first, if we have an usize > 0x80.
- let predicate_kind = if decoder.positioned_at_shorthand() {
- let pos = decoder.read_usize()?;
- assert!(pos >= SHORTHAND_OFFSET);
- let shorthand = pos - SHORTHAND_OFFSET;
-
- decoder.with_position(shorthand, ty::PredicateKind::decode)
- } else {
- ty::PredicateKind::decode(decoder)
- }?;
- let predicate = predicate_kind.to_predicate(tcx);
- Ok((predicate, Decodable::decode(decoder)?))
- })
+ .map(|_| Decodable::decode(decoder))
.collect::<Result<Vec<_>, _>>()?,
))
}
// FIXME(#36588): These impls are horribly unsound as they allow
// the caller to pick any lifetime for `'tcx`, including `'static`.
- rustc_hir::arena_types!(impl_arena_allocatable_decoders, [$DecoderName [$($typaram),*]], 'tcx);
arena_types!(impl_arena_allocatable_decoders, [$DecoderName [$($typaram),*]], 'tcx);
impl<$($typaram),*> SpecializedDecoder<CrateNum>
where &'_x ty::TyS<'_y>: UseSpecializedDecodable
{
fn specialized_decode(&mut self) -> Result<&'_x ty::TyS<'_y>, Self::Error> {
- unsafe { transmute::<Result<ty::Ty<'tcx>, Self::Error>, Result<&'_x ty::TyS<'_y>, Self::Error>>(decode_ty(self)) }
+ unsafe {
+ transmute::<
+ Result<ty::Ty<'tcx>, Self::Error>,
+ Result<&'_x ty::TyS<'_y>, Self::Error>,
+ >(decode_ty(self))
+ }
+ }
+ }
+
+ impl<'_x, $($typaram),*> SpecializedDecoder<ty::Predicate<'_x>>
+ for $DecoderName<$($typaram),*> {
+ fn specialized_decode(&mut self) -> Result<ty::Predicate<'_x>, Self::Error> {
+ unsafe {
+ transmute::<
+ Result<ty::Predicate<'tcx>, Self::Error>,
+ Result<ty::Predicate<'_x>, Self::Error>,
+ >(decode_predicate(self))
+ }
}
}
--- /dev/null
+use crate::mir::interpret::truncate;
+use rustc_target::abi::Size;
+
+#[derive(Copy, Clone)]
+/// A type for representing any integer. Only used for printing.
+// FIXME: Use this for the integer-tree representation needed for type level ints and
+// const generics?
+pub struct ConstInt {
+ /// Number of bytes of the integer. Only 1, 2, 4, 8, 16 are legal values.
+ size: u8,
+ /// Whether the value is of a signed integer type.
+ signed: bool,
+ /// Whether the value is a `usize` or `isize` type.
+ is_ptr_sized_integral: bool,
+ /// Raw memory of the integer. All bytes beyond the `size` are unused and must be zero.
+ raw: u128,
+}
+
+impl ConstInt {
+ pub fn new(raw: u128, size: Size, signed: bool, is_ptr_sized_integral: bool) -> Self {
+ assert!(raw <= truncate(u128::MAX, size));
+ Self { raw, size: size.bytes() as u8, signed, is_ptr_sized_integral }
+ }
+}
+
+impl std::fmt::Debug for ConstInt {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let Self { size, signed, raw, is_ptr_sized_integral } = *self;
+ if signed {
+ let bit_size = size * 8;
+ let min = 1u128 << (bit_size - 1);
+ let max = min - 1;
+ if raw == min {
+ match (size, is_ptr_sized_integral) {
+ (_, true) => write!(fmt, "isize::MIN"),
+ (1, _) => write!(fmt, "i8::MIN"),
+ (2, _) => write!(fmt, "i16::MIN"),
+ (4, _) => write!(fmt, "i32::MIN"),
+ (8, _) => write!(fmt, "i64::MIN"),
+ (16, _) => write!(fmt, "i128::MIN"),
+ _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+ }
+ } else if raw == max {
+ match (size, is_ptr_sized_integral) {
+ (_, true) => write!(fmt, "isize::MAX"),
+ (1, _) => write!(fmt, "i8::MAX"),
+ (2, _) => write!(fmt, "i16::MAX"),
+ (4, _) => write!(fmt, "i32::MAX"),
+ (8, _) => write!(fmt, "i64::MAX"),
+ (16, _) => write!(fmt, "i128::MAX"),
+ _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+ }
+ } else {
+ match size {
+ 1 => write!(fmt, "{}", raw as i8)?,
+ 2 => write!(fmt, "{}", raw as i16)?,
+ 4 => write!(fmt, "{}", raw as i32)?,
+ 8 => write!(fmt, "{}", raw as i64)?,
+ 16 => write!(fmt, "{}", raw as i128)?,
+ _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+ }
+ if fmt.alternate() {
+ match (size, is_ptr_sized_integral) {
+ (_, true) => write!(fmt, "_isize")?,
+ (1, _) => write!(fmt, "_i8")?,
+ (2, _) => write!(fmt, "_i16")?,
+ (4, _) => write!(fmt, "_i32")?,
+ (8, _) => write!(fmt, "_i64")?,
+ (16, _) => write!(fmt, "_i128")?,
+ _ => bug!(),
+ }
+ }
+ Ok(())
+ }
+ } else {
+ let max = truncate(u128::MAX, Size::from_bytes(size));
+ if raw == max {
+ match (size, is_ptr_sized_integral) {
+ (_, true) => write!(fmt, "usize::MAX"),
+ (1, _) => write!(fmt, "u8::MAX"),
+ (2, _) => write!(fmt, "u16::MAX"),
+ (4, _) => write!(fmt, "u32::MAX"),
+ (8, _) => write!(fmt, "u64::MAX"),
+ (16, _) => write!(fmt, "u128::MAX"),
+ _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+ }
+ } else {
+ match size {
+ 1 => write!(fmt, "{}", raw as u8)?,
+ 2 => write!(fmt, "{}", raw as u16)?,
+ 4 => write!(fmt, "{}", raw as u32)?,
+ 8 => write!(fmt, "{}", raw as u64)?,
+ 16 => write!(fmt, "{}", raw as u128)?,
+ _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+ }
+ if fmt.alternate() {
+ match (size, is_ptr_sized_integral) {
+ (_, true) => write!(fmt, "_usize")?,
+ (1, _) => write!(fmt, "_u8")?,
+ (2, _) => write!(fmt, "_u16")?,
+ (4, _) => write!(fmt, "_u32")?,
+ (8, _) => write!(fmt, "_u64")?,
+ (16, _) => write!(fmt, "_u128")?,
+ _ => bug!(),
+ }
+ }
+ Ok(())
+ }
+ }
+ }
+}
use crate::ty::{
self, query, AdtDef, AdtKind, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
DefIdTree, ExistentialPredicate, FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy,
- IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, ProjectionTy,
- Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut,
+ IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind,
+ ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar,
+ TyVid, TypeAndMut,
};
use rustc_ast::ast;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::definitions::{DefPathHash, Definitions};
+use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::{self, PanicLocationLangItem};
use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate};
use rustc_index::vec::{Idx, IndexVec};
use rustc_session::Session;
use rustc_span::source_map::MultiSpan;
use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx};
use rustc_target::spec::abi;
canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo>>,
region: InternedSet<'tcx, RegionKind>,
existential_predicates: InternedSet<'tcx, List<ExistentialPredicate<'tcx>>>,
- predicate_kind: InternedSet<'tcx, PredicateKind<'tcx>>,
+ predicate: InternedSet<'tcx, PredicateInner<'tcx>>,
predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
projs: InternedSet<'tcx, List<ProjectionKind>>,
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
region: Default::default(),
existential_predicates: Default::default(),
canonical_var_infos: Default::default(),
- predicate_kind: Default::default(),
+ predicate: Default::default(),
predicates: Default::default(),
projs: Default::default(),
place_elems: Default::default(),
})
.0
}
+
+ #[inline(never)]
+ fn intern_predicate(&self, kind: PredicateKind<'tcx>) -> &'tcx PredicateInner<'tcx> {
+ self.predicate
+ .intern(kind, |kind| {
+ let flags = super::flags::FlagComputation::for_predicate(&kind);
+
+ let predicate_struct = PredicateInner {
+ kind,
+ flags: flags.flags,
+ outer_exclusive_binder: flags.outer_exclusive_binder,
+ };
+
+ Interned(self.arena.alloc(predicate_struct))
+ })
+ .0
+ }
}
pub struct CommonTypes<'tcx> {
pub u128: Ty<'tcx>,
pub f32: Ty<'tcx>,
pub f64: Ty<'tcx>,
+ pub str_: Ty<'tcx>,
pub never: Ty<'tcx>,
pub self_param: Ty<'tcx>,
- pub err: Ty<'tcx>,
/// Dummy type used for the `Self` of a `TraitRef` created for converting
/// a trait object, and which gets removed in `ExistentialTraitRef`.
/// This is used for warning unused imports. During type
/// checking, this `Lrc` should not be cloned: it must have a ref-count
/// of 1 so that we can insert things into the set mutably.
- pub used_trait_imports: Lrc<DefIdSet>,
+ pub used_trait_imports: Lrc<FxHashSet<LocalDefId>>,
/// If any errors occurred while type-checking this body,
/// this field will be set to `Some(ErrorReported)`.
bool: mk(Bool),
char: mk(Char),
never: mk(Never),
- err: mk(Error),
isize: mk(Int(ast::IntTy::Isize)),
i8: mk(Int(ast::IntTy::I8)),
i16: mk(Int(ast::IntTy::I16)),
u128: mk(Uint(ast::UintTy::U128)),
f32: mk(Float(ast::FloatTy::F32)),
f64: mk(Float(ast::FloatTy::F64)),
+ str_: mk(Str),
self_param: mk(ty::Param(ty::ParamTy { index: 0, name: kw::SelfUpper })),
trait_object_dummy_self: mk(Infer(ty::FreshTy(0))),
// conflict.
#[derive(Debug)]
pub struct FreeRegionInfo {
- // def id corresponding to FreeRegion
- pub def_id: DefId,
+ // `LocalDefId` corresponding to FreeRegion
+ pub def_id: LocalDefId,
// the bound region corresponding to FreeRegion
pub boundregion: ty::BoundRegion,
// checks if bound region is in Impl Item
/// via `extern crate` item and not `--extern` option or compiler built-in.
pub extern_prelude: FxHashMap<Symbol, bool>,
- // Internal cache for metadata decoding. No need to track deps on this.
- pub rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
+ // Internal caches for metadata decoding. No need to track deps on this.
+ pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
+ pub pred_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Predicate<'tcx>>>,
/// Caches the results of trait selection. This cache is used
/// for things that do not have to do with the parameters in scope.
};
let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
- for (hir_id, v) in resolutions.trait_map.into_iter() {
+ for (hir_id, v) in krate.trait_map.iter() {
let map = trait_map.entry(hir_id.owner).or_default();
- map.insert(hir_id.local_id, StableVec::new(v));
+ map.insert(hir_id.local_id, StableVec::new(v.to_vec()));
}
GlobalCtxt {
definitions,
def_path_hash_to_def_id,
queries: query::Queries::new(providers, extern_providers, on_disk_query_result_cache),
- rcache: Default::default(),
+ ty_rcache: Default::default(),
+ pred_rcache: Default::default(),
selection_cache: Default::default(),
evaluation_cache: Default::default(),
crate_name: Symbol::intern(crate_name),
}
}
+ /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
+ #[track_caller]
+ pub fn ty_error(self) -> Ty<'tcx> {
+ self.ty_error_with_message(DUMMY_SP, "TyKind::Error constructed but no error reported")
+ }
+
+ /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to
+ /// ensure it gets used.
+ #[track_caller]
+ pub fn ty_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Ty<'tcx> {
+ self.sess.delay_span_bug(span, msg);
+ self.mk_ty(Error(super::sty::DelaySpanBugEmitted(())))
+ }
+
+ /// Like `err` but for constants.
+ #[track_caller]
+ pub fn const_error(self, ty: Ty<'tcx>) -> &'tcx Const<'tcx> {
+ self.sess
+ .delay_span_bug(DUMMY_SP, "ty::ConstKind::Error constructed but no error reported.");
+ self.mk_const(ty::Const {
+ val: ty::ConstKind::Error(super::sty::DelaySpanBugEmitted(())),
+ ty,
+ })
+ }
+
pub fn consider_optimizing<T: Fn() -> String>(&self, msg: T) -> bool {
let cname = self.crate_name(LOCAL_CRATE).as_str();
self.sess.consider_optimizing(&cname, msg)
StableHashingContext::new(self.sess, krate, self.definitions, &*self.cstore)
}
+ #[inline(always)]
+ pub fn create_no_span_stable_hashing_context(self) -> StableHashingContext<'tcx> {
+ let krate = self.gcx.untracked_crate;
+
+ StableHashingContext::ignore_spans(self.sess, krate, self.definitions, &*self.cstore)
+ }
+
// This method makes sure that we have a DepNode and a Fingerprint for
// every upstream crate. It needs to be called once right after the tcx is
// created.
// Returns the `DefId` and the `BoundRegion` corresponding to the given region.
pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
let (suitable_region_binding_scope, bound_region) = match *region {
- ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
- ty::ReEarlyBound(ref ebr) => {
- (self.parent(ebr.def_id).unwrap(), ty::BoundRegion::BrNamed(ebr.def_id, ebr.name))
+ ty::ReFree(ref free_region) => {
+ (free_region.scope.expect_local(), free_region.bound_region)
}
+ ty::ReEarlyBound(ref ebr) => (
+ self.parent(ebr.def_id).unwrap().expect_local(),
+ ty::BoundRegion::BrNamed(ebr.def_id, ebr.name),
+ ),
_ => return None, // not a free region
};
- let hir_id = self.hir().as_local_hir_id(suitable_region_binding_scope.expect_local());
+ let hir_id = self.hir().as_local_hir_id(suitable_region_binding_scope);
let is_impl_item = match self.hir().find(hir_id) {
Some(Node::Item(..) | Node::TraitItem(..)) => false,
Some(Node::ImplItem(..)) => {
})
}
- pub fn return_type_impl_or_dyn_trait(&self, scope_def_id: DefId) -> Option<(Span, bool)> {
- let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local());
+ /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type.
+ pub fn return_type_impl_or_dyn_traits(
+ &self,
+ scope_def_id: LocalDefId,
+ ) -> Vec<&'tcx hir::Ty<'tcx>> {
+ let hir_id = self.hir().as_local_hir_id(scope_def_id);
let hir_output = match self.hir().get(hir_id) {
Node::Item(hir::Item {
kind:
),
..
}) => ty,
- _ => return None,
+ _ => return vec![],
};
- let ret_ty = self.type_of(scope_def_id);
- match ret_ty.kind {
- ty::FnDef(_, _) => {
- let sig = ret_ty.fn_sig(*self);
- let output = self.erase_late_bound_regions(&sig.output());
- if output.is_impl_trait() {
- let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap();
- Some((fn_decl.output.span(), false))
- } else {
- let mut v = TraitObjectVisitor(vec![]);
- rustc_hir::intravisit::walk_ty(&mut v, hir_output);
- if v.0.len() == 1 {
- return Some((v.0[0], true));
- }
- None
- }
- }
- _ => None,
- }
+ let mut v = TraitObjectVisitor(vec![], self.hir());
+ v.visit_ty(hir_output);
+ v.0
}
- pub fn return_type_impl_trait(&self, scope_def_id: DefId) -> Option<(Ty<'tcx>, Span)> {
+ pub fn return_type_impl_trait(&self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> {
// HACK: `type_of_def_id()` will fail on these (#55796), so return `None`.
- let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local());
+ let hir_id = self.hir().as_local_hir_id(scope_def_id);
match self.hir().get(hir_id) {
Node::Item(item) => {
match item.kind {
}
// Checks if the bound region is in Impl Item.
- pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: DefId) -> bool {
- let container_id = self.associated_item(suitable_region_binding_scope).container.id();
+ pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: LocalDefId) -> bool {
+ let container_id =
+ self.associated_item(suitable_region_binding_scope.to_def_id()).container.id();
if self.impl_trait_ref(container_id).is_some() {
// For now, we do not try to target impls of traits. This is
// because this message is going to suggest that the user
}
}
-impl<'tcx> GlobalCtxt<'tcx> {
- /// Calls the closure with a local `TyCtxt` using the given arena.
- /// `interners` is a slot passed so we can create a CtxtInterners
- /// with the same lifetime as `arena`.
- pub fn enter_local<F, R>(&'tcx self, f: F) -> R
- where
- F: FnOnce(TyCtxt<'tcx>) -> R,
- {
- let tcx = TyCtxt { gcx: self };
- ty::tls::with_related_context(tcx, |icx| {
- let new_icx = ty::tls::ImplicitCtxt {
- tcx,
- query: icx.query,
- diagnostics: icx.diagnostics,
- layout_depth: icx.layout_depth,
- task_deps: icx.task_deps,
- };
- ty::tls::enter_context(&new_icx, |_| f(tcx))
- })
- }
-}
-
/// A trait implemented for all `X<'a>` types that can be safely and
/// efficiently converted to `X<'tcx>` as long as they are part of the
/// provided `TyCtxt<'tcx>`.
nop_lift! {type_; Ty<'a> => Ty<'tcx>}
nop_lift! {region; Region<'a> => Region<'tcx>}
nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>}
-nop_lift! {predicate_kind; &'a PredicateKind<'a> => &'tcx PredicateKind<'tcx>}
+nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>}
nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>}
nop_list_lift! {existential_predicates; ExistentialPredicate<'a> => ExistentialPredicate<'tcx>}
with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
}
- /// Allows access to the current `ImplicitCtxt` whose tcx field has the same global
- /// interner as the tcx argument passed in. This means the closure is given an `ImplicitCtxt`
- /// with the same `'tcx` lifetime as the `TyCtxt` passed in.
- /// This will panic if you pass it a `TyCtxt` which has a different global interner from
- /// the current `ImplicitCtxt`'s `tcx` field.
+ /// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument
+ /// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime
+ /// as the `TyCtxt` passed in.
+ /// This will panic if you pass it a `TyCtxt` which is different from the current
+ /// `ImplicitCtxt`'s `tcx` field.
#[inline]
pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R
where
let variant = match t.kind {
ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
ty::Float(..) | ty::Str | ty::Never => continue,
- ty::Error => /* unimportant */ continue,
+ ty::Error(_) => /* unimportant */ continue,
$(ty::$variant(..) => &mut $variant,)*
};
let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
&self.0.kind
}
}
+// N.B., an `Interned<PredicateInner>` compares and hashes as a `PredicateKind`.
+impl<'tcx> PartialEq for Interned<'tcx, PredicateInner<'tcx>> {
+ fn eq(&self, other: &Interned<'tcx, PredicateInner<'tcx>>) -> bool {
+ self.0.kind == other.0.kind
+ }
+}
+
+impl<'tcx> Eq for Interned<'tcx, PredicateInner<'tcx>> {}
+
+impl<'tcx> Hash for Interned<'tcx, PredicateInner<'tcx>> {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ self.0.kind.hash(s)
+ }
+}
+
+impl<'tcx> Borrow<PredicateKind<'tcx>> for Interned<'tcx, PredicateInner<'tcx>> {
+ fn borrow<'a>(&'a self) -> &'a PredicateKind<'tcx> {
+ &self.0.kind
+ }
+}
// N.B., an `Interned<List<T>>` compares and hashes as its elements.
impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List<T>> {
}
}
-direct_interners!(
+direct_interners! {
region: mk_region(RegionKind),
const_: mk_const(Const<'tcx>),
- predicate_kind: intern_predicate_kind(PredicateKind<'tcx>),
-);
+}
macro_rules! slice_interners {
($($field:ident: $method:ident($ty:ty)),+) => (
})
}
+ /// Same a `self.mk_region(kind)`, but avoids accessing the interners if
+ /// `*r == kind`.
+ #[inline]
+ pub fn reuse_or_mk_region(self, r: Region<'tcx>, kind: RegionKind) -> Region<'tcx> {
+ if *r == kind { r } else { self.mk_region(kind) }
+ }
+
#[allow(rustc::usage_of_ty_tykind)]
#[inline]
pub fn mk_ty(&self, st: TyKind<'tcx>) -> Ty<'tcx> {
#[inline]
pub fn mk_predicate(&self, kind: PredicateKind<'tcx>) -> Predicate<'tcx> {
- let kind = self.intern_predicate_kind(kind);
- Predicate { kind }
+ let inner = self.interners.intern_predicate(kind);
+ Predicate { inner }
}
pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
}
}
- #[inline]
- pub fn mk_str(self) -> Ty<'tcx> {
- self.mk_ty(Str)
- }
-
#[inline]
pub fn mk_static_str(self) -> Ty<'tcx> {
- self.mk_imm_ref(self.lifetimes.re_static, self.mk_str())
+ self.mk_imm_ref(self.lifetimes.re_static, self.types.str_)
}
#[inline]
}
}
-pub struct TraitObjectVisitor(pub Vec<rustc_span::Span>);
-impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor {
+/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
+pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
+
+impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
type Map = rustc_hir::intravisit::ErasedMap<'v>;
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
hir::intravisit::NestedVisitorMap::None
}
- fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
- if let hir::TyKind::TraitObject(
- _,
- hir::Lifetime { name: hir::LifetimeName::ImplicitObjectLifetimeDefault, .. },
- ) = ty.kind
- {
- self.0.push(ty.span);
+ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+ match ty.kind {
+ hir::TyKind::TraitObject(
+ _,
+ hir::Lifetime {
+ name:
+ hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
+ ..
+ },
+ ) => {
+ self.0.push(ty);
+ }
+ hir::TyKind::OpaqueDef(item_id, _) => {
+ self.0.push(ty);
+ let item = self.1.expect_item(item_id.id);
+ hir::intravisit::walk_item(self, item);
+ }
+ _ => {}
}
+ hir::intravisit::walk_ty(self, ty);
}
}
ty::Projection(_) => "associated type".into(),
ty::Param(p) => format!("type parameter `{}`", p).into(),
ty::Opaque(..) => "opaque type".into(),
- ty::Error => "type error".into(),
+ ty::Error(_) => "type error".into(),
}
}
pub fn prefix_string(&self) -> Cow<'static, str> {
match self.kind {
ty::Infer(_)
- | ty::Error
+ | ty::Error(_)
| ty::Bool
| ty::Char
| ty::Int(_)
}
ty::Opaque(def_id, _) => Some(OpaqueSimplifiedType(def_id)),
ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
- ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error => None,
+ ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
}
}
use crate::ty::subst::{GenericArg, GenericArgKind};
use crate::ty::{self, InferConst, Ty, TypeFlags};
+use std::slice;
#[derive(Debug)]
pub struct FlagComputation {
result
}
+ pub fn for_predicate(kind: &ty::PredicateKind<'_>) -> FlagComputation {
+ let mut result = FlagComputation::new();
+ result.add_predicate_kind(kind);
+ result
+ }
+
pub fn for_const(c: &ty::Const<'_>) -> TypeFlags {
let mut result = FlagComputation::new();
result.add_const(c);
}
/// indicates that `self` refers to something at binding level `binder`
- fn add_binder(&mut self, binder: ty::DebruijnIndex) {
+ fn add_bound_var(&mut self, binder: ty::DebruijnIndex) {
let exclusive_binder = binder.shifted_in(1);
self.add_exclusive_binder(exclusive_binder);
}
/// Adds the flags/depth from a set of types that appear within the current type, but within a
/// region binder.
- fn add_bound_computation(&mut self, computation: &FlagComputation) {
+ fn add_bound_computation(&mut self, computation: FlagComputation) {
self.add_flags(computation.flags);
// The types that contributed to `computation` occurred within
| &ty::Str
| &ty::Foreign(..) => {}
- &ty::Error => self.add_flags(TypeFlags::HAS_ERROR),
+ &ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
&ty::Param(_) => {
self.add_flags(TypeFlags::HAS_TY_PARAM);
&ty::GeneratorWitness(ref ts) => {
let mut computation = FlagComputation::new();
computation.add_tys(&ts.skip_binder()[..]);
- self.add_bound_computation(&computation);
+ self.add_bound_computation(computation);
}
&ty::Closure(_, ref substs) => {
}
&ty::Bound(debruijn, _) => {
- self.add_binder(debruijn);
- self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+ self.add_bound_var(debruijn);
}
&ty::Placeholder(..) => {
ty::ExistentialPredicate::Projection(p) => {
let mut proj_computation = FlagComputation::new();
proj_computation.add_existential_projection(&p);
- self.add_bound_computation(&proj_computation);
+ self.add_bound_computation(proj_computation);
}
ty::ExistentialPredicate::AutoTrait(_) => {}
}
}
- self.add_bound_computation(&computation);
+ self.add_bound_computation(computation);
self.add_region(r);
}
}
}
+ fn add_predicate_kind(&mut self, kind: &ty::PredicateKind<'_>) {
+ match kind {
+ ty::PredicateKind::Trait(trait_pred, _constness) => {
+ let mut computation = FlagComputation::new();
+ computation.add_substs(trait_pred.skip_binder().trait_ref.substs);
+
+ self.add_bound_computation(computation);
+ }
+ ty::PredicateKind::RegionOutlives(poly_outlives) => {
+ let mut computation = FlagComputation::new();
+ let ty::OutlivesPredicate(a, b) = poly_outlives.skip_binder();
+ computation.add_region(a);
+ computation.add_region(b);
+
+ self.add_bound_computation(computation);
+ }
+ ty::PredicateKind::TypeOutlives(poly_outlives) => {
+ let mut computation = FlagComputation::new();
+ let ty::OutlivesPredicate(ty, region) = poly_outlives.skip_binder();
+ computation.add_ty(ty);
+ computation.add_region(region);
+
+ self.add_bound_computation(computation);
+ }
+ ty::PredicateKind::Subtype(poly_subtype) => {
+ let mut computation = FlagComputation::new();
+ let ty::SubtypePredicate { a_is_expected: _, a, b } = poly_subtype.skip_binder();
+ computation.add_ty(a);
+ computation.add_ty(b);
+
+ self.add_bound_computation(computation);
+ }
+ ty::PredicateKind::Projection(projection) => {
+ let mut computation = FlagComputation::new();
+ let ty::ProjectionPredicate { projection_ty, ty } = projection.skip_binder();
+ computation.add_projection_ty(projection_ty);
+ computation.add_ty(ty);
+
+ self.add_bound_computation(computation);
+ }
+ ty::PredicateKind::WellFormed(arg) => {
+ self.add_substs(slice::from_ref(arg));
+ }
+ ty::PredicateKind::ObjectSafe(_def_id) => {}
+ ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => {
+ self.add_substs(substs);
+ }
+ ty::PredicateKind::ConstEvaluatable(_def_id, substs) => {
+ self.add_substs(substs);
+ }
+ ty::PredicateKind::ConstEquate(expected, found) => {
+ self.add_const(expected);
+ self.add_const(found);
+ }
+ }
+ }
+
fn add_ty(&mut self, ty: Ty<'_>) {
self.add_flags(ty.flags);
self.add_exclusive_binder(ty.outer_exclusive_binder);
computation.add_tys(fn_sig.skip_binder().inputs());
computation.add_ty(fn_sig.skip_binder().output());
- self.add_bound_computation(&computation);
+ self.add_bound_computation(computation);
}
fn add_region(&mut self, r: ty::Region<'_>) {
self.add_flags(r.type_flags());
if let ty::ReLateBound(debruijn, _) = *r {
- self.add_binder(debruijn);
+ self.add_bound_var(debruijn);
}
}
}
}
ty::ConstKind::Bound(debruijn, _) => {
- self.add_binder(debruijn);
- self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+ self.add_bound_var(debruijn);
}
ty::ConstKind::Param(_) => {
self.add_flags(TypeFlags::HAS_CT_PARAM);
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
ty::ConstKind::Value(_) => {}
- ty::ConstKind::Error => self.add_flags(TypeFlags::HAS_ERROR),
+ ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
}
}
//! These methods return true to indicate that the visitor has found what it is
//! looking for, and does not need to visit anything else.
+use crate::ty::structural_impls::PredicateVisitor;
use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
fn has_param_types_or_consts(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM)
}
+ fn has_infer_regions(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_RE_INFER)
+ }
fn has_infer_types(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_INFER)
}
}
}
+impl<'tcx> PredicateVisitor<'tcx> for HasEscapingVarsVisitor {
+ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
+ predicate.inner.outer_exclusive_binder > self.outer_index
+ }
+}
+
// FIXME: Optimize for checking for infer flags
struct HasTypeFlagsVisitor {
flags: ty::TypeFlags,
}
}
+impl<'tcx> PredicateVisitor<'tcx> for HasTypeFlagsVisitor {
+ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
+ debug!(
+ "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
+ predicate, predicate.inner.flags, self.flags
+ );
+ predicate.inner.flags.intersects(self.flags)
+ }
+}
/// Collects all the late-bound regions at the innermost binding level
/// into a hash set.
struct LateBoundRegionsCollector {
use std::fmt;
+/// A monomorphized `InstanceDef`.
+///
+/// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type
+/// simply couples a potentially generic `InstanceDef` with some substs, and codegen and const eval
+/// will do all required substitution as they run.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
#[derive(HashStable, Lift)]
pub struct Instance<'tcx> {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, HashStable)]
pub enum InstanceDef<'tcx> {
+ /// A user-defined callable item.
+ ///
+ /// This includes:
+ /// - `fn` items
+ /// - closures
+ /// - generators
Item(DefId),
+
+ /// An intrinsic `fn` item (with `"rust-intrinsic"` or `"platform-intrinsic"` ABI).
+ ///
+ /// Alongside `Virtual`, this is the only `InstanceDef` that does not have its own callable MIR.
+ /// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the
+ /// caller.
Intrinsic(DefId),
- /// `<T as Trait>::method` where `method` receives unsizeable `self: Self`.
+ /// `<T as Trait>::method` where `method` receives unsizeable `self: Self` (part of the
+ /// `unsized_locals` feature).
+ ///
+ /// The generated shim will take `Self` via `*mut Self` - conceptually this is `&owned Self` -
+ /// and dereference the argument to call the original function.
VtableShim(DefId),
/// `fn()` pointer where the function itself cannot be turned into a pointer.
/// (the definition of the function itself).
ReifyShim(DefId),
- /// `<fn() as FnTrait>::call_*`
+ /// `<fn() as FnTrait>::call_*` (generated `FnTrait` implementation for `fn()` pointers).
+ ///
/// `DefId` is `FnTrait::call_*`.
///
/// NB: the (`fn` pointer) type must currently be monomorphic to avoid double substitution
// FIXME(#69925) support polymorphic MIR shim bodies properly instead.
FnPtrShim(DefId, Ty<'tcx>),
- /// `<dyn Trait as Trait>::fn`, "direct calls" of which are implicitly
- /// codegen'd as virtual calls.
+ /// Dynamic dispatch to `<dyn Trait as Trait>::fn`.
///
- /// NB: if this is reified to a `fn` pointer, a `ReifyShim` is used
- /// (see `ReifyShim` above for more details on that).
+ /// This `InstanceDef` does not have callable MIR. Calls to `Virtual` instances must be
+ /// codegen'd as virtual calls through the vtable.
+ ///
+ /// If this is reified to a `fn` pointer, a `ReifyShim` is used (see `ReifyShim` above for more
+ /// details on that).
Virtual(DefId, usize),
- /// `<[mut closure] as FnOnce>::call_once`
- ClosureOnceShim {
- call_once: DefId,
- },
+ /// `<[FnMut closure] as FnOnce>::call_once`.
+ ///
+ /// The `DefId` is the ID of the `call_once` method in `FnOnce`.
+ ClosureOnceShim { call_once: DefId },
/// `core::ptr::drop_in_place::<T>`.
+ ///
/// The `DefId` is for `core::ptr::drop_in_place`.
/// The `Option<Ty<'tcx>>` is either `Some(T)`, or `None` for empty drop
/// glue.
// FIXME(#69925) support polymorphic MIR shim bodies properly instead.
DropGlue(DefId, Option<Ty<'tcx>>),
- ///`<T as Clone>::clone` shim.
+ /// Compiler-generated `<T as Clone>::clone` implementation.
+ ///
+ /// For all types that automatically implement `Copy`, a trivial `Clone` impl is provided too.
+ /// Additionally, arrays, tuples, and closures get a `Clone` shim even if they aren't `Copy`.
+ ///
+ /// The `DefId` is for `Clone::clone`, the `Ty` is the type `T` with the builtin `Clone` impl.
///
/// NB: the type must currently be monomorphic to avoid double substitution
/// problems with the MIR shim bodies. `Instance::resolve` enforces this.
return Ok(tcx.intern_layout(Layout {
variants: Variants::Multiple {
- discr: niche_scalar,
- discr_kind: DiscriminantKind::Niche {
+ tag: niche_scalar,
+ tag_encoding: TagEncoding::Niche {
dataful_variant: i,
niche_variants,
niche_start,
},
- discr_index: 0,
+ tag_field: 0,
variants: st,
},
fields: FieldsShape::Arbitrary {
tcx.intern_layout(Layout {
variants: Variants::Multiple {
- discr: tag,
- discr_kind: DiscriminantKind::Tag,
- discr_index: 0,
+ tag,
+ tag_encoding: TagEncoding::Direct,
+ tag_field: 0,
variants: layout_variants,
},
fields: FieldsShape::Arbitrary {
bug!("Layout::compute: unexpected type `{}`", ty)
}
- ty::Param(_) | ty::Error => {
+ ty::Param(_) | ty::Error(_) => {
return Err(LayoutError::Unknown(ty));
}
})
// Build a prefix layout, including "promoting" all ineligible
// locals as part of the prefix. We compute the layout of all of
// these fields at once to get optimal packing.
- let discr_index = substs.as_generator().prefix_tys().count();
+ let tag_index = substs.as_generator().prefix_tys().count();
// `info.variant_fields` already accounts for the reserved variants, so no need to add them.
let max_discr = (info.variant_fields.len() - 1) as u128;
let discr_int = Integer::fit_unsigned(max_discr);
let discr_int_ty = discr_int.to_ty(tcx, false);
- let discr = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr };
- let discr_layout = self.tcx.intern_layout(Layout::scalar(self, discr.clone()));
- let discr_layout = TyAndLayout { ty: discr_int_ty, layout: discr_layout };
+ let tag = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr };
+ let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag.clone()));
+ let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
let promoted_layouts = ineligible_locals
.iter()
.as_generator()
.prefix_tys()
.map(|ty| self.layout_of(ty))
- .chain(iter::once(Ok(discr_layout)))
+ .chain(iter::once(Ok(tag_layout)))
.chain(promoted_layouts)
.collect::<Result<Vec<_>, _>>()?;
let prefix = self.univariant_uninterned(
// "a" (`0..b_start`) and "b" (`b_start..`) correspond to
// "outer" and "promoted" fields respectively.
- let b_start = (discr_index + 1) as u32;
+ let b_start = (tag_index + 1) as u32;
let offsets_b = offsets.split_off(b_start as usize);
let offsets_a = offsets;
let layout = tcx.intern_layout(Layout {
variants: Variants::Multiple {
- discr,
- discr_kind: DiscriminantKind::Tag,
- discr_index,
+ tag: tag,
+ tag_encoding: TagEncoding::Direct,
+ tag_field: tag_index,
variants,
},
fields: outer_fields,
}
}
- Variants::Multiple { ref discr, ref discr_kind, .. } => {
+ Variants::Multiple { ref tag, ref tag_encoding, .. } => {
debug!(
"print-type-size `{:#?}` adt general variants def {}",
layout.ty,
record(
adt_kind.into(),
adt_packed,
- match discr_kind {
- DiscriminantKind::Tag => Some(discr.value.size(self)),
+ match tag_encoding {
+ TagEncoding::Direct => Some(tag.value.size(self)),
_ => None,
},
variant_infos,
}
let fields = match this.ty.kind {
+ ty::Adt(def, _) if def.variants.is_empty() =>
+ bug!("for_variant called on zero-variant enum"),
ty::Adt(def, _) => def.variants[variant_index].fields.len(),
_ => bug!(),
};
fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
let tcx = cx.tcx();
- let discr_layout = |discr: &Scalar| -> C::TyAndLayout {
- let layout = Layout::scalar(cx, discr.clone());
+ let tag_layout = |tag: &Scalar| -> C::TyAndLayout {
+ let layout = Layout::scalar(cx, tag.clone());
MaybeResult::from(Ok(TyAndLayout {
layout: tcx.intern_layout(layout),
- ty: discr.value.to_ty(tcx),
+ ty: tag.value.to_ty(tcx),
}))
};
.unwrap()
.nth(i)
.unwrap(),
- Variants::Multiple { ref discr, discr_index, .. } => {
- if i == discr_index {
- return discr_layout(discr);
+ Variants::Multiple { ref tag, tag_field, .. } => {
+ if i == tag_field {
+ return tag_layout(tag);
}
substs.as_generator().prefix_tys().nth(i).unwrap()
}
Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs),
// Discriminant field for enums (where applicable).
- Variants::Multiple { ref discr, .. } => {
+ Variants::Multiple { ref tag, .. } => {
assert_eq!(i, 0);
- return discr_layout(discr);
+ return tag_layout(tag);
}
}
}
| ty::Opaque(..)
| ty::Param(_)
| ty::Infer(_)
- | ty::Error => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty),
+ | ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty),
})
}
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
let tcx = cx.tcx();
- let is_freeze = ty.is_freeze(tcx, cx.param_env(), DUMMY_SP);
+ let is_freeze = ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env());
let kind = match mt {
hir::Mutability::Not => {
if is_freeze {
// using more niches than just null (e.g., the first page of
// the address space, or unaligned pointers).
Variants::Multiple {
- discr_kind: DiscriminantKind::Niche { dataful_variant, .. },
- discr_index,
+ tag_encoding: TagEncoding::Niche { dataful_variant, .. },
+ tag_field,
..
- } if this.fields.offset(discr_index) == offset => {
+ } if this.fields.offset(tag_field) == offset => {
Some(this.for_variant(cx, dataful_variant))
}
_ => Some(this),
use rustc_serialize::{Encodable, Encoder};
-use std::cmp::{self, Ordering};
+use std::alloc::Layout;
+use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter;
assert!(mem::size_of::<T>() != 0);
assert!(!slice.is_empty());
- // Align up the size of the len (usize) field
- let align = mem::align_of::<T>();
- let align_mask = align - 1;
- let offset = mem::size_of::<usize>();
- let offset = (offset + align_mask) & !align_mask;
-
- let size = offset + slice.len() * mem::size_of::<T>();
-
- let mem = arena
- .dropless
- .alloc_raw(size, cmp::max(mem::align_of::<T>(), mem::align_of::<usize>()));
+ let (layout, _offset) =
+ Layout::new::<usize>().extend(Layout::for_value::<[T]>(slice)).unwrap();
+ let mem = arena.dropless.alloc_raw(layout);
unsafe {
let result = &mut *(mem as *mut List<T>);
// Write the length
pub use self::query::queries;
+pub use self::consts::ConstInt;
+
pub mod adjustment;
pub mod binding;
pub mod cast;
pub mod util;
pub mod walk;
+mod consts;
mod context;
mod diagnostics;
mod instance;
pub definitions: rustc_hir::definitions::Definitions,
pub cstore: Box<CrateStoreDyn>,
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
- pub trait_map: FxHashMap<hir::HirId, Vec<hir::TraitCandidate<hir::HirId>>>,
pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
pub export_map: ExportMap<LocalDefId>,
}
}
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::TyS<'tcx> {
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let ty::TyS {
ref kind,
}
}
-#[derive(Clone, Copy, Hash, RustcEncodable, RustcDecodable, Lift)]
-#[derive(HashStable)]
+#[derive(Debug)]
+crate struct PredicateInner<'tcx> {
+ kind: PredicateKind<'tcx>,
+ flags: TypeFlags,
+ /// See the comment for the corresponding field of [TyS].
+ outer_exclusive_binder: ty::DebruijnIndex,
+}
+
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(PredicateInner<'_>, 40);
+
+#[derive(Clone, Copy, Lift)]
pub struct Predicate<'tcx> {
- kind: &'tcx PredicateKind<'tcx>,
+ inner: &'tcx PredicateInner<'tcx>,
}
+impl rustc_serialize::UseSpecializedEncodable for Predicate<'_> {}
+impl rustc_serialize::UseSpecializedDecodable for Predicate<'_> {}
+
impl<'tcx> PartialEq for Predicate<'tcx> {
fn eq(&self, other: &Self) -> bool {
// `self.kind` is always interned.
- ptr::eq(self.kind, other.kind)
+ ptr::eq(self.inner, other.inner)
+ }
+}
+
+impl Hash for Predicate<'_> {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ (self.inner as *const PredicateInner<'_>).hash(s)
}
}
impl<'tcx> Predicate<'tcx> {
#[inline(always)]
pub fn kind(self) -> &'tcx PredicateKind<'tcx> {
- self.kind
+ &self.inner.kind
+ }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
+ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+ let PredicateInner {
+ ref kind,
+
+ // The other fields just provide fast access to information that is
+ // also contained in `kind`, so no need to hash them.
+ flags: _,
+ outer_exclusive_binder: _,
+ } = self.inner;
+
+ kind.hash_stable(hcx, hasher);
}
}
pub fn is_field_list_non_exhaustive(&self) -> bool {
self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE)
}
+
+ /// `repr(transparent)` structs can have a single non-ZST field, this function returns that
+ /// field.
+ pub fn transparent_newtype_field(&self, tcx: TyCtxt<'tcx>) -> Option<&FieldDef> {
+ for field in &self.fields {
+ let field_ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, self.def_id));
+ if !field_ty.is_zst(tcx, self.def_id) {
+ return Some(field);
+ }
+ }
+
+ None
+ }
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
/// Alternatively, if there is no explicit discriminant, returns the
/// inferred discriminant directly.
pub fn discriminant_def_for_variant(&self, variant_index: VariantIdx) -> (Option<DefId>, u32) {
+ assert!(!self.variants.is_empty());
let mut explicit_index = variant_index.as_u32();
let expr_did;
loop {
pub fn sized_constraint(&self, tcx: TyCtxt<'tcx>) -> &'tcx [Ty<'tcx>] {
tcx.adt_sized_constraint(self.did).0
}
-
- /// `repr(transparent)` structs can have a single non-ZST field, this function returns that
- /// field.
- pub fn transparent_newtype_field(
- &self,
- tcx: TyCtxt<'tcx>,
- param_env: ParamEnv<'tcx>,
- ) -> Option<&FieldDef> {
- assert!(self.is_struct() && self.repr.transparent());
-
- for field in &self.non_enum_variant().fields {
- let field_ty = tcx.normalize_erasing_regions(
- param_env,
- field.ty(tcx, InternalSubsts::identity_for_item(tcx, self.did)),
- );
-
- if !field_ty.is_zst(tcx, self.did) {
- return Some(field);
- }
- }
-
- None
- }
}
impl<'tcx> FieldDef {
ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*)
ty::Placeholder(..) |
ty::Bound(..) |
- ty::Error => {
+ ty::Error(_) => {
// (*) Function pointers and trait objects are both binders.
// In the RFC, this means we would add the bound regions to
// the "bound regions list". In our representation, no such
| ty::Opaque(..)
| ty::Infer(_)
| ty::Bound(..)
- | ty::Error
+ | ty::Error(_)
| ty::GeneratorWitness(..)
| ty::Never
| ty::Float(_) => None,
let substs = substs.truncate_to(self.tcx, generics);
self.push_generic_params(substs, iter::empty(), output, debug);
}
- ty::Error
+ ty::Error(_)
| ty::Bound(..)
| ty::Infer(_)
| ty::Placeholder(..)
use crate::middle::cstore::{ExternCrate, ExternCrateSource};
-use crate::mir::interpret::{
- sign_extend, truncate, AllocId, ConstValue, GlobalAlloc, Pointer, Scalar,
-};
+use crate::mir::interpret::{AllocId, ConstValue, GlobalAlloc, Pointer, Scalar};
use crate::ty::layout::IntegerExt;
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
-use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, ConstInt, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
use rustc_ast::ast;
p!(write("{}", infer_ty))
}
}
- ty::Error => p!(write("[type error]")),
+ ty::Error(_) => p!(write("[type error]")),
ty::Param(ref param_ty) => p!(write("{}", param_ty)),
ty::Bound(debruijn, bound_ty) => match bound_ty.kind {
ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?,
self.pretty_print_bound_var(debruijn, bound_var)?
}
ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
- ty::ConstKind::Error => p!(write("[const error]")),
+ ty::ConstKind::Error(_) => p!(write("[const error]")),
};
Ok(self)
}
}
// Int
(Scalar::Raw { data, .. }, ty::Uint(ui)) => {
- let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size();
- let max = truncate(u128::MAX, bit_size);
-
- let ui_str = ui.name_str();
- if data == max {
- p!(write("{}::MAX", ui_str))
- } else {
- if print_ty { p!(write("{}{}", data, ui_str)) } else { p!(write("{}", data)) }
- };
+ let size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size();
+ let int = ConstInt::new(data, size, false, ty.is_ptr_sized_integral());
+ if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) }
}
(Scalar::Raw { data, .. }, ty::Int(i)) => {
let size = Integer::from_attr(&self.tcx(), SignedInt(*i)).size();
- let bit_size = size.bits() as u128;
- let min = 1u128 << (bit_size - 1);
- let max = min - 1;
-
- let i_str = i.name_str();
- match data {
- d if d == min => p!(write("{}::MIN", i_str)),
- d if d == max => p!(write("{}::MAX", i_str)),
- _ => {
- let data = sign_extend(data, size) as i128;
- if print_ty {
- p!(write("{}{}", data, i_str))
- } else {
- p!(write("{}", data))
- }
- }
- }
+ let int = ConstInt::new(data, size, true, ty.is_ptr_sized_integral());
+ if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) }
}
// Char
(Scalar::Raw { data, .. }, ty::Char) if char::from_u32(data as u32).is_some() => {
}
p!(write(")"));
}
+ ty::Adt(def, substs) if def.variants.is_empty() => {
+ p!(print_value_path(def.did, substs));
+ }
ty::Adt(def, substs) => {
- let variant_def = &def.variants[contents.variant];
+ let variant_id =
+ contents.variant.expect("destructed const of adt without variant id");
+ let variant_def = &def.variants[variant_id];
p!(print_value_path(variant_def.def_id, substs));
match variant_def.ctor_kind {
let cache_key =
ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand };
- if let Some(&ty) = tcx.rcache.borrow().get(&cache_key) {
+ if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) {
return Ok(ty);
}
let ty = or_insert_with(self)?;
// This may overwrite the entry, but it should overwrite with the same value.
- tcx.rcache.borrow_mut().insert_same(cache_key, ty);
+ tcx.ty_rcache.borrow_mut().insert_same(cache_key, ty);
Ok(ty)
}
+ fn cached_predicate_for_shorthand<F>(
+ &mut self,
+ shorthand: usize,
+ or_insert_with: F,
+ ) -> Result<ty::Predicate<'tcx>, Self::Error>
+ where
+ F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>,
+ {
+ let tcx = self.tcx();
+
+ let cache_key =
+ ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand };
+
+ if let Some(&pred) = tcx.pred_rcache.borrow().get(&cache_key) {
+ return Ok(pred);
+ }
+
+ let pred = or_insert_with(self)?;
+ // This may overwrite the entry, but it should overwrite with the same value.
+ tcx.pred_rcache.borrow_mut().insert_same(cache_key, pred);
+ Ok(pred)
+ }
+
fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
}
}
-impl<'a, 'b, 'c, 'tcx, E> SpecializedEncoder<&'b [(ty::Predicate<'c>, Span)]>
- for CacheEncoder<'a, 'tcx, E>
+impl<'a, 'b, 'tcx, E> SpecializedEncoder<ty::Predicate<'b>> for CacheEncoder<'a, 'tcx, E>
where
E: 'a + TyEncoder,
{
#[inline]
- fn specialized_encode(
- &mut self,
- predicates: &&'b [(ty::Predicate<'c>, Span)],
- ) -> Result<(), Self::Error> {
- debug_assert!(self.tcx.lift(*predicates).is_some());
- let predicates = unsafe {
- std::mem::transmute::<
- &&'b [(ty::Predicate<'c>, Span)],
- &&'tcx [(ty::Predicate<'tcx>, Span)],
- >(predicates)
- };
- ty_codec::encode_spanned_predicates(self, predicates, |encoder| {
+ fn specialized_encode(&mut self, predicate: &ty::Predicate<'b>) -> Result<(), Self::Error> {
+ debug_assert!(self.tcx.lift(predicate).is_some());
+ let predicate =
+ unsafe { std::mem::transmute::<&ty::Predicate<'b>, &ty::Predicate<'tcx>>(predicate) };
+ ty_codec::encode_with_shorthand(self, predicate, |encoder| {
&mut encoder.predicate_shorthands
})
}
fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
// SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
// FIXME: Represent the above fact in the trait system somehow.
- unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.types.err) }
+ unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error()) }
}
}
// FIXME: Represent the above fact in the trait system somehow.
unsafe {
std::mem::transmute::<AdtSizedConstraint<'tcx>, AdtSizedConstraint<'_>>(
- AdtSizedConstraint(tcx.intern_type_list(&[tcx.types.err])),
+ AdtSizedConstraint(tcx.intern_type_list(&[tcx.ty_error()])),
)
}
}
bug!("bound types encountered in super_relate_tys")
}
- (&ty::Error, _) | (_, &ty::Error) => Ok(tcx.types.err),
+ (&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(tcx.ty_error()),
(&ty::Never, _)
| (&ty::Char, _)
bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b)
}
- (ty::ConstKind::Error, _) | (_, ty::ConstKind::Error) => Ok(ty::ConstKind::Error),
+ (ty::ConstKind::Error(d), _) | (_, ty::ConstKind::Error(d)) => Ok(ty::ConstKind::Error(d)),
(ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => {
return Ok(a);
a: &Self,
b: &Self,
) -> RelateResult<'tcx, Self> {
- if a.len() != b.len() {
+ let tcx = relation.tcx();
+
+ // FIXME: this is wasteful, but want to do a perf run to see how slow it is.
+ // We need to perform this deduplication as we sometimes generate duplicate projections
+ // in `a`.
+ let mut a_v: Vec<_> = a.into_iter().collect();
+ let mut b_v: Vec<_> = b.into_iter().collect();
+ a_v.sort_by(|a, b| a.stable_cmp(tcx, b));
+ a_v.dedup();
+ b_v.sort_by(|a, b| a.stable_cmp(tcx, b));
+ b_v.dedup();
+ if a_v.len() != b_v.len() {
return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b)));
}
- let tcx = relation.tcx();
- let v = a.iter().zip(b.iter()).map(|(ep_a, ep_b)| {
+ let v = a_v.into_iter().zip(b_v.into_iter()).map(|(ep_a, ep_b)| {
use crate::ty::ExistentialPredicate::*;
match (ep_a, ep_b) {
(Trait(ref a), Trait(ref b)) => Ok(Trait(relation.relate(a, b)?)),
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
- | ty::Error
+ | ty::Error(_)
| ty::Infer(_)
| ty::Param(..)
| ty::Bound(..)
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
- | ty::Error
+ | ty::Error(_)
| ty::Infer(_)
| ty::Bound(..)
| ty::Placeholder(..)
impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
- let new = ty::PredicateKind::super_fold_with(self.kind, folder);
- if new != *self.kind { folder.tcx().mk_predicate(new) } else { *self }
+ let new = ty::PredicateKind::super_fold_with(&self.inner.kind, folder);
+ if new != self.inner.kind { folder.tcx().mk_predicate(new) } else { *self }
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- ty::PredicateKind::super_visit_with(self.kind, visitor)
+ ty::PredicateKind::super_visit_with(&self.inner.kind, visitor)
+ }
+
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ visitor.visit_predicate(*self)
+ }
+
+ fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
+ self.inner.outer_exclusive_binder > binder
+ }
+
+ fn has_type_flags(&self, flags: ty::TypeFlags) -> bool {
+ self.inner.flags.intersects(flags)
+ }
+}
+
+pub(super) trait PredicateVisitor<'tcx>: TypeVisitor<'tcx> {
+ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool;
+}
+
+impl<T: TypeVisitor<'tcx>> PredicateVisitor<'tcx> for T {
+ default fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
+ predicate.super_visit_with(self)
}
}
ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(..)
- | ty::ConstKind::Error => *self,
+ | ty::ConstKind::Error(_) => *self,
}
}
ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(_)
- | ty::ConstKind::Error => false,
+ | ty::ConstKind::Error(_) => false,
}
}
}
/// A placeholder for a type which could not be computed; this is
/// propagated to avoid useless error messages.
- Error,
+ Error(DelaySpanBugEmitted),
}
+/// A type that is not publicly constructable. This prevents people from making `TyKind::Error`
+/// except through `tcx.err*()`.
+#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[derive(RustcEncodable, RustcDecodable, HashStable)]
+pub struct DelaySpanBugEmitted(pub(super) ());
+
// `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
static_assert_size!(TyKind<'_>, 24);
/// Calls `f` with a reference to the name of the enumerator for the given
/// variant `v`.
- #[inline]
- pub fn variant_name(self, v: VariantIdx) -> Cow<'static, str> {
+ pub fn variant_name(v: VariantIdx) -> Cow<'static, str> {
match v.as_usize() {
Self::UNRESUMED => Cow::from(Self::UNRESUMED_NAME),
Self::RETURNED => Cow::from(Self::RETURNED_NAME),
flags = flags | TypeFlags::HAS_FREE_REGIONS;
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
flags = flags | TypeFlags::HAS_RE_INFER;
- flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE;
}
ty::RePlaceholder(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
flags = flags | TypeFlags::HAS_RE_PLACEHOLDER;
- flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE;
}
ty::ReEarlyBound(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
flags = flags | TypeFlags::HAS_RE_PARAM;
- flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE;
}
ty::ReFree { .. } => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
#[inline]
pub fn has_concrete_skeleton(&self) -> bool {
match self.kind {
- Param(_) | Infer(_) | Error => false,
+ Param(_) | Infer(_) | Error(_) => false,
_ => true,
}
}
match self.kind {
FnDef(def_id, substs) => tcx.fn_sig(def_id).subst(tcx, substs),
FnPtr(f) => f,
- Error => {
+ Error(_) => {
// ignore errors (#54954)
ty::Binder::dummy(FnSig::fake())
}
variant_index: VariantIdx,
) -> Option<Discr<'tcx>> {
match self.kind {
+ TyKind::Adt(adt, _) if adt.variants.is_empty() => {
+ bug!("discriminant_for_variant called on zero variant enum");
+ }
TyKind::Adt(adt, _) if adt.is_enum() => {
Some(adt.discriminant_for_variant(tcx, variant_index))
}
// closure type is not yet known
Bound(..) | Infer(_) => None,
- Error => Some(ty::ClosureKind::Fn),
+ Error(_) => Some(ty::ClosureKind::Fn),
_ => bug!("cannot convert type `{:?}` to a closure kind", self),
}
| ty::Array(..)
| ty::Closure(..)
| ty::Never
- | ty::Error => true,
+ | ty::Error(_) => true,
ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false,
// can leak through `val` into the const we return.
Ok(val) => Const::from_value(tcx, val, self.ty),
Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => self,
- Err(ErrorHandled::Reported(ErrorReported)) => {
- tcx.mk_const(ty::Const { val: ty::ConstKind::Error, ty: self.ty })
- }
+ Err(ErrorHandled::Reported(ErrorReported)) => tcx.const_error(self.ty),
}
} else {
self
/// A placeholder for a const which could not be computed; this is
/// propagated to avoid useless error messages.
- Error,
+ Error(DelaySpanBugEmitted),
}
#[cfg(target_arch = "x86_64")]
/// in a different item, with `target_substs` as the base for
/// the target impl/trait, with the source child-specific
/// parameters (e.g., method parameters) on top of that base.
+ ///
+ /// For example given:
+ ///
+ /// ```no_run
+ /// trait X<S> { fn f<T>(); }
+ /// impl<U> X<U> for U { fn f<V>() {} }
+ /// ```
+ ///
+ /// * If `self` is `[Self, S, T]`: the identity substs of `f` in the trait.
+ /// * If `source_ancestor` is the def_id of the trait.
+ /// * If `target_substs` is `[U]`, the substs for the impl.
+ /// * Then we will return `[U, T]`, the subst for `f` in the impl that
+ /// are needed for it to match the trait.
pub fn rebase_onto(
&self,
tcx: TyCtxt<'tcx>,
///
/// ```
/// type Func<A> = fn(A);
- /// type MetaFunc = for<'a> fn(Func<&'a int>)
+ /// type MetaFunc = for<'a> fn(Func<&'a i32>)
/// ```
///
/// The type `MetaFunc`, when fully expanded, will be
///
- /// for<'a> fn(fn(&'a int))
+ /// for<'a> fn(fn(&'a i32))
/// ^~ ^~ ^~~
/// | | |
/// | | DebruijnIndex of 2
/// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the
/// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip
/// over the inner binder (remember that we count De Bruijn indices from 1). However, in the
- /// definition of `MetaFunc`, the binder is not visible, so the type `&'a int` will have a
+ /// definition of `MetaFunc`, the binder is not visible, so the type `&'a i32` will have a
/// De Bruijn index of 1. It's only during the substitution that we can see we must increase the
/// depth by 1 to account for the binder that we passed through.
///
///
/// ```
/// type FuncTuple<A> = (A,fn(A));
- /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a int>)
+ /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a i32>)
/// ```
///
/// Here the final type will be:
///
- /// for<'a> fn((&'a int, fn(&'a int)))
+ /// for<'a> fn((&'a i32, fn(&'a i32)))
/// ^~~ ^~~
/// | |
/// DebruijnIndex of 1 |
/// DebruijnIndex of 2
///
- /// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the
+ /// As indicated in the diagram, here the same type `&'a i32` is substituted once, but in the
/// first case we do not increase the De Bruijn index and in the second case we do. The reason
/// is that only in the second case have we passed through a fn binder.
fn shift_vars_through_binders<T: TypeFoldable<'tcx>>(&self, val: T) -> T {
if let ty::Adt(def, substs) = ty.kind {
for field in def.all_fields() {
let field_ty = field.ty(self, substs);
- if let Error = field_ty.kind {
+ if let Error(_) = field_ty.kind {
return true;
}
}
/// winds up being reported as an error during NLL borrow check.
pub fn is_copy_modulo_regions(
&'tcx self,
- tcx: TyCtxt<'tcx>,
+ tcx_at: TyCtxtAt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- span: Span,
) -> bool {
- tcx.at(span).is_copy_raw(param_env.and(self))
+ tcx_at.is_copy_raw(param_env.and(self))
}
/// Checks whether values of this type `T` have a size known at
/// that the `Freeze` trait is not exposed to end users and is
/// effectively an implementation detail.
// FIXME: use `TyCtxtAt` instead of separate `Span`.
- pub fn is_freeze(
- &'tcx self,
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- span: Span,
- ) -> bool {
- self.is_trivially_freeze() || tcx.at(span).is_freeze_raw(param_env.and(self))
+ pub fn is_freeze(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ self.is_trivially_freeze() || tcx_at.is_freeze_raw(param_env.and(self))
}
/// Fast path helper for testing if a type is `Freeze`.
| ty::Ref(..)
| ty::RawPtr(_)
| ty::FnDef(..)
- | ty::Error
+ | ty::Error(_)
| ty::FnPtr(_) => true,
ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_freeze),
ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(),
// called for known, fully-monomorphized types.
Projection(_) | Opaque(..) | Param(_) | Bound(..) | Placeholder(_) | Infer(_) => false,
- Foreign(_) | GeneratorWitness(..) | Error => false,
+ Foreign(_) | GeneratorWitness(..) | Error(_) => false,
}
}
// Foreign types can never have destructors.
ty::Foreign(..) => Ok(SmallVec::new()),
- ty::Dynamic(..) | ty::Error => Err(AlwaysRequiresDrop),
+ ty::Dynamic(..) | ty::Error(_) => Err(AlwaysRequiresDrop),
ty::Slice(ty) => needs_drop_components(ty, target_layout),
ty::Array(elem_ty, size) => {
/// Skips the subtree corresponding to the last type
/// returned by `next()`.
///
- /// Example: Imagine you are walking `Foo<Bar<int>, usize>`.
+ /// Example: Imagine you are walking `Foo<Bar<i32>, usize>`.
///
/// ```
/// let mut iter: TypeWalker = ...;
/// iter.next(); // yields Foo
- /// iter.next(); // yields Bar<int>
- /// iter.skip_current_subtree(); // skips int
+ /// iter.next(); // yields Bar<i32>
+ /// iter.skip_current_subtree(); // skips i32
/// iter.next(); // yields usize
/// ```
pub fn skip_current_subtree(&mut self) {
| ty::Infer(_)
| ty::Param(_)
| ty::Never
- | ty::Error
+ | ty::Error(_)
| ty::Placeholder(..)
| ty::Bound(..)
| ty::Foreign(..) => {}
| ty::ConstKind::Placeholder(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Value(_)
- | ty::ConstKind::Error => {}
+ | ty::ConstKind::Error(_) => {}
ty::ConstKind::Unevaluated(_, substs, _) => {
stack.extend(substs.iter().rev());
let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
- if span == move_span {
+ if location == move_out.source {
err.span_label(
span,
format!("value moved{} here, in previous iteration of loop", move_msg),
);
}
}
+ if let UseSpans::PatUse(span) = move_spans {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ &format!(
+ "borrow this field in the pattern to avoid moving {}",
+ self.describe_place(moved_place.as_ref())
+ .map(|n| format!("`{}`", n))
+ .unwrap_or_else(|| "the value".to_string())
+ ),
+ "ref ".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+
if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
let sess = self.infcx.tcx.sess;
if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
_ => true,
};
- if needs_note {
- let mpi = self.move_data.moves[move_out_indices[0]].path;
- let place = &self.move_data.move_paths[mpi].place;
+ let mpi = self.move_data.moves[move_out_indices[0]].path;
+ let place = &self.move_data.move_paths[mpi].place;
+ let ty = place.ty(self.body, self.infcx.tcx).ty;
+
+ if is_loop_move {
+ if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind {
+ // We have a `&mut` ref, we need to reborrow on each iteration (#62112).
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ &format!(
+ "consider creating a fresh reborrow of {} here",
+ self.describe_place(moved_place)
+ .map(|n| format!("`{}`", n))
+ .unwrap_or_else(|| "the mutable reference".to_string()),
+ ),
+ "&mut *".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
- let ty = place.ty(self.body, self.infcx.tcx).ty;
+ if needs_note {
let opt_name =
self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
let note_msg = match opt_name {
// Used in a closure.
(LaterUseKind::ClosureCapture, var_span)
}
- UseSpans::OtherUse(span) | UseSpans::FnSelfUse { var_span: span, .. } => {
+ UseSpans::PatUse(span)
+ | UseSpans::OtherUse(span)
+ | UseSpans::FnSelfUse { var_span: span, .. } => {
let block = &self.body.basic_blocks()[location.block];
let kind = if let Some(&Statement {
use rustc_hir as hir;
use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItemGroup;
use rustc_hir::GeneratorKind;
use rustc_middle::mir::{
AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place,
fn_span: Span,
kind: FnSelfUseKind,
},
- // This access has a single span associated to it: common case.
+ /// This access is caused by a `match` or `if let` pattern.
+ PatUse(Span),
+ /// This access has a single span associated to it: common case.
OtherUse(Span),
}
pub(super) fn args_or_use(self) -> Span {
match self {
UseSpans::ClosureUse { args_span: span, .. }
+ | UseSpans::PatUse(span)
| UseSpans::FnSelfUse { var_span: span, .. }
| UseSpans::OtherUse(span) => span,
}
pub(super) fn var_or_use(self) -> Span {
match self {
UseSpans::ClosureUse { var_span: span, .. }
+ | UseSpans::PatUse(span)
| UseSpans::FnSelfUse { var_span: span, .. }
| UseSpans::OtherUse(span) => span,
}
{
match self {
closure @ UseSpans::ClosureUse { .. } => closure,
+ UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(),
fn_self @ UseSpans::FnSelfUse { .. } => fn_self,
- UseSpans::OtherUse(_) => if_other(),
}
}
}
}
}
- let normal_ret = OtherUse(stmt.source_info.span);
+ let normal_ret =
+ if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
+ PatUse(stmt.source_info.span)
+ } else {
+ OtherUse(stmt.source_info.span)
+ };
// We are trying to find MIR of the form:
// ```
debug!("move_spans: target_temp = {:?}", target_temp);
- if let Some(Terminator { kind: TerminatorKind::Call { func, args, fn_span, .. }, .. }) =
- &self.body[location.block].terminator
+ if let Some(Terminator {
+ kind: TerminatorKind::Call { func, args, fn_span, from_hir_call, .. },
+ ..
+ }) = &self.body[location.block].terminator
{
let mut method_did = None;
if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func {
if let [Operand::Move(self_place), ..] = **args {
if self_place.as_local() == Some(target_temp) {
- let is_fn_once = tcx.parent(method_did) == tcx.lang_items().fn_once_trait();
+ let parent = tcx.parent(method_did);
+ let is_fn_once = parent == tcx.lang_items().fn_once_trait();
+ let is_operator = !from_hir_call
+ && parent.map_or(false, |p| {
+ tcx.lang_items().group(LangItemGroup::Op).contains(&p)
+ });
let fn_call_span = *fn_span;
let self_arg = tcx.fn_arg_names(method_did)[0];
let kind = if is_fn_once {
FnSelfUseKind::FnOnceCall
- } else if fn_call_span.is_desugaring(DesugaringKind::Operator) {
+ } else if is_operator {
FnSelfUseKind::Operator { self_arg }
} else {
debug!(
if let (Some(f), Some(ty::RegionKind::ReStatic)) =
(self.to_error_region(fr), self.to_error_region(outlived_fr))
{
- if let Some((ty::TyS { kind: ty::Opaque(did, substs), .. }, _)) = self
+ if let Some((&ty::TyS { kind: ty::Opaque(did, substs), .. }, _)) = self
.infcx
.tcx
.is_suitable_region(f)
//
// eg. check for `impl Trait + 'static` instead of `impl Trait`.
let has_static_predicate = {
- let predicates_of = self.infcx.tcx.predicates_of(*did);
+ let predicates_of = self.infcx.tcx.predicates_of(did);
let bounds = predicates_of.instantiate(self.infcx.tcx, substs);
let mut found = false;
diag.help(&format!("consider replacing `{}` with `{}`", fr_name, static_str));
} else {
// Otherwise, we should suggest adding a constraint on the return type.
- let span = self.infcx.tcx.def_span(*did);
+ let span = self.infcx.tcx.def_span(did);
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
let suggestable_fr_name = if fr_name.was_named() {
fr_name.to_string()
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue};
use rustc_middle::mir::{BorrowKind, Mutability, Operand};
-use rustc_middle::mir::{InlineAsmOperand, TerminatorKind};
+use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::mir::{Statement, StatementKind};
use rustc_middle::ty::TyCtxt;
self.super_statement(statement, location);
}
- fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Location) {
+ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
self.check_activations(location);
- match kind {
+ match &terminator.kind {
TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => {
self.consume_operand(location, discr);
}
- TerminatorKind::Drop { location: drop_place, target: _, unwind: _ } => {
+ TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => {
self.access_place(
location,
*drop_place,
);
}
TerminatorKind::DropAndReplace {
- location: drop_place,
+ place: drop_place,
value: ref new_value,
target: _,
unwind: _,
}
}
- self.super_terminator_kind(kind, location);
+ self.super_terminator(terminator, location);
}
}
TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => {
self.consume_operand(loc, (discr, span), flow_state);
}
- TerminatorKind::Drop { location: ref drop_place, target: _, unwind: _ } => {
+ TerminatorKind::Drop { place: ref drop_place, target: _, unwind: _ } => {
let tcx = self.infcx.tcx;
// Compute the type with accurate region information.
);
}
TerminatorKind::DropAndReplace {
- location: drop_place,
+ place: drop_place,
value: ref new_value,
target: _,
unwind: _,
.tcx
.sess
.delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty));
- (self.infcx.tcx.types.err, None)
+ (self.infcx.tcx.ty_error(), None)
});
let constraints2 = self.add_implied_bounds(ty);
normalized_inputs_and_output.push(ty);
if place_ty.variant_index.is_none() {
if place_ty.ty.references_error() {
assert!(self.errors_reported);
- return PlaceTy::from_ty(self.tcx().types.err);
+ return PlaceTy::from_ty(self.tcx().ty_error());
}
}
place_ty = self.sanitize_projection(place_ty, elem, place, location)
fn error(&mut self) -> Ty<'tcx> {
self.errors_reported = true;
- self.tcx().types.err
+ self.tcx().ty_error()
}
fn field_ty(
// no checks needed for these
}
- TerminatorKind::DropAndReplace { ref location, ref value, target: _, unwind: _ } => {
- let place_ty = location.ty(body, tcx).ty;
+ TerminatorKind::DropAndReplace { ref place, ref value, target: _, unwind: _ } => {
+ let place_ty = place.ty(body, tcx).ty;
let rv_ty = value.ty(body, tcx);
let locations = term_location.to_locations();
category: ConstraintCategory,
borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
) -> Fallible<()> {
- debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
+ debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations);
TypeRelating::new(
infcx,
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
) -> Self {
let tcx = infcx.tcx;
let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id);
- UniversalRegionsBuilder { infcx, mir_def_id: mir_def_id.to_def_id(), mir_hir_id, param_env }
- .build()
+ UniversalRegionsBuilder { infcx, mir_def_id, mir_hir_id, param_env }.build()
}
/// Given a reference to a closure type, extracts all the values
struct UniversalRegionsBuilder<'cx, 'tcx> {
infcx: &'cx InferCtxt<'cx, 'tcx>,
- mir_def_id: DefId,
+ mir_def_id: LocalDefId,
mir_hir_id: HirId,
param_env: ty::ParamEnv<'tcx>,
}
let mut indices = self.compute_indices(fr_static, defining_ty);
debug!("build: indices={:?}", indices);
- let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id);
+ let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id.to_def_id());
// If this is a closure or generator, then the late-bound regions from the enclosing
// function are actually external regions to us. For example, here, 'a is not local
// fn foo<'a>() {
// let c = || { let x: &'a u32 = ...; }
// }
- if self.mir_def_id != closure_base_def_id {
+ if self.mir_def_id.to_def_id() != closure_base_def_id {
self.infcx.replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices)
}
);
// Converse of above, if this is a function then the late-bound regions declared on its
// signature are local to the fn.
- if self.mir_def_id == closure_base_def_id {
+ if self.mir_def_id.to_def_id() == closure_base_def_id {
self.infcx
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices);
}
/// see `DefiningTy` for details.
fn defining_ty(&self) -> DefiningTy<'tcx> {
let tcx = self.infcx.tcx;
- let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
+ let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id.to_def_id());
match tcx.hir().body_owner_kind(self.mir_hir_id) {
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
- let defining_ty = if self.mir_def_id == closure_base_def_id {
+ let defining_ty = if self.mir_def_id.to_def_id() == closure_base_def_id {
tcx.type_of(closure_base_def_id)
} else {
- let tables = tcx.typeck_tables_of(self.mir_def_id.expect_local());
+ let tables = tcx.typeck_tables_of(self.mir_def_id);
tables.node_type(self.mir_hir_id)
};
}
BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
- assert_eq!(closure_base_def_id, self.mir_def_id);
+ assert_eq!(self.mir_def_id.to_def_id(), closure_base_def_id);
let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
let substs =
self.infcx.replace_free_regions_with_nll_infer_vars(FR, &identity_substs);
- DefiningTy::Const(self.mir_def_id, substs)
+ DefiningTy::Const(self.mir_def_id.to_def_id(), substs)
}
}
}
defining_ty: DefiningTy<'tcx>,
) -> UniversalRegionIndices<'tcx> {
let tcx = self.infcx.tcx;
- let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
+ let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id.to_def_id());
let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
let fr_substs = match defining_ty {
DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
let tcx = self.infcx.tcx;
match defining_ty {
DefiningTy::Closure(def_id, substs) => {
- assert_eq!(self.mir_def_id, def_id);
+ assert_eq!(self.mir_def_id.to_def_id(), def_id);
let closure_sig = substs.as_closure().sig();
let inputs_and_output = closure_sig.inputs_and_output();
let closure_ty = tcx.closure_env_ty(def_id, substs).unwrap();
}
DefiningTy::Generator(def_id, substs, movability) => {
- assert_eq!(self.mir_def_id, def_id);
+ assert_eq!(self.mir_def_id.to_def_id(), def_id);
let resume_ty = substs.as_generator().resume_ty();
let output = substs.as_generator().return_ty();
let generator_ty = tcx.mk_generator(def_id, substs, movability);
DefiningTy::Const(def_id, _) => {
// For a constant body, there are no inputs, and one
// "output" (the type of the constant).
- assert_eq!(self.mir_def_id, def_id);
+ assert_eq!(self.mir_def_id.to_def_id(), def_id);
let ty = tcx.type_of(def_id);
let ty = indices.fold_to_region_vids(tcx, &ty);
ty::Binder::dummy(tcx.intern_type_list(&[ty]))
fn replace_bound_regions_with_nll_infer_vars<T>(
&self,
origin: NLLRegionVariableOrigin,
- all_outlive_scope: DefId,
+ all_outlive_scope: LocalDefId,
value: &ty::Binder<T>,
indices: &mut UniversalRegionIndices<'tcx>,
) -> T
fn replace_late_bound_regions_with_nll_infer_vars(
&self,
- mir_def_id: DefId,
+ mir_def_id: LocalDefId,
indices: &mut UniversalRegionIndices<'tcx>,
);
}
fn replace_bound_regions_with_nll_infer_vars<T>(
&self,
origin: NLLRegionVariableOrigin,
- all_outlive_scope: DefId,
+ all_outlive_scope: LocalDefId,
value: &ty::Binder<T>,
indices: &mut UniversalRegionIndices<'tcx>,
) -> T
let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br);
let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
- scope: all_outlive_scope,
+ scope: all_outlive_scope.to_def_id(),
bound_region: br,
}));
let region_vid = self.next_nll_region_var(origin);
/// inputs vector.
fn replace_late_bound_regions_with_nll_infer_vars(
&self,
- mir_def_id: DefId,
+ mir_def_id: LocalDefId,
indices: &mut UniversalRegionIndices<'tcx>,
) {
debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
- let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id);
+ let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id());
for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
if !indices.indices.contains_key(&r) {
use rustc_middle::mir::visit::{PlaceContext, Visitor};
-use rustc_middle::mir::{Local, Location, Place, Statement, StatementKind, TerminatorKind};
+use rustc_middle::mir::{
+ Local, Location, Place, Statement, StatementKind, Terminator, TerminatorKind,
+};
use rustc_data_structures::fx::FxHashSet;
}
impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tcx> {
- fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, _location: Location) {
- debug!("visit_terminator_kind: kind={:?}", kind);
- match &kind {
+ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+ debug!("visit_terminator: terminator={:?}", terminator);
+ match &terminator.kind {
TerminatorKind::Call { destination: Some((into, _)), .. } => {
self.remove_never_initialized_mut_locals(*into);
}
- TerminatorKind::DropAndReplace { location, .. } => {
- self.remove_never_initialized_mut_locals(*location);
+ TerminatorKind::DropAndReplace { place, .. } => {
+ self.remove_never_initialized_mut_locals(*place);
}
_ => {}
}
+
+ self.super_terminator(terminator, location);
}
- fn visit_statement(&mut self, statement: &Statement<'tcx>, _location: Location) {
+ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
if let StatementKind::Assign(box (into, _)) = &statement.kind {
debug!(
"visit_statement: statement={:?} local={:?} \
);
self.remove_never_initialized_mut_locals(*into);
}
+
+ self.super_statement(statement, location);
}
fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) {
use std::fmt;
use rustc_middle::mir::AssertKind;
+use rustc_middle::ty::ConstInt;
use rustc_span::{Span, Symbol};
use super::InterpCx;
NeedsRfc(String),
ConstAccessesStatic,
ModifiedGlobal,
- AssertFailure(AssertKind<u64>),
+ AssertFailure(AssertKind<ConstInt>),
Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
}
_unwind: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
use rustc_middle::mir::AssertKind::*;
- // Convert `AssertKind<Operand>` to `AssertKind<u64>`.
+ // Convert `AssertKind<Operand>` to `AssertKind<Scalar>`.
+ let eval_to_int =
+ |op| ecx.read_immediate(ecx.eval_operand(op, None)?).map(|x| x.to_const_int());
let err = match msg {
BoundsCheck { ref len, ref index } => {
- let len = ecx
- .read_immediate(ecx.eval_operand(len, None)?)
- .expect("can't eval len")
- .to_scalar()?
- .to_machine_usize(&*ecx)?;
- let index = ecx
- .read_immediate(ecx.eval_operand(index, None)?)
- .expect("can't eval index")
- .to_scalar()?
- .to_machine_usize(&*ecx)?;
+ let len = eval_to_int(len)?;
+ let index = eval_to_int(index)?;
BoundsCheck { len, index }
}
- Overflow(op) => Overflow(*op),
- OverflowNeg => OverflowNeg,
- DivisionByZero => DivisionByZero,
- RemainderByZero => RemainderByZero,
+ Overflow(op, l, r) => Overflow(*op, eval_to_int(l)?, eval_to_int(r)?),
+ OverflowNeg(op) => OverflowNeg(eval_to_int(op)?),
+ DivisionByZero(op) => DivisionByZero(eval_to_int(op)?),
+ RemainderByZero(op) => RemainderByZero(eval_to_int(op)?),
ResumedAfterReturn(generator_kind) => ResumedAfterReturn(*generator_kind),
ResumedAfterPanic(generator_kind) => ResumedAfterPanic(*generator_kind),
};
ConstValue::Scalar(loc_place.ptr)
}
-// this function uses `unwrap` copiously, because an already validated constant
-// must have valid fields and can thus never fail outside of compiler bugs
+/// This function uses `unwrap` copiously, because an already validated constant
+/// must have valid fields and can thus never fail outside of compiler bugs. However, it is
+/// invoked from the pretty printer, where it can receive enums with no variants and e.g.
+/// `read_discriminant` needs to be able to handle that.
pub(crate) fn destructure_const<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
let op = ecx.eval_const_to_op(val, None).unwrap();
- let variant = ecx.read_discriminant(op).unwrap().1;
-
// We go to `usize` as we cannot allocate anything bigger anyway.
- let field_count = match val.ty.kind {
- ty::Array(_, len) => usize::try_from(len.eval_usize(tcx, param_env)).unwrap(),
- ty::Adt(def, _) => def.variants[variant].fields.len(),
- ty::Tuple(substs) => substs.len(),
+ let (field_count, variant, down) = match val.ty.kind {
+ ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
+ ty::Adt(def, _) if def.variants.is_empty() => {
+ return mir::DestructuredConst { variant: None, fields: tcx.arena.alloc_slice(&[]) };
+ }
+ ty::Adt(def, _) => {
+ let variant = ecx.read_discriminant(op).unwrap().1;
+ let down = ecx.operand_downcast(op, variant).unwrap();
+ (def.variants[variant].fields.len(), Some(variant), down)
+ }
+ ty::Tuple(substs) => (substs.len(), None, op),
_ => bug!("cannot destructure constant {:?}", val),
};
- let down = ecx.operand_downcast(op, variant).unwrap();
let fields_iter = (0..field_count).map(|i| {
let field_op = ecx.operand_field(down, i).unwrap();
let val = op_to_const(&ecx, field_op);
Goto { target } => propagate(target, exit_state),
Assert { target, cleanup: unwind, expected: _, msg: _, cond: _ }
- | Drop { target, unwind, location: _ }
- | DropAndReplace { target, unwind, value: _, location: _ }
+ | Drop { target, unwind, place: _ }
+ | DropAndReplace { target, unwind, value: _, place: _ }
| FalseUnwind { real_target: target, unwind } => {
if let Some(unwind) = unwind {
if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
self.super_terminator(terminator, location);
match terminator.kind {
- mir::TerminatorKind::Drop { location: dropped_place, .. }
- | mir::TerminatorKind::DropAndReplace { location: dropped_place, .. } => {
+ mir::TerminatorKind::Drop { place: dropped_place, .. }
+ | mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
// See documentation for `unsound_ignore_borrow_on_drop` for an explanation.
if !self.ignore_borrow_on_drop {
self.trans.gen(dropped_place.local);
///
/// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
fn shared_borrow_allows_mutation(&self, place: Place<'tcx>) -> bool {
- !place.ty(self.body, self.tcx).ty.is_freeze(self.tcx, self.param_env, DUMMY_SP)
+ !place.ty(self.body, self.tcx).ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env)
}
}
where
T: GenKill<Local>,
{
+ fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
+ let mir::Place { projection, local } = *place;
+
+ // We purposefully do not call `super_place` here to avoid calling `visit_local` for this
+ // place with one of the `Projection` variants of `PlaceContext`.
+ self.visit_projection(local, projection, context, location);
+
+ match DefUse::for_place(context) {
+ // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use.
+ Some(_) if place.is_indirect() => self.0.gen(local),
+
+ Some(DefUse::Def) if projection.is_empty() => self.0.kill(local),
+ Some(DefUse::Use) => self.0.gen(local),
+ _ => {}
+ }
+ }
+
fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
+ // Because we do not call `super_place` above, `visit_local` is only called for locals that
+ // do not appear as part of a `Place` in the MIR. This handles cases like the implicit use
+ // of the return place in a `Return` terminator or the index in an `Index` projection.
match DefUse::for_place(context) {
Some(DefUse::Def) => self.0.kill(local),
Some(DefUse::Use) => self.0.gen(local),
| MutatingUseContext::AsmOutput
| MutatingUseContext::Borrow
| MutatingUseContext::Drop
- | MutatingUseContext::Projection
| MutatingUseContext::Retag,
)
| PlaceContext::NonMutatingUse(
| NonMutatingUseContext::Copy
| NonMutatingUseContext::Inspect
| NonMutatingUseContext::Move
- | NonMutatingUseContext::Projection
| NonMutatingUseContext::ShallowBorrow
| NonMutatingUseContext::SharedBorrow
| NonMutatingUseContext::UniqueBorrow,
) => Some(DefUse::Use),
+
+ PlaceContext::MutatingUse(MutatingUseContext::Projection)
+ | PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {
+ unreachable!("A projection could be a def or a use and must be handled separately")
+ }
}
}
}
self.gather_init(place.as_ref(), InitKind::Deep);
}
- TerminatorKind::Drop { location, target: _, unwind: _ } => {
- self.gather_move(location);
+ TerminatorKind::Drop { place, target: _, unwind: _ } => {
+ self.gather_move(place);
}
- TerminatorKind::DropAndReplace { location, ref value, .. } => {
- self.create_move_path(location);
+ TerminatorKind::DropAndReplace { place, ref value, .. } => {
+ self.create_move_path(place);
self.gather_operand(value);
- self.gather_init(location.as_ref(), InitKind::Deep);
+ self.gather_init(place.as_ref(), InitKind::Deep);
}
TerminatorKind::Call {
ref func,
}
if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
- bug!("reifying a fn ptr that requires const arguments");
+ span_bug!(
+ self.cur_span(),
+ "reifying a fn ptr that requires const arguments"
+ );
}
let instance = ty::Instance::resolve_for_fn_ptr(
let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
self.write_scalar(fn_ptr, dest)?;
}
- _ => bug!("reify fn pointer on {:?}", src.layout.ty),
+ _ => span_bug!(self.cur_span(), "reify fn pointer on {:?}", src.layout.ty),
}
}
// No change to value
self.write_immediate(*src, dest)?;
}
- _ => bug!("fn to unsafe fn cast on {:?}", cast_ty),
+ _ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {:?}", cast_ty),
}
}
let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
self.write_scalar(fn_ptr, dest)?;
}
- _ => bug!("closure fn pointer on {:?}", src.layout.ty),
+ _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty),
}
}
}
assert!(src.layout.ty.is_unsafe_ptr());
return match *src {
Immediate::ScalarPair(data, _) => Ok(data.into()),
- Immediate::Scalar(..) => bug!(
+ Immediate::Scalar(..) => span_bug!(
+ self.cur_span(),
"{:?} input to a fat-to-thin cast ({:?} -> {:?})",
*src,
src.layout.ty,
}
// Casts to bool are not permitted by rustc, no need to handle them here.
- _ => bug!("invalid int to {:?} cast", cast_ty),
+ _ => span_bug!(self.cur_span(), "invalid int to {:?} cast", cast_ty),
}
}
// float -> f64
Float(FloatTy::F64) => Scalar::from_f64(f.convert(&mut false).value),
// That's it.
- _ => bug!("invalid float to {:?} cast", dest_ty),
+ _ => span_bug!(self.cur_span(), "invalid float to {:?} cast", dest_ty),
}
}
self.write_immediate(val, dest)
}
- _ => bug!("invalid unsizing {:?} -> {:?}", src.layout.ty, cast_ty),
+ _ => {
+ span_bug!(self.cur_span(), "invalid unsizing {:?} -> {:?}", src.layout.ty, cast_ty)
+ }
}
}
assert_eq!(def_a, def_b);
if def_a.is_box() || def_b.is_box() {
if !def_a.is_box() || !def_b.is_box() {
- bug!("invalid unsizing between {:?} -> {:?}", src.layout.ty, cast_ty.ty);
+ span_bug!(
+ self.cur_span(),
+ "invalid unsizing between {:?} -> {:?}",
+ src.layout.ty,
+ cast_ty.ty
+ );
}
return self.unsize_into_ptr(
src,
}
Ok(())
}
- _ => bug!("unsize_into: invalid conversion: {:?} -> {:?}", src.layout, dest.layout),
+ _ => span_bug!(
+ self.cur_span(),
+ "unsize_into: invalid conversion: {:?} -> {:?}",
+ src.layout,
+ dest.layout
+ ),
}
}
}
};
use rustc_middle::ty::layout::{self, TyAndLayout};
use rustc_middle::ty::{
- self, fold::BottomUpFolder, query::TyCtxtAt, subst::SubstsRef, Ty, TyCtxt, TypeFoldable,
+ self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
};
use rustc_span::{source_map::DUMMY_SP, Span};
use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout};
Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy,
ScalarMaybeUninit, StackPopJump,
};
+use crate::transform::validate::equal_up_to_regions;
use crate::util::storage::AlwaysLiveLocals;
pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
}
impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> {
+ /// Read the local's value or error if the local is not yet live or not live anymore.
+ ///
+ /// Note: This may only be invoked from the `Machine::access_local` hook and not from
+ /// anywhere else. You may be invalidating machine invariants if you do!
pub fn access(&self) -> InterpResult<'tcx, Operand<Tag>> {
match self.value {
LocalValue::Dead => throw_ub!(DeadLocal),
/// Overwrite the local. If the local can be overwritten in place, return a reference
/// to do so; otherwise return the `MemPlace` to consult instead.
+ ///
+ /// Note: This may only be invoked from the `Machine::access_local_mut` hook and not from
+ /// anywhere else. You may be invalidating machine invariants if you do!
pub fn access_mut(
&mut self,
) -> InterpResult<'tcx, Result<&mut LocalValue<Tag>, MemPlace<Tag>>> {
/// This test should be symmetric, as it is primarily about layout compatibility.
pub(super) fn mir_assign_valid_types<'tcx>(
tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
src: TyAndLayout<'tcx>,
dest: TyAndLayout<'tcx>,
) -> bool {
- if src.ty == dest.ty {
- // Equal types, all is good.
- return true;
- }
- if src.layout != dest.layout {
- // Layout differs, definitely not equal.
- // We do this here because Miri would *do the wrong thing* if we allowed layout-changing
- // assignments.
- return false;
- }
-
- // Type-changing assignments can happen for (at least) two reasons:
- // 1. `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment.
- // 2. Subtyping is used. While all normal lifetimes are erased, higher-ranked types
- // with their late-bound lifetimes are still around and can lead to type differences.
- // Normalize both of them away.
- let normalize = |ty: Ty<'tcx>| {
- ty.fold_with(&mut BottomUpFolder {
- tcx,
- // Normalize all references to immutable.
- ty_op: |ty| match ty.kind {
- ty::Ref(_, pointee, _) => tcx.mk_imm_ref(tcx.lifetimes.re_erased, pointee),
- _ => ty,
- },
- // We just erase all late-bound lifetimes, but this is not fully correct (FIXME):
- // lifetimes in invariant positions could matter (e.g. through associated types).
- // We rely on the fact that layout was confirmed to be equal above.
- lt_op: |_| tcx.lifetimes.re_erased,
- // Leave consts unchanged.
- ct_op: |ct| ct,
- })
- };
- normalize(src.ty) == normalize(dest.ty)
+ // Type-changing assignments can happen when subtyping is used. While
+ // all normal lifetimes are erased, higher-ranked types with their
+ // late-bound lifetimes are still around and can lead to type
+ // differences. So we compare ignoring lifetimes.
+ if equal_up_to_regions(tcx, param_env, src.ty, dest.ty) {
+ // Make sure the layout is equal, too -- just to be safe. Miri really
+ // needs layout equality. For performance reason we skip this check when
+ // the types are equal. Equal types *can* have different layouts when
+ // enum downcast is involved (as enum variants carry the type of the
+ // enum), but those should never occur in assignments.
+ if cfg!(debug_assertions) || src.ty != dest.ty {
+ assert_eq!(src.layout, dest.layout);
+ }
+ true
+ } else {
+ false
+ }
}
/// Use the already known layout if given (but sanity check in debug mode),
#[cfg_attr(not(debug_assertions), inline(always))]
pub(super) fn from_known_layout<'tcx>(
tcx: TyCtxtAt<'tcx>,
+ param_env: ParamEnv<'tcx>,
known_layout: Option<TyAndLayout<'tcx>>,
compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
Some(known_layout) => {
if cfg!(debug_assertions) {
let check_layout = compute()?;
- if !mir_assign_valid_types(tcx.tcx, check_layout, known_layout) {
+ if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) {
span_bug!(
tcx.span,
"expected type differs from actual type.\nexpected: {:?}\nactual: {:?}",
#[inline]
pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
- ty.is_freeze(*self.tcx, self.param_env, self.tcx.span)
+ ty.is_freeze(self.tcx, self.param_env)
}
pub fn load_mir(
// have to support that case (mostly by skipping all caching).
match frame.locals.get(local).and_then(|state| state.layout.get()) {
None => {
- let layout = from_known_layout(self.tcx, layout, || {
+ let layout = from_known_layout(self.tcx, self.param_env, layout, || {
let local_ty = frame.body.local_decls[local].ty;
let local_ty =
self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty);
if sized_size == Size::ZERO {
return Ok(None);
} else {
- bug!("Fields cannot be extern types, unless they are at offset 0")
+ span_bug!(
+ self.cur_span(),
+ "Fields cannot be extern types, unless they are at offset 0"
+ )
}
}
};
ty::Foreign(_) => Ok(None),
- _ => bug!("size_and_align_of::<{:?}> not supported", layout.ty),
+ _ => span_bug!(self.cur_span(), "size_and_align_of::<{:?}> not supported", layout.ty),
}
}
#[inline]
if let InternMode::Static(mutability) = mode {
// For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume
// no interior mutability.
- let frozen = ty.map_or(true, |ty| ty.is_freeze(*ecx.tcx, ecx.param_env, ecx.tcx.span));
+ let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx, ecx.param_env));
// For statics, allocation mutability is the combination of the place mutability and
// the type mutability.
// The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere.
Static(hir::Mutability),
Constant,
Promoted,
- ConstProp,
}
/// Intern `ret` and everything it references.
let base_intern_mode = match intern_kind {
InternKind::Static(mutbl) => InternMode::Static(mutbl),
// FIXME: what about array lengths, array initializers?
- InternKind::Constant | InternKind::ConstProp | InternKind::Promoted => {
- InternMode::ConstBase
- }
+ InternKind::Constant | InternKind::Promoted => InternMode::ConstBase,
};
// Type based interning.
Err(error) => {
ecx.tcx.sess.delay_span_bug(
ecx.tcx.span,
- "error during interning should later cause validation failure",
+ &format!(
+ "error during interning should later cause validation failure: {}",
+ error
+ ),
);
// Some errors shouldn't come up because creating them causes
// an allocation, which we should avoid. When that happens,
// immutability is so important.
alloc.mutability = Mutability::Not;
}
- InternKind::Constant | InternKind::ConstProp => {
+ InternKind::Constant => {
// If it's a constant, we should not have any "leftovers" as everything
// is tracked by const-checking.
// FIXME: downgrade this to a warning? It rejects some legitimate consts,
ConstValue::from_machine_usize(n, &tcx)
}
sym::type_id => ConstValue::from_u64(tcx.type_id_hash(tp_ty)),
+ sym::variant_count => {
+ if let ty::Adt(ref adt, _) = tp_ty.kind {
+ ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx)
+ } else {
+ ConstValue::from_machine_usize(0u64, &tcx)
+ }
+ }
other => bug!("`{}` is not a zero arg intrinsic", other),
})
}
| sym::needs_drop
| sym::size_of
| sym::type_id
- | sym::type_name => {
+ | sym::type_name
+ | sym::variant_count => {
let gid = GlobalId { instance, promoted: None };
let ty = match intrinsic_name {
- sym::min_align_of | sym::pref_align_of | sym::size_of => self.tcx.types.usize,
+ sym::min_align_of | sym::pref_align_of | sym::size_of | sym::variant_count => {
+ self.tcx.types.usize
+ }
sym::needs_drop => self.tcx.types.bool,
sym::type_id => self.tcx.types.u64,
sym::type_name => self.tcx.mk_static_str(),
let bits = self.force_bits(val, layout_of.size)?;
let kind = match layout_of.abi {
Abi::Scalar(ref scalar) => scalar.value,
- _ => bug!("{} called on invalid type {:?}", intrinsic_name, ty),
+ _ => span_bug!(
+ self.cur_span(),
+ "{} called on invalid type {:?}",
+ intrinsic_name,
+ ty
+ ),
};
let (nonzero, intrinsic_name) = match intrinsic_name {
sym::cttz_nonzero => (true, sym::cttz),
let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self);
self.write_scalar(offset_ptr, dest)?;
}
+ sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
+ // FIXME: return `true` for at least some comparisons where we can reliably
+ // determine the result of runtime (in)equality tests at compile-time.
+ self.write_scalar(Scalar::from_bool(false), dest)?;
+ }
sym::ptr_offset_from => {
let a = self.read_immediate(args[0])?.to_scalar()?;
let b = self.read_immediate(args[1])?.to_scalar()?;
);
self.copy_op(self.operand_index(args[0], index)?, dest)?;
}
+ // FIXME(#73156): Handle source code coverage in const eval
+ sym::count_code_region => (),
_ => return Ok(false),
}
| ty::Dynamic(_, _) => self.pretty_print_type(ty),
// Placeholders (all printed as `_` to uniformize them).
- ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error => {
+ ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
write!(self, "_")?;
Ok(self)
}
use super::{
AllocId, Allocation, AllocationExtra, CheckInAllocMsg, Frame, ImmTy, InterpCx, InterpResult,
- Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar,
+ LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar,
};
/// Data returned by Machine::stack_pop,
) -> InterpResult<'tcx>;
/// Called to read the specified `local` from the `frame`.
+ /// Since reading a ZST is not actually accessing memory or locals, this is never invoked
+ /// for ZST reads.
#[inline]
fn access_local(
_ecx: &InterpCx<'mir, 'tcx, Self>,
frame.locals[local].access()
}
+ /// Called to write the specified `local` from the `frame`.
+ /// Since writing a ZST is not actually accessing memory or locals, this is never invoked
+ /// for ZST reads.
+ #[inline]
+ fn access_local_mut<'a>(
+ ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
+ frame: usize,
+ local: mir::Local,
+ ) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>>
+ where
+ 'tcx: 'mir,
+ {
+ ecx.stack_mut()[frame].locals[local].access_mut()
+ }
+
/// Called before a basic block terminator is executed.
/// You can use this to detect endlessly running programs.
#[inline]
use rustc_macros::HashStable;
use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{ConstInt, Ty};
use rustc_middle::{mir, ty};
-use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, LayoutOf, Size};
+use rustc_target::abi::{Abi, HasDataLayout, LayoutOf, Size, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants};
use super::{
pub fn from_int(i: impl Into<i128>, layout: TyAndLayout<'tcx>) -> Self {
Self::from_scalar(Scalar::from_int(i, layout.size), layout)
}
+
+ #[inline]
+ pub fn to_const_int(self) -> ConstInt {
+ assert!(self.layout.ty.is_integral());
+ ConstInt::new(
+ self.to_scalar()
+ .expect("to_const_int doesn't work on scalar pairs")
+ .assert_bits(self.layout.size),
+ self.layout.size,
+ self.layout.ty.is_signed(),
+ self.layout.ty.is_ptr_sized_integral(),
+ )
+ }
}
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
if let Ok(imm) = self.try_read_immediate(op)? {
Ok(imm)
} else {
- bug!("primitive read failed for type: {:?}", op.layout.ty);
+ span_bug!(self.cur_span(), "primitive read failed for type: {:?}", op.layout.ty);
}
}
let val = if offset.bytes() == 0 { a } else { b };
Immediate::from(val)
}
- Immediate::Scalar(val) => {
- bug!("field access on non aggregate {:#?}, {:#?}", val, op.layout)
- }
+ Immediate::Scalar(val) => span_bug!(
+ self.cur_span(),
+ "field access on non aggregate {:#?}, {:#?}",
+ val,
+ op.layout
+ ),
};
Ok(OpTy { op: Operand::Immediate(immediate), layout: field_layout })
}
})
}
- /// This is used by [priroda](https://github.com/oli-obk/priroda) to get an OpTy from a local
+ /// Read from a local. Will not actually access the local if reading from a ZST.
+ /// Will not access memory, instead an indirect `Operand` is returned.
+ ///
+ /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an
+ /// OpTy from a local
pub fn access_local(
&self,
frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
// Sanity-check the type we ended up with.
debug_assert!(mir_assign_valid_types(
*self.tcx,
+ self.param_env,
self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
place.ty(&self.frame().body.local_decls, *self.tcx).ty
))?,
// Early-return cases.
let val_val = match val.val {
ty::ConstKind::Param(_) => throw_inval!(TooGeneric),
- ty::ConstKind::Error => throw_inval!(TypeckError(ErrorReported)),
+ ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)),
ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
let instance = self.resolve(def_id, substs)?;
// We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation.
ty::ConstKind::Infer(..)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(..) => {
- bug!("eval_const_to_op: Unexpected ConstKind {:?}", val)
+ span_bug!(self.cur_span(), "eval_const_to_op: Unexpected ConstKind {:?}", val)
}
ty::ConstKind::Value(val_val) => val_val,
};
// documentation).
let val_val = M::adjust_global_const(self, val_val)?;
// Other cases need layout.
- let layout = from_known_layout(self.tcx, layout, || self.layout_of(val.ty))?;
+ let layout =
+ from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(val.ty))?;
let op = match val_val {
ConstValue::ByRef { alloc, offset } => {
let id = self.tcx.create_memory_alloc(alloc);
op: OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, VariantIdx)> {
trace!("read_discriminant_value {:#?}", op.layout);
-
// Get type and layout of the discriminant.
let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?;
trace!("discriminant type: {:?}", discr_layout.ty);
// This is not to be confused with its "variant index", which is just determining its position in the
// declared list of variants -- they can differ with explicitly assigned discriminants.
// We use "tag" to refer to how the discriminant is encoded in memory, which can be either
- // straight-forward (`DiscriminantKind::Tag`) or with a niche (`DiscriminantKind::Niche`).
- // Unfortunately, the rest of the compiler calls the latter "discriminant", too, which makes things
- // rather confusing.
- let (tag_scalar_layout, tag_kind, tag_index) = match op.layout.variants {
+ // straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
+ let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants {
Variants::Single { index } => {
let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) {
Some(discr) => {
};
return Ok((discr, index));
}
- Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => {
- (discr, discr_kind, discr_index)
+ Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => {
+ (tag, tag_encoding, tag_field)
}
};
let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?;
// Read tag and sanity-check `tag_layout`.
- let tag_val = self.read_immediate(self.operand_field(op, tag_index)?)?;
+ let tag_val = self.read_immediate(self.operand_field(op, tag_field)?)?;
assert_eq!(tag_layout.size, tag_val.layout.size);
assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
let tag_val = tag_val.to_scalar()?;
trace!("tag value: {:?}", tag_val);
// Figure out which discriminant and variant this corresponds to.
- Ok(match *tag_kind {
- DiscriminantKind::Tag => {
+ Ok(match *tag_encoding {
+ TagEncoding::Direct => {
let tag_bits = self
.force_bits(tag_val, tag_layout.size)
- .map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
+ .map_err(|_| err_ub!(InvalidTag(tag_val.erase_tag())))?;
// Cast bits from tag layout to discriminant layout.
- let discr_val_cast = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
- let discr_bits = discr_val_cast.assert_bits(discr_layout.size);
+ let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
+ let discr_bits = discr_val.assert_bits(discr_layout.size);
// Convert discriminant to variant index, and catch invalid discriminants.
let index = match op.layout.ty.kind {
ty::Adt(adt, _) => {
.discriminants(def_id, *self.tcx)
.find(|(_, var)| var.val == discr_bits)
}
- _ => bug!("tagged layout for non-adt non-generator"),
+ _ => span_bug!(self.cur_span(), "tagged layout for non-adt non-generator"),
}
- .ok_or_else(|| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
+ .ok_or_else(|| err_ub!(InvalidTag(tag_val.erase_tag())))?;
// Return the cast value, and the index.
- (discr_val_cast, index.0)
+ (discr_val, index.0)
}
- DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => {
+ TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
// Compute the variant this niche value/"tag" corresponds to. With niche layout,
// discriminant (encoded in niche/tag) and variant index are the same.
let variants_start = niche_variants.start().as_u32();
&& variants_start == variants_end
&& !self.memory.ptr_may_be_null(ptr);
if !ptr_valid {
- throw_ub!(InvalidDiscriminant(tag_val.erase_tag()))
+ throw_ub!(InvalidTag(tag_val.erase_tag()))
}
dataful_variant
}
Le => l <= r,
Gt => l > r,
Ge => l >= r,
- _ => bug!("Invalid operation on char: {:?}", bin_op),
+ _ => span_bug!(self.cur_span(), "Invalid operation on char: {:?}", bin_op),
};
(Scalar::from_bool(res), false, self.tcx.types.bool)
}
BitAnd => l & r,
BitOr => l | r,
BitXor => l ^ r,
- _ => bug!("Invalid operation on bool: {:?}", bin_op),
+ _ => span_bug!(self.cur_span(), "Invalid operation on bool: {:?}", bin_op),
};
(Scalar::from_bool(res), false, self.tcx.types.bool)
}
Mul => ((l * r).value.into(), ty),
Div => ((l / r).value.into(), ty),
Rem => ((l % r).value.into(), ty),
- _ => bug!("invalid float op: `{:?}`", bin_op),
+ _ => span_bug!(self.cur_span(), "invalid float op: `{:?}`", bin_op),
};
(val, false, ty)
}
// For the remaining ops, the types must be the same on both sides
if left_layout.ty != right_layout.ty {
- bug!(
+ span_bug!(
+ self.cur_span(),
"invalid asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})",
bin_op,
l,
));
}
- _ => bug!(
+ _ => span_bug!(
+ self.cur_span(),
"invalid binary op {:?}: {:?}, {:?} (both {:?})",
bin_op,
l,
M::binary_ptr_op(self, bin_op, left, right)
}
- _ => bug!("Invalid MIR: bad LHS type for binop: {:?}", left.layout.ty),
+ _ => span_bug!(
+ self.cur_span(),
+ "Invalid MIR: bad LHS type for binop: {:?}",
+ left.layout.ty
+ ),
}
}
let val = val.to_bool()?;
let res = match un_op {
Not => !val,
- _ => bug!("Invalid bool op {:?}", un_op),
+ _ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op),
};
Ok((Scalar::from_bool(res), false, self.tcx.types.bool))
}
let res = match (un_op, fty) {
(Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?),
(Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
- _ => bug!("Invalid float op {:?}", un_op),
+ _ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op),
};
Ok((res, false, layout.ty))
}
use rustc_middle::mir;
use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
use rustc_middle::ty::{self, Ty};
-use rustc_target::abi::{Abi, Align, DiscriminantKind, FieldsShape};
+use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding};
use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants};
use super::{
// Sanity-check the type we ended up with.
debug_assert!(mir_assign_valid_types(
*self.tcx,
+ self.param_env,
self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
place.ty(&self.frame().body.local_decls, *self.tcx).ty
))?,
// but not factored as a separate function.
let mplace = match dest.place {
Place::Local { frame, local } => {
- match self.stack_mut()[frame].locals[local].access_mut()? {
+ match M::access_local_mut(self, frame, local)? {
Ok(local) => {
// Local can be updated in-place.
*local = LocalValue::Live(Operand::Immediate(src));
) -> InterpResult<'tcx> {
// We do NOT compare the types for equality, because well-typed code can
// actually "transmute" `&mut T` to `&T` in an assignment without a cast.
- if !mir_assign_valid_types(*self.tcx, src.layout, dest.layout) {
+ if !mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) {
span_bug!(
self.cur_span(),
"type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
src: OpTy<'tcx, M::PointerTag>,
dest: PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
- if mir_assign_valid_types(*self.tcx, src.layout, dest.layout) {
+ if mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) {
// Fast path: Just use normal `copy_op`
return self.copy_op(src, dest);
}
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> {
let (mplace, size) = match place.place {
Place::Local { frame, local } => {
- match self.stack_mut()[frame].locals[local].access_mut()? {
+ match M::access_local_mut(self, frame, local)? {
Ok(&mut local_val) => {
// We need to make an allocation.
}
// Now we can call `access_mut` again, asserting it goes well,
// and actually overwrite things.
- *self.stack_mut()[frame].locals[local].access_mut().unwrap().unwrap() =
+ *M::access_local_mut(self, frame, local).unwrap().unwrap() =
LocalValue::Live(Operand::Indirect(mplace));
(mplace, Some(size))
}
MPlaceTy { mplace, layout }
}
- pub fn write_discriminant_index(
+ /// Writes the discriminant of the given variant.
+ pub fn write_discriminant(
&mut self,
variant_index: VariantIdx,
dest: PlaceTy<'tcx, M::PointerTag>,
assert_eq!(index, variant_index);
}
Variants::Multiple {
- discr_kind: DiscriminantKind::Tag,
- discr: ref discr_layout,
- discr_index,
+ tag_encoding: TagEncoding::Direct,
+ tag: ref tag_layout,
+ tag_field,
..
} => {
// No need to validate that the discriminant here because the
// raw discriminants for enums are isize or bigger during
// their computation, but the in-memory tag is the smallest possible
// representation
- let size = discr_layout.value.size(self);
- let discr_val = truncate(discr_val, size);
+ let size = tag_layout.value.size(self);
+ let tag_val = truncate(discr_val, size);
- let discr_dest = self.place_field(dest, discr_index)?;
- self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
+ let tag_dest = self.place_field(dest, tag_field)?;
+ self.write_scalar(Scalar::from_uint(tag_val, size), tag_dest)?;
}
Variants::Multiple {
- discr_kind:
- DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start },
- discr: ref discr_layout,
- discr_index,
+ tag_encoding:
+ TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
+ tag: ref tag_layout,
+ tag_field,
..
} => {
// No need to validate that the discriminant here because the
.checked_sub(variants_start)
.expect("overflow computing relative variant idx");
// We need to use machine arithmetic when taking into account `niche_start`:
- // discr_val = variant_index_relative + niche_start_val
- let discr_layout = self.layout_of(discr_layout.value.to_int_ty(*self.tcx))?;
- let niche_start_val = ImmTy::from_uint(niche_start, discr_layout);
+ // tag_val = variant_index_relative + niche_start_val
+ let tag_layout = self.layout_of(tag_layout.value.to_int_ty(*self.tcx))?;
+ let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
let variant_index_relative_val =
- ImmTy::from_uint(variant_index_relative, discr_layout);
- let discr_val = self.binary_op(
+ ImmTy::from_uint(variant_index_relative, tag_layout);
+ let tag_val = self.binary_op(
mir::BinOp::Add,
variant_index_relative_val,
niche_start_val,
)?;
// Write result.
- let niche_dest = self.place_field(dest, discr_index)?;
- self.write_immediate(*discr_val, niche_dest)?;
+ let niche_dest = self.place_field(dest, tag_field)?;
+ self.write_immediate(*tag_val, niche_dest)?;
}
}
}
SetDiscriminant { place, variant_index } => {
let dest = self.eval_place(**place)?;
- self.write_discriminant_index(*variant_index, dest)?;
+ self.write_discriminant(*variant_index, dest)?;
}
// Mark locals as alive
Aggregate(ref kind, ref operands) => {
let (dest, active_field_index) = match **kind {
mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
- self.write_discriminant_index(variant_index, dest)?;
+ self.write_discriminant(variant_index, dest)?;
if adt_def.is_enum() {
(self.place_downcast(dest, variant_index)?, active_field_index)
} else {
Goto { target } => self.go_to_block(target),
- SwitchInt { ref discr, ref values, ref targets, .. } => {
+ SwitchInt { ref discr, ref values, ref targets, switch_ty } => {
let discr = self.read_immediate(self.eval_operand(discr, None)?)?;
trace!("SwitchInt({:?})", *discr);
+ assert_eq!(discr.layout.ty, switch_ty);
// Branch to the `otherwise` case by default, if no match is found.
assert!(!targets.is_empty());
self.go_to_block(target_block);
}
- Call {
- ref func,
- ref args,
- destination,
- ref cleanup,
- from_hir_call: _from_hir_call,
- fn_span: _,
- } => {
+ Call { ref func, ref args, destination, ref cleanup, from_hir_call: _, fn_span: _ } => {
let old_stack = self.frame_idx();
let old_loc = self.frame().loc;
let func = self.eval_operand(func, None)?;
}
}
- Drop { location, target, unwind } => {
- let place = self.eval_place(location)?;
+ Drop { place, target, unwind } => {
+ let place = self.eval_place(place)?;
let ty = place.layout.ty;
- trace!("TerminatorKind::drop: {:?}, type {}", location, ty);
+ trace!("TerminatorKind::drop: {:?}, type {}", place, ty);
let instance = Instance::resolve_drop_in_place(*self.tcx, ty);
self.drop_in_place(place, instance, target, unwind)?;
ty::FnDef(..) => instance_ty.fn_sig(*self.tcx).abi(),
ty::Closure(..) => Abi::RustCall,
ty::Generator(..) => Abi::Rust,
- _ => bug!("unexpected callee ty: {:?}", instance_ty),
+ _ => span_bug!(self.cur_span(), "unexpected callee ty: {:?}", instance_ty),
}
};
let normalize_abi = |abi| match abi {
fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem {
// First, check if we are projecting to a variant.
match layout.variants {
- Variants::Multiple { discr_index, .. } => {
- if discr_index == field {
+ Variants::Multiple { tag_field, .. } => {
+ if tag_field == field {
return match layout.ty.kind {
ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag,
ty::Generator(..) => PathElem::GeneratorTag,
| ty::Generator(..) => Ok(false),
// Some types only occur during typechecking, they have no layout.
// We should not see them here and we could not check them anyway.
- ty::Error
+ ty::Error(_)
| ty::Infer(..)
| ty::Placeholder(..)
| ty::Bound(..)
try_validation!(
self.walk_value(op),
self.path,
- err_ub!(InvalidDiscriminant(val)) =>
- { "{}", val } expected { "a valid enum discriminant" },
+ err_ub!(InvalidTag(val)) =>
+ { "{}", val } expected { "a valid enum tag" },
err_unsup!(ReadPointerAsBytes) =>
{ "a pointer" } expected { "plain (non-pointer) bytes" },
);
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_fn)]
-#![feature(const_if_match)]
-#![feature(const_loop)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
+#![cfg_attr(bootstrap, feature(const_loop))]
#![feature(const_panic)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
//! Mono Item Collection
//! ====================
//!
-//! This module is responsible for discovering all items that will contribute to
+//! This module is responsible for discovering all items that will contribute
//! to code generation of the crate. The important part here is that it not only
//! needs to find syntax-level items (functions, structs, etc) but also all
//! their monomorphized instantiations. Every non-generic, non-const function
//! function or method call (represented by a CALL terminator in MIR). But
//! calls are not the only thing that might introduce a reference between two
//! function mono items, and as we will see below, they are just a
-//! specialized of the form described next, and consequently will don't get any
+//! specialization of the form described next, and consequently will not get any
//! special treatment in the algorithm.
//!
//! #### Taking a reference to a function or method
//! - Eager mode is meant to be used in conjunction with incremental compilation
//! where a stable set of mono items is more important than a minimal
//! one. Thus, eager mode will instantiate drop-glue for every drop-able type
-//! in the crate, even of no drop call for that type exists (yet). It will
+//! in the crate, even if no drop call for that type exists (yet). It will
//! also instantiate default implementations of trait methods, something that
//! otherwise is only done on demand.
//!
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
-use rustc_errors::ErrorReported;
+use rustc_errors::{ErrorReported, FatalError};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
use rustc_session::config::EntryFnType;
+use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
use smallvec::SmallVec;
use std::iter;
tcx.sess.time("monomorphization_collector_graph_walk", || {
par_iter(roots).for_each(|root| {
let mut recursion_depths = DefIdMap::default();
- collect_items_rec(tcx, root, visited, &mut recursion_depths, inlining_map);
+ collect_items_rec(
+ tcx,
+ dummy_spanned(root),
+ visited,
+ &mut recursion_depths,
+ inlining_map,
+ );
});
});
}
// We can only codegen items that are instantiable - items all of
// whose predicates hold. Luckily, items that aren't instantiable
// can't actually be used, so we can just skip codegenning them.
- roots.retain(|root| root.is_instantiable(tcx));
-
roots
+ .into_iter()
+ .filter_map(|root| root.node.is_instantiable(tcx).then_some(root.node))
+ .collect()
}
// Collect all monomorphized items reachable from `starting_point`
fn collect_items_rec<'tcx>(
tcx: TyCtxt<'tcx>,
- starting_point: MonoItem<'tcx>,
+ starting_point: Spanned<MonoItem<'tcx>>,
visited: MTRef<'_, MTLock<FxHashSet<MonoItem<'tcx>>>>,
recursion_depths: &mut DefIdMap<usize>,
inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>,
) {
- if !visited.lock_mut().insert(starting_point) {
+ if !visited.lock_mut().insert(starting_point.node) {
// We've been here already, no need to search again.
return;
}
- debug!("BEGIN collect_items_rec({})", starting_point.to_string(tcx, true));
+ debug!("BEGIN collect_items_rec({})", starting_point.node.to_string(tcx, true));
let mut neighbors = Vec::new();
let recursion_depth_reset;
- match starting_point {
+ match starting_point.node {
MonoItem::Static(def_id) => {
let instance = Instance::mono(tcx, def_id);
debug_assert!(should_monomorphize_locally(tcx, &instance));
let ty = instance.monomorphic_ty(tcx);
- visit_drop_use(tcx, ty, true, &mut neighbors);
+ visit_drop_use(tcx, ty, true, starting_point.span, &mut neighbors);
recursion_depth_reset = None;
debug_assert!(should_monomorphize_locally(tcx, &instance));
// Keep track of the monomorphization recursion depth
- recursion_depth_reset = Some(check_recursion_limit(tcx, instance, recursion_depths));
+ recursion_depth_reset =
+ Some(check_recursion_limit(tcx, instance, starting_point.span, recursion_depths));
check_type_length_limit(tcx, instance);
rustc_data_structures::stack::ensure_sufficient_stack(|| {
}
}
- record_accesses(tcx, starting_point, &neighbors[..], inlining_map);
+ record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map);
for neighbour in neighbors {
collect_items_rec(tcx, neighbour, visited, recursion_depths, inlining_map);
recursion_depths.insert(def_id, depth);
}
- debug!("END collect_items_rec({})", starting_point.to_string(tcx, true));
+ debug!("END collect_items_rec({})", starting_point.node.to_string(tcx, true));
}
-fn record_accesses<'tcx>(
+fn record_accesses<'a, 'tcx: 'a>(
tcx: TyCtxt<'tcx>,
caller: MonoItem<'tcx>,
- callees: &[MonoItem<'tcx>],
+ callees: impl Iterator<Item = &'a MonoItem<'tcx>>,
inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>,
) {
let is_inlining_candidate = |mono_item: &MonoItem<'tcx>| {
// FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec`
// instead to avoid creating this `SmallVec`.
let accesses: SmallVec<[_; 128]> =
- callees.iter().map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect();
+ callees.map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect();
inlining_map.lock_mut().record_accesses(caller, &accesses);
}
fn check_recursion_limit<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
+ span: Span,
recursion_depths: &mut DefIdMap<usize>,
) -> (DefId, usize) {
let def_id = instance.def_id();
// infinite expansion.
if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) {
let error = format!("reached the recursion limit while instantiating `{}`", instance);
- if let Some(def_id) = def_id.as_local() {
- let hir_id = tcx.hir().as_local_hir_id(def_id);
- tcx.sess.span_fatal(tcx.hir().span(hir_id), &error);
- } else {
- tcx.sess.fatal(&error);
- }
+ let mut err = tcx.sess.struct_span_fatal(span, &error);
+ err.span_note(
+ tcx.def_span(def_id),
+ &format!("`{}` defined here", tcx.def_path_str(def_id)),
+ );
+ err.emit();
+ FatalError.raise();
}
recursion_depths.insert(def_id, recursion_depth + 1);
struct MirNeighborCollector<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
body: &'a mir::Body<'tcx>,
- output: &'a mut Vec<MonoItem<'tcx>>,
+ output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
instance: Instance<'tcx>,
}
fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
debug!("visiting rvalue {:?}", *rvalue);
+ let span = self.body.source_info(location).span;
+
match *rvalue {
// When doing an cast from a regular pointer to a fat pointer, we
// have to instantiate all methods of the trait being cast to, so we
self.tcx,
target_ty,
source_ty,
+ span,
self.output,
);
}
) => {
let fn_ty = operand.ty(self.body, self.tcx);
let fn_ty = self.monomorphize(fn_ty);
- visit_fn_use(self.tcx, fn_ty, false, &mut self.output);
+ visit_fn_use(self.tcx, fn_ty, false, span, &mut self.output);
}
mir::Rvalue::Cast(
mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)),
ty::ClosureKind::FnOnce,
);
if should_monomorphize_locally(self.tcx, &instance) {
- self.output.push(create_fn_mono_item(instance));
+ self.output.push(create_fn_mono_item(instance, span));
}
}
_ => bug!(),
tcx.require_lang_item(ExchangeMallocFnLangItem, None);
let instance = Instance::mono(tcx, exchange_malloc_fn_def_id);
if should_monomorphize_locally(tcx, &instance) {
- self.output.push(create_fn_mono_item(instance));
+ self.output.push(create_fn_mono_item(instance, span));
+ }
+ }
+ mir::Rvalue::ThreadLocalRef(def_id) => {
+ assert!(self.tcx.is_thread_local_static(def_id));
+ let instance = Instance::mono(self.tcx, def_id);
+ if should_monomorphize_locally(self.tcx, &instance) {
+ trace!("collecting thread-local static {:?}", def_id);
+ self.output.push(respan(span, MonoItem::Static(def_id)));
}
}
_ => { /* not interesting */ }
self.super_const(constant);
}
- fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location: Location) {
- debug!("visiting terminator {:?} @ {:?}", kind, location);
+ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
+ debug!("visiting terminator {:?} @ {:?}", terminator, location);
+ let source = self.body.source_info(location).span;
let tcx = self.tcx;
- match *kind {
+ match terminator.kind {
mir::TerminatorKind::Call { ref func, .. } => {
let callee_ty = func.ty(self.body, tcx);
let callee_ty = self.monomorphize(callee_ty);
- visit_fn_use(self.tcx, callee_ty, true, &mut self.output);
+ visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output);
}
- mir::TerminatorKind::Drop { ref location, .. }
- | mir::TerminatorKind::DropAndReplace { ref location, .. } => {
- let ty = location.ty(self.body, self.tcx).ty;
+ mir::TerminatorKind::Drop { ref place, .. }
+ | mir::TerminatorKind::DropAndReplace { ref place, .. } => {
+ let ty = place.ty(self.body, self.tcx).ty;
let ty = self.monomorphize(ty);
- visit_drop_use(self.tcx, ty, true, self.output);
+ visit_drop_use(self.tcx, ty, true, source, self.output);
}
mir::TerminatorKind::InlineAsm { ref operands, .. } => {
for op in operands {
match *op {
mir::InlineAsmOperand::SymFn { ref value } => {
let fn_ty = self.monomorphize(value.literal.ty);
- visit_fn_use(self.tcx, fn_ty, false, &mut self.output);
+ visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output);
}
mir::InlineAsmOperand::SymStatic { def_id } => {
let instance = Instance::mono(self.tcx, def_id);
if should_monomorphize_locally(self.tcx, &instance) {
trace!("collecting asm sym static {:?}", def_id);
- self.output.push(MonoItem::Static(def_id));
+ self.output.push(respan(source, MonoItem::Static(def_id)));
}
}
_ => {}
| mir::TerminatorKind::FalseUnwind { .. } => bug!(),
}
- self.super_terminator_kind(kind, location);
+ self.super_terminator(terminator, location);
}
fn visit_local(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
is_direct_call: bool,
- output: &mut Vec<MonoItem<'tcx>>,
+ source: Span,
+ output: &mut Vec<Spanned<MonoItem<'tcx>>>,
) {
let instance = Instance::resolve_drop_in_place(tcx, ty);
- visit_instance_use(tcx, instance, is_direct_call, output);
+ visit_instance_use(tcx, instance, is_direct_call, source, output);
}
fn visit_fn_use<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
is_direct_call: bool,
- output: &mut Vec<MonoItem<'tcx>>,
+ source: Span,
+ output: &mut Vec<Spanned<MonoItem<'tcx>>>,
) {
if let ty::FnDef(def_id, substs) = ty.kind {
let instance = if is_direct_call {
ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, substs)
.unwrap()
};
- visit_instance_use(tcx, instance, is_direct_call, output);
+ visit_instance_use(tcx, instance, is_direct_call, source, output);
}
}
tcx: TyCtxt<'tcx>,
instance: ty::Instance<'tcx>,
is_direct_call: bool,
- output: &mut Vec<MonoItem<'tcx>>,
+ source: Span,
+ output: &mut Vec<Spanned<MonoItem<'tcx>>>,
) {
debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call);
if !should_monomorphize_locally(tcx, &instance) {
ty::InstanceDef::DropGlue(_, None) => {
// Don't need to emit noop drop glue if we are calling directly.
if !is_direct_call {
- output.push(create_fn_mono_item(instance));
+ output.push(create_fn_mono_item(instance, source));
}
}
ty::InstanceDef::DropGlue(_, Some(_))
| ty::InstanceDef::Item(..)
| ty::InstanceDef::FnPtrShim(..)
| ty::InstanceDef::CloneShim(..) => {
- output.push(create_fn_mono_item(instance));
+ output.push(create_fn_mono_item(instance, source));
}
}
}
let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
let param_env = ty::ParamEnv::reveal_all();
let type_has_metadata = |ty: Ty<'tcx>| -> bool {
- use rustc_span::DUMMY_SP;
if ty.is_sized(tcx.at(DUMMY_SP), param_env) {
return false;
}
}
}
-fn create_fn_mono_item(instance: Instance<'_>) -> MonoItem<'_> {
+fn create_fn_mono_item(instance: Instance<'_>, source: Span) -> Spanned<MonoItem<'_>> {
debug!("create_fn_mono_item(instance={})", instance);
- MonoItem::Fn(instance)
+ respan(source, MonoItem::Fn(instance))
}
/// Creates a `MonoItem` for each method that is referenced by the vtable for
tcx: TyCtxt<'tcx>,
trait_ty: Ty<'tcx>,
impl_ty: Ty<'tcx>,
- output: &mut Vec<MonoItem<'tcx>>,
+ source: Span,
+ output: &mut Vec<Spanned<MonoItem<'tcx>>>,
) {
assert!(
!trait_ty.needs_subst()
.unwrap()
})
.filter(|&instance| should_monomorphize_locally(tcx, &instance))
- .map(create_fn_mono_item);
+ .map(|item| create_fn_mono_item(item, source));
output.extend(methods);
}
// Also add the destructor.
- visit_drop_use(tcx, impl_ty, false, output);
+ visit_drop_use(tcx, impl_ty, false, source, output);
}
}
struct RootCollector<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
mode: MonoItemCollectionMode,
- output: &'a mut Vec<MonoItem<'tcx>>,
+ output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
entry_fn: Option<(LocalDefId, EntryFnType)>,
}
let ty = Instance::new(def_id.to_def_id(), InternalSubsts::empty())
.monomorphic_ty(self.tcx);
- visit_drop_use(self.tcx, ty, true, self.output);
+ visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output);
}
}
}
"RootCollector: ItemKind::GlobalAsm({})",
def_id_to_string(self.tcx, self.tcx.hir().local_def_id(item.hir_id))
);
- self.output.push(MonoItem::GlobalAsm(item.hir_id));
+ self.output.push(dummy_spanned(MonoItem::GlobalAsm(item.hir_id)));
}
hir::ItemKind::Static(..) => {
let def_id = self.tcx.hir().local_def_id(item.hir_id);
debug!("RootCollector: ItemKind::Static({})", def_id_to_string(self.tcx, def_id));
- self.output.push(MonoItem::Static(def_id.to_def_id()));
+ self.output.push(dummy_spanned(MonoItem::Static(def_id.to_def_id())));
}
hir::ItemKind::Const(..) => {
// const items only generate mono items if they are
debug!("RootCollector::push_if_root: found root def_id={:?}", def_id);
let instance = Instance::mono(self.tcx, def_id.to_def_id());
- self.output.push(create_fn_mono_item(instance));
+ self.output.push(create_fn_mono_item(instance, DUMMY_SP));
}
}
.unwrap()
.unwrap();
- self.output.push(create_fn_mono_item(start_instance));
+ self.output.push(create_fn_mono_item(start_instance, DUMMY_SP));
}
}
fn create_mono_items_for_default_impls<'tcx>(
tcx: TyCtxt<'tcx>,
item: &'tcx hir::Item<'tcx>,
- output: &mut Vec<MonoItem<'tcx>>,
+ output: &mut Vec<Spanned<MonoItem<'tcx>>>,
) {
match item.kind {
hir::ItemKind::Impl { ref generics, ref items, .. } => {
.unwrap()
.unwrap();
- let mono_item = create_fn_mono_item(instance);
- if mono_item.is_instantiable(tcx) && should_monomorphize_locally(tcx, &instance)
+ let mono_item = create_fn_mono_item(instance, DUMMY_SP);
+ if mono_item.node.is_instantiable(tcx)
+ && should_monomorphize_locally(tcx, &instance)
{
output.push(mono_item);
}
}
/// Scans the miri alloc in order to find function calls, closures, and drop-glue.
-fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec<MonoItem<'tcx>>) {
+fn collect_miri<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ alloc_id: AllocId,
+ output: &mut Vec<Spanned<MonoItem<'tcx>>>,
+) {
match tcx.global_alloc(alloc_id) {
GlobalAlloc::Static(def_id) => {
assert!(!tcx.is_thread_local_static(def_id));
let instance = Instance::mono(tcx, def_id);
if should_monomorphize_locally(tcx, &instance) {
trace!("collecting static {:?}", def_id);
- output.push(MonoItem::Static(def_id));
+ output.push(dummy_spanned(MonoItem::Static(def_id)));
}
}
GlobalAlloc::Memory(alloc) => {
GlobalAlloc::Function(fn_instance) => {
if should_monomorphize_locally(tcx, &fn_instance) {
trace!("collecting {:?} with {:#?}", alloc_id, fn_instance);
- output.push(create_fn_mono_item(fn_instance));
+ output.push(create_fn_mono_item(fn_instance, DUMMY_SP));
}
}
}
fn collect_neighbours<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
- output: &mut Vec<MonoItem<'tcx>>,
+ output: &mut Vec<Spanned<MonoItem<'tcx>>>,
) {
debug!("collect_neighbours: {:?}", instance.def_id());
let body = tcx.instance_mir(instance.def);
fn collect_const_value<'tcx>(
tcx: TyCtxt<'tcx>,
value: ConstValue<'tcx>,
- output: &mut Vec<MonoItem<'tcx>>,
+ output: &mut Vec<Spanned<MonoItem<'tcx>>>,
) {
match value {
ConstValue::Scalar(Scalar::Ptr(ptr)) => collect_miri(tcx, ptr.alloc_id, output),
fn merge_codegen_units<'tcx>(
tcx: TyCtxt<'tcx>,
initial_partitioning: &mut PreInliningPartitioning<'tcx>,
- mut target_cgu_count: usize,
+ target_cgu_count: usize,
) {
assert!(target_cgu_count >= 1);
let codegen_units = &mut initial_partitioning.codegen_units;
- if tcx.is_compiler_builtins(LOCAL_CRATE) {
- // Compiler builtins require some degree of control over how mono items
- // are partitioned into compilation units. Provide it by keeping the
- // original partitioning when compiling the compiler builtins crate.
- target_cgu_count = codegen_units.len();
- }
-
// Note that at this point in time the `codegen_units` here may not be in a
// deterministic order (but we know they're deterministically the same set).
// We want this merging to produce a deterministic ordering of codegen units
let mut result = match instance {
ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance),
- ty::InstanceDef::VtableShim(def_id) => build_call_shim(
- tcx,
- instance,
- Some(Adjustment::DerefMove),
- CallKind::Direct(def_id),
- None,
- ),
+ ty::InstanceDef::VtableShim(def_id) => {
+ build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id), None)
+ }
ty::InstanceDef::FnPtrShim(def_id, ty) => {
// FIXME(eddyb) support generating shims for a "shallow type",
// e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
let arg_tys = sig.inputs();
- build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect, Some(arg_tys))
+ build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty), Some(arg_tys))
}
// We are generating a call back to our def-id, which the
// codegen backend knows to turn to an actual call, be it
#[derive(Copy, Clone, Debug, PartialEq)]
enum Adjustment {
+ /// Pass the receiver as-is.
Identity,
+
+ /// We get passed `&[mut] self` and call the target with `*self`.
+ ///
+ /// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it
+ /// (for `VtableShim`, which effectively is passed `&own Self`).
Deref,
- DerefMove,
+
+ /// We get passed `self: Self` and call the target with `&mut self`.
+ ///
+ /// In this case we need to ensure that the `Self` is dropped after the call, as the callee
+ /// won't do it for us.
RefMut,
}
#[derive(Copy, Clone, Debug, PartialEq)]
-enum CallKind {
- Indirect,
+enum CallKind<'tcx> {
+ /// Call the `FnPtr` that was passed as the receiver.
+ Indirect(Ty<'tcx>),
+
+ /// Call a known `FnDef`.
Direct(DefId),
}
arg_count,
vec![],
span,
- vec![],
None,
)
}
let param_env = tcx.param_env(def_id);
let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
- let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span);
+ let is_copy = self_ty.is_copy_modulo_regions(tcx.at(builder.span), param_env);
let dest = Place::return_place();
let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
self.block(
vec![],
TerminatorKind::Drop {
- location: self.tcx.mk_place_index(dest, beg),
+ place: self.tcx.mk_place_index(dest, beg),
target: BasicBlock::new(8),
unwind: None,
},
self.block(
vec![],
TerminatorKind::Drop {
- location: previous_field,
+ place: previous_field,
target: previous_cleanup,
unwind: None,
},
tcx: TyCtxt<'tcx>,
instance: ty::InstanceDef<'tcx>,
rcvr_adjustment: Option<Adjustment>,
- call_kind: CallKind,
+ call_kind: CallKind<'tcx>,
untuple_args: Option<&[Ty<'tcx>]>,
) -> Body<'tcx> {
debug!(
let sig = tcx.fn_sig(def_id);
let mut sig = tcx.erase_late_bound_regions(&sig);
+ if let CallKind::Indirect(fnty) = call_kind {
+ // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
+ // can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from
+ // the implemented `FnX` trait.
+
+ // Apply the opposite adjustment to the MIR input.
+ let mut inputs_and_output = sig.inputs_and_output.to_vec();
+
+ // Initial signature is `fn(&? Self, Args) -> Self::Output` where `Args` is a tuple of the
+ // fn arguments. `Self` may be passed via (im)mutable reference or by-value.
+ assert_eq!(inputs_and_output.len(), 3);
+
+ // `Self` is always the original fn type `ty`. The MIR call terminator is only defined for
+ // `FnDef` and `FnPtr` callees, not the `Self` type param.
+ let self_arg = &mut inputs_and_output[0];
+ *self_arg = match rcvr_adjustment.unwrap() {
+ Adjustment::Identity => fnty,
+ Adjustment::Deref => tcx.mk_imm_ptr(fnty),
+ Adjustment::RefMut => tcx.mk_mut_ptr(fnty),
+ };
+ sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
+ }
+
// FIXME(eddyb) avoid having this snippet both here and in
// `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?).
if let ty::InstanceDef::VtableShim(..) = instance {
let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment {
Adjustment::Identity => Operand::Move(rcvr_place()),
- Adjustment::Deref => Operand::Move(tcx.mk_place_deref(rcvr_place())), // Can't copy `&mut`
- Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_place())),
+ Adjustment::Deref => Operand::Move(tcx.mk_place_deref(rcvr_place())),
Adjustment::RefMut => {
// let rcvr = &mut rcvr;
let ref_rcvr = local_decls.push(
});
let (callee, mut args) = match call_kind {
- CallKind::Indirect => (rcvr.unwrap(), vec![]),
+ // `FnPtr` call has no receiver. Args are untupled below.
+ CallKind::Indirect(_) => (rcvr.unwrap(), vec![]),
+
+ // `FnDef` call with optional receiver.
CallKind::Direct(def_id) => {
let ty = tcx.type_of(def_id);
(
block(
&mut blocks,
vec![],
- TerminatorKind::Drop {
- location: rcvr_place(),
- target: BasicBlock::new(2),
- unwind: None,
- },
+ TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(2), unwind: None },
false,
);
}
block(
&mut blocks,
vec![],
- TerminatorKind::Drop {
- location: rcvr_place(),
- target: BasicBlock::new(4),
- unwind: None,
- },
+ TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(4), unwind: None },
true,
);
let terminator = data.terminator();
match terminator.kind {
- TerminatorKind::Drop { location, .. }
- if util::is_disaligned(tcx, body, param_env, location) =>
+ TerminatorKind::Drop { place, .. }
+ if util::is_disaligned(tcx, body, param_env, place) =>
{
add_move_for_packed_drop(tcx, body, &mut patch, terminator, loc, data.is_cleanup);
}
is_cleanup: bool,
) {
debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc);
- let (location, target, unwind) = match terminator.kind {
- TerminatorKind::Drop { ref location, target, unwind } => (location, target, unwind),
+ let (place, target, unwind) = match terminator.kind {
+ TerminatorKind::Drop { ref place, target, unwind } => (place, target, unwind),
_ => unreachable!(),
};
let source_info = terminator.source_info;
- let ty = location.ty(body, tcx).ty;
+ let ty = place.ty(body, tcx).ty;
let temp = patch.new_temp(ty, terminator.source_info.span);
let storage_dead_block = patch.new_block(BasicBlockData {
});
patch.add_statement(loc, StatementKind::StorageLive(temp));
- patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*location)));
+ patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place)));
patch.patch_terminator(
loc.block,
- TerminatorKind::Drop { location: Place::from(temp), target: storage_dead_block, unwind },
+ TerminatorKind::Drop { place: Place::from(temp), target: storage_dead_block, unwind },
);
}
}
}
-#[derive(Debug)]
-pub struct IfOrMatch;
-impl NonConstOp for IfOrMatch {
- fn feature_gate() -> Option<Symbol> {
- Some(sym::const_if_match)
- }
-
- fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
- // This should be caught by the HIR const-checker.
- ccx.tcx.sess.delay_span_bug(span, "complex control flow is forbidden in a const context");
- }
-}
-
#[derive(Debug)]
pub struct InlineAsm;
impl NonConstOp for InlineAsm {}
#[derive(Debug)]
-pub struct LiveDrop;
+pub struct LiveDrop(pub Option<Span>);
impl NonConstOp for LiveDrop {
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
- struct_span_err!(
+ let mut diagnostic = struct_span_err!(
ccx.tcx.sess,
span,
E0493,
"destructors cannot be evaluated at compile-time"
- )
- .span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()))
- .emit();
- }
-}
-
-#[derive(Debug)]
-pub struct Loop;
-impl NonConstOp for Loop {
- fn feature_gate() -> Option<Symbol> {
- Some(sym::const_loop)
- }
-
- fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
- // This should be caught by the HIR const-checker.
- ccx.tcx.sess.delay_span_bug(span, "complex control flow is forbidden in a const context");
+ );
+ diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
+ if let Some(span) = self.0 {
+ diagnostic.span_label(span, "value is dropped here");
+ }
+ diagnostic.emit();
}
}
#[derive(Debug)]
pub struct MutBorrow;
impl NonConstOp for MutBorrow {
+ fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
+ // Forbid everywhere except in const fn
+ ccx.const_kind() == hir::ConstContext::ConstFn
+ && ccx.tcx.features().enabled(Self::feature_gate().unwrap())
+ }
+
fn feature_gate() -> Option<Symbol> {
Some(sym::const_mut_refs)
}
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
- let mut err = feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_mut_refs,
- span,
- &format!(
- "references in {}s may only refer \
- to immutable values",
- ccx.const_kind()
- ),
- );
- err.span_label(span, format!("{}s require immutable values", ccx.const_kind()));
+ let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn {
+ feature_err(
+ &ccx.tcx.sess.parse_sess,
+ sym::const_mut_refs,
+ span,
+ &format!("mutable references are not allowed in {}s", ccx.const_kind()),
+ )
+ } else {
+ struct_span_err!(
+ ccx.tcx.sess,
+ span,
+ E0764,
+ "mutable references are not allowed in {}s",
+ ccx.const_kind(),
+ )
+ };
+ err.span_label(span, "`&mut` is only allowed in `const fn`".to_string());
if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
err.note(
"References in statics and constants may only refer \
#[derive(Debug)]
pub struct RawPtrComparison;
impl NonConstOp for RawPtrComparison {
- fn feature_gate() -> Option<Symbol> {
- Some(sym::const_compare_raw_pointers)
- }
-
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
- feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_compare_raw_pointers,
- span,
- &format!("comparing raw pointers inside {}", ccx.const_kind()),
- )
- .emit();
+ let mut err = ccx
+ .tcx
+ .sess
+ .struct_span_err(span, "pointers cannot be reliably compared during const eval.");
+ err.note(
+ "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
+ for more information",
+ );
+ err.emit();
}
}
impl CheckLiveDrops<'mir, 'tcx> {
fn check_live_drop(&self, span: Span) {
- ops::non_const(self.ccx, ops::LiveDrop, span);
+ ops::non_const(self.ccx, ops::LiveDrop(None), span);
}
}
trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
match &terminator.kind {
- mir::TerminatorKind::Drop { location: dropped_place, .. } => {
+ mir::TerminatorKind::Drop { place: dropped_place, .. } => {
let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
return;
}
fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
- !ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP)
+ !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env)
}
fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {
self.super_assign(place, rvalue, location);
}
- fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location: Location) {
+ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
// The effect of assignment to the return place in `TerminatorKind::Call` is not applied
// here; that occurs in `apply_call_return_effect`.
- if let mir::TerminatorKind::DropAndReplace { value, location: dest, .. } = kind {
+ if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind {
let qualif = qualifs::in_operand::<Q, _>(
self.ccx,
&mut |l| self.qualifs_per_local.contains(l),
value,
);
- if !dest.is_indirect() {
- self.assign_qualif_direct(dest, qualif);
+ if !place.is_indirect() {
+ self.assign_qualif_direct(place, qualif);
}
}
// We need to assign qualifs to the dropped location before visiting the operand that
// replaces it since qualifs can be cleared on move.
- self.super_terminator_kind(kind, location);
+ self.super_terminator(terminator, location);
}
}
}
}
- check_short_circuiting_in_const_local(self.ccx);
-
- if body.is_cfg_cyclic() {
- // We can't provide a good span for the error here, but this should be caught by the
- // HIR const-checker anyways.
- self.check_op_spanned(ops::Loop, body.span);
- }
-
self.visit_body(&body);
// Ensure that the end result is `Sync` in a non-thread local `static`.
self.super_statement(statement, location);
}
- StatementKind::FakeRead(
- FakeReadCause::ForMatchedPlace
- | FakeReadCause::ForMatchGuard
- | FakeReadCause::ForGuardBinding,
- _,
- ) => {
- self.super_statement(statement, location);
- self.check_op(ops::IfOrMatch);
- }
StatementKind::LlvmInlineAsm { .. } => {
self.super_statement(statement, location);
self.check_op(ops::InlineAsm);
}
- StatementKind::FakeRead(FakeReadCause::ForLet | FakeReadCause::ForIndex, _)
+ StatementKind::FakeRead(..)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Retag { .. }
// Forbid all `Drop` terminators unless the place being dropped is a local with no
// projections that cannot be `NeedsDrop`.
- TerminatorKind::Drop { location: dropped_place, .. }
- | TerminatorKind::DropAndReplace { location: dropped_place, .. } => {
+ TerminatorKind::Drop { place: dropped_place, .. }
+ | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
// If we are checking live drops after drop-elaboration, don't emit duplicate
// errors here.
if super::post_drop_elaboration::checking_enabled(self.tcx) {
};
if needs_drop {
- self.check_op_spanned(ops::LiveDrop, err_span);
+ self.check_op_spanned(
+ ops::LiveDrop(Some(terminator.source_info.span)),
+ err_span,
+ );
}
}
.emit();
}
-fn check_short_circuiting_in_const_local(ccx: &ConstCx<'_, 'tcx>) {
- let body = ccx.body;
-
- if body.control_flow_destroyed.is_empty() {
- return;
- }
-
- let mut locals = body.vars_iter();
- if let Some(local) = locals.next() {
- let span = body.local_decls[local].source_info.span;
- let mut error = ccx.tcx.sess.struct_span_err(
- span,
- &format!(
- "new features like let bindings are not permitted in {}s \
- which also use short circuiting operators",
- ccx.const_kind(),
- ),
- );
- for (span, kind) in body.control_flow_destroyed.iter() {
- error.span_note(
- *span,
- &format!(
- "use of {} here does not actually short circuit due to \
- the const evaluator presently not being able to do control flow. \
- See issue #49146 <https://github.com/rust-lang/rust/issues/49146> \
- for more information.",
- kind
- ),
- );
- }
- for local in locals {
- let span = body.local_decls[local].source_info.span;
- error.span_note(span, "more locals are defined here");
- }
- error.emit();
- }
-}
-
fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) {
let ty = body.return_ty();
tcx.infer_ctxt().enter(|infcx| {
_ => {}
}
}
- // raw pointer and fn pointer operations are unsafe as it is not clear whether one
- // pointer would be "less" or "equal" to another, because we cannot know where llvm
- // or the linker will place various statics in memory. Without this information the
- // result of a comparison of addresses would differ between runtime and compile-time.
- Rvalue::BinaryOp(_, ref lhs, _)
- if self.const_context && self.tcx.features().const_compare_raw_pointers =>
- {
- if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind {
- self.require_unsafe(
- "pointer operation",
- "operations on pointers in constants",
- UnsafetyViolationKind::General,
- );
- }
- }
_ => {}
}
self.super_rvalue(rvalue, location);
),
};
if !elem_ty.is_copy_modulo_regions(
- self.tcx,
+ self.tcx.at(self.source_info.span),
self.param_env,
- self.source_info.span,
) {
self.require_unsafe(
"assignment to non-`Copy` union field",
// Check `is_freeze` as late as possible to avoid cycle errors
// with opaque types.
- } else if !place.ty(self.body, self.tcx).ty.is_freeze(
- self.tcx,
- self.param_env,
- self.source_info.span,
- ) {
+ } else if !place
+ .ty(self.body, self.tcx)
+ .ty
+ .is_freeze(self.tcx.at(self.source_info.span), self.param_env)
+ {
(
"borrow of layout constrained field with interior \
mutability",
use std::cell::Cell;
use rustc_ast::ast::Mutability;
+use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::DefKind;
use rustc_hir::HirId;
use rustc_index::bit_set::BitSet;
};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutError, TyAndLayout};
use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, ConstInt, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable};
use rustc_session::lint;
use rustc_span::{def_id::DefId, Span};
use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TargetDataLayout};
use crate::const_eval::error_to_const_error;
use crate::interpret::{
- self, compile_time_machine, intern_const_alloc_recursive, AllocId, Allocation, Frame, ImmTy,
- Immediate, InternKind, InterpCx, LocalState, LocalValue, Memory, MemoryKind, OpTy,
- Operand as InterpOperand, PlaceTy, Pointer, ScalarMaybeUninit, StackPopCleanup,
+ self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx, LocalState,
+ LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
+ ScalarMaybeUninit, StackPopCleanup,
};
use crate::transform::{MirPass, MirSource};
body.arg_count,
Default::default(),
tcx.def_span(source.def_id()),
- Default::default(),
body.generator_kind,
);
struct ConstPropMachine<'mir, 'tcx> {
/// The virtual call stack.
stack: Vec<Frame<'mir, 'tcx, (), ()>>,
+ /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end.
+ written_only_inside_own_block_locals: FxHashSet<Local>,
+ /// Locals that need to be cleared after every block terminates.
+ only_propagate_inside_block_locals: BitSet<Local>,
}
impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> {
- fn new() -> Self {
- Self { stack: Vec::new() }
+ fn new(only_propagate_inside_block_locals: BitSet<Local>) -> Self {
+ Self {
+ stack: Vec::new(),
+ written_only_inside_own_block_locals: Default::default(),
+ only_propagate_inside_block_locals,
+ }
}
}
l.access()
}
+ fn access_local_mut<'a>(
+ ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
+ frame: usize,
+ local: Local,
+ ) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>>
+ {
+ if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) {
+ ecx.machine.written_only_inside_own_block_locals.insert(local);
+ }
+ ecx.machine.stack[frame].locals[local].access_mut()
+ }
+
fn before_access_global(
_memory_extra: &(),
_alloc_id: AllocId,
// Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
// the last known `SourceInfo` here and just keep revisiting it.
source_info: Option<SourceInfo>,
- // Locals we need to forget at the end of the current block
- locals_of_current_block: BitSet<Local>,
}
impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> {
let param_env = tcx.param_env(def_id).with_reveal_all();
let span = tcx.def_span(def_id);
- let mut ecx = InterpCx::new(tcx, span, param_env, ConstPropMachine::new(), ());
let can_const_prop = CanConstProp::check(body);
+ let mut only_propagate_inside_block_locals = BitSet::new_empty(can_const_prop.len());
+ for (l, mode) in can_const_prop.iter_enumerated() {
+ if *mode == ConstPropMode::OnlyInsideOwnBlock {
+ only_propagate_inside_block_locals.insert(l);
+ }
+ }
+ let mut ecx = InterpCx::new(
+ tcx,
+ span,
+ param_env,
+ ConstPropMachine::new(only_propagate_inside_block_locals),
+ (),
+ );
let ret = ecx
.layout_of(body.return_ty().subst(tcx, substs))
//FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
local_decls: body.local_decls.clone(),
source_info: None,
- locals_of_current_block: BitSet::new_empty(body.local_decls.len()),
}
}
fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
- let op = self.ecx.eval_place_to_op(place, None).ok();
+ let op = match self.ecx.eval_place_to_op(place, None) {
+ Ok(op) => op,
+ Err(e) => {
+ trace!("get_const failed: {}", e);
+ return None;
+ }
+ };
// Try to read the local as an immediate so that if it is representable as a scalar, we can
// handle it as such, but otherwise, just return the value as is.
- match op.map(|ret| self.ecx.try_read_immediate(ret)) {
- Some(Ok(Ok(imm))) => Some(imm.into()),
+ Some(match self.ecx.try_read_immediate(op) {
+ Ok(Ok(imm)) => imm.into(),
_ => op,
- }
+ })
}
/// Remove `local` from the pool of `Locals`. Allows writing to them,
lint: &'static lint::Lint,
source_info: SourceInfo,
message: &'static str,
- panic: AssertKind<u64>,
+ panic: AssertKind<ConstInt>,
) -> Option<()> {
let lint_root = self.lint_root(source_info)?;
self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| {
arg: &Operand<'tcx>,
source_info: SourceInfo,
) -> Option<()> {
- if self.use_ecx(|this| {
+ if let (val, true) = self.use_ecx(|this| {
let val = this.ecx.read_immediate(this.ecx.eval_operand(arg, None)?)?;
let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, val)?;
- Ok(overflow)
+ Ok((val, overflow))
})? {
// `AssertKind` only has an `OverflowNeg` variant, so make sure that is
// appropriate to use.
lint::builtin::ARITHMETIC_OVERFLOW,
source_info,
"this arithmetic operation will overflow",
- AssertKind::OverflowNeg,
+ AssertKind::OverflowNeg(val.to_const_int()),
)?;
}
) -> Option<()> {
let r =
self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(right, None)?))?;
+ let l = self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(left, None)?));
// Check for exceeding shifts *even if* we cannot evaluate the LHS.
if op == BinOp::Shr || op == BinOp::Shl {
// We need the type of the LHS. We cannot use `place_layout` as that is the type
// of the result, which for checked binops is not the same!
let left_ty = left.ty(&self.local_decls, self.tcx);
- let left_size_bits = self.ecx.layout_of(left_ty).ok()?.size.bits();
+ let left_size = self.ecx.layout_of(left_ty).ok()?.size;
let right_size = r.layout.size;
let r_bits = r.to_scalar().ok();
// This is basically `force_bits`.
let r_bits = r_bits.and_then(|r| r.to_bits_or_ptr(right_size, &self.tcx).ok());
- if r_bits.map_or(false, |b| b >= left_size_bits as u128) {
+ if r_bits.map_or(false, |b| b >= left_size.bits() as u128) {
debug!("check_binary_op: reporting assert for {:?}", source_info);
self.report_assert_as_lint(
lint::builtin::ARITHMETIC_OVERFLOW,
source_info,
"this arithmetic operation will overflow",
- AssertKind::Overflow(op),
+ AssertKind::Overflow(
+ op,
+ match l {
+ Some(l) => l.to_const_int(),
+ // Invent a dummy value, the diagnostic ignores it anyway
+ None => ConstInt::new(
+ 1,
+ left_size,
+ left_ty.is_signed(),
+ left_ty.is_ptr_sized_integral(),
+ ),
+ },
+ r.to_const_int(),
+ ),
)?;
}
}
+ let l = l?;
+
// The remaining operators are handled through `overflowing_binary_op`.
if self.use_ecx(|this| {
- let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?;
let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
Ok(overflow)
})? {
lint::builtin::ARITHMETIC_OVERFLOW,
source_info,
"this arithmetic operation will overflow",
- AssertKind::Overflow(op),
+ AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
)?;
}
}
// Do not try creating references (#67862)
- Rvalue::Ref(_, _, place_ref) => {
- trace!("skipping Ref({:?})", place_ref);
+ Rvalue::AddressOf(_, place) | Rvalue::Ref(_, _, place) => {
+ trace!("skipping AddressOf | Ref for {:?}", place);
+
+ // This may be creating mutable references or immutable references to cells.
+ // If that happens, the pointed to value could be mutated via that reference.
+ // Since we aren't tracking references, the const propagator loses track of what
+ // value the local has right now.
+ // Thus, all locals that have their reference taken
+ // must not take part in propagation.
+ Self::remove_const(&mut self.ecx, place.local);
return None;
}
ScalarMaybeUninit::Scalar(l),
ScalarMaybeUninit::Scalar(r),
)) => l.is_bits() && r.is_bits(),
- interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
- let mplace = op.assert_mem_place(&self.ecx);
- intern_const_alloc_recursive(&mut self.ecx, InternKind::ConstProp, mplace, false);
- true
- }
_ => false,
}
}
OnlyInsideOwnBlock,
/// The `Local` can be propagated into but reads cannot be propagated.
OnlyPropagateInto,
- /// No propagation is allowed at all.
+ /// The `Local` cannot be part of propagation at all. Any statement
+ /// referencing it either for reading or writing will not get propagated.
NoPropagation,
}
// end of the block anyway, and inside the block we overwrite previous
// states as applicable.
ConstPropMode::OnlyInsideOwnBlock => {}
- other => {
+ ConstPropMode::NoPropagation => {}
+ ConstPropMode::OnlyPropagateInto => {}
+ other @ ConstPropMode::FullConstProp => {
trace!(
"local {:?} can't be propagated because of multiple assignments",
local,
);
- *other = ConstPropMode::NoPropagation;
+ *other = ConstPropMode::OnlyPropagateInto;
}
}
}
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
let can_const_prop = self.can_const_prop[place.local];
if let Some(()) = self.const_prop(rval, place_layout, source_info, place) {
- if can_const_prop != ConstPropMode::NoPropagation {
- // This will return None for variables that are from other blocks,
- // so it should be okay to propagate from here on down.
- if let Some(value) = self.get_const(place) {
- if self.should_const_prop(value) {
- trace!("replacing {:?} with {:?}", rval, value);
- self.replace_with_const(rval, value, source_info);
- if can_const_prop == ConstPropMode::FullConstProp
- || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
- {
- trace!("propagated into {:?}", place);
- }
- }
- if can_const_prop == ConstPropMode::OnlyInsideOwnBlock {
- trace!(
- "found local restricted to its block. Will remove it from const-prop after block is finished. Local: {:?}",
- place.local
- );
- self.locals_of_current_block.insert(place.local);
+ // This will return None if the above `const_prop` invocation only "wrote" a
+ // type whose creation requires no write. E.g. a generator whose initial state
+ // consists solely of uninitialized memory (so it doesn't capture any locals).
+ if let Some(value) = self.get_const(place) {
+ if self.should_const_prop(value) {
+ trace!("replacing {:?} with {:?}", rval, value);
+ self.replace_with_const(rval, value, source_info);
+ if can_const_prop == ConstPropMode::FullConstProp
+ || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
+ {
+ trace!("propagated into {:?}", place);
}
}
}
- if can_const_prop == ConstPropMode::OnlyPropagateInto
- || can_const_prop == ConstPropMode::NoPropagation
- {
- trace!("can't propagate into {:?}", place);
- if place.local != RETURN_PLACE {
- Self::remove_const(&mut self.ecx, place.local);
+ match can_const_prop {
+ ConstPropMode::OnlyInsideOwnBlock => {
+ trace!(
+ "found local restricted to its block. \
+ Will remove it from const-prop after block is finished. Local: {:?}",
+ place.local
+ );
}
+ ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => {
+ trace!("can't propagate into {:?}", place);
+ if place.local != RETURN_PLACE {
+ Self::remove_const(&mut self.ecx, place.local);
+ }
+ }
+ ConstPropMode::FullConstProp => {}
}
} else {
// Const prop failed, so erase the destination, ensuring that whatever happens
);
Self::remove_const(&mut self.ecx, place.local);
}
+ } else {
+ trace!(
+ "cannot propagate into {:?}, because the type of the local is generic.",
+ place,
+ );
+ Self::remove_const(&mut self.ecx, place.local);
}
} else {
match statement.kind {
}
Operand::Constant(_) => {}
}
+ let mut eval_to_int = |op| {
+ let op = self
+ .eval_operand(op, source_info)
+ .expect("if we got here, it must be const");
+ self.ecx.read_immediate(op).unwrap().to_const_int()
+ };
let msg = match msg {
- AssertKind::DivisionByZero => AssertKind::DivisionByZero,
- AssertKind::RemainderByZero => AssertKind::RemainderByZero,
+ AssertKind::DivisionByZero(op) => {
+ AssertKind::DivisionByZero(eval_to_int(op))
+ }
+ AssertKind::RemainderByZero(op) => {
+ AssertKind::RemainderByZero(eval_to_int(op))
+ }
AssertKind::BoundsCheck { ref len, ref index } => {
- let len =
- self.eval_operand(len, source_info).expect("len must be const");
- let len = self
- .ecx
- .read_scalar(len)
- .unwrap()
- .to_machine_usize(&self.tcx)
- .unwrap();
- let index = self
- .eval_operand(index, source_info)
- .expect("index must be const");
- let index = self
- .ecx
- .read_scalar(index)
- .unwrap()
- .to_machine_usize(&self.tcx)
- .unwrap();
+ let len = eval_to_int(len);
+ let index = eval_to_int(index);
AssertKind::BoundsCheck { len, index }
}
// Overflow is are already covered by checks on the binary operators.
- AssertKind::Overflow(_) | AssertKind::OverflowNeg => return,
+ AssertKind::Overflow(..) | AssertKind::OverflowNeg(_) => return,
// Need proper const propagator for these.
_ => return,
};
}
}
}
- // We remove all Locals which are restricted in propagation to their containing blocks.
- for local in self.locals_of_current_block.iter() {
+
+ // We remove all Locals which are restricted in propagation to their containing blocks and
+ // which were modified in the current block.
+ // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`
+ let mut locals = std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals);
+ for &local in locals.iter() {
Self::remove_const(&mut self.ecx, local);
}
- self.locals_of_current_block.clear();
+ locals.clear();
+ // Put it back so we reuse the heap of the storage
+ self.ecx.machine.written_only_inside_own_block_locals = locals;
+ if cfg!(debug_assertions) {
+ // Ensure we are correctly erasing locals with the non-debug-assert logic.
+ for local in self.ecx.machine.only_propagate_inside_block_locals.iter() {
+ assert!(
+ self.get_const(local.into()).is_none()
+ || self
+ .layout_of(self.local_decls[local].ty)
+ .map_or(true, |layout| layout.is_zst())
+ )
+ }
+ }
}
}
.iterate_to_fixpoint()
.into_results_cursor(body);
for (bb, bb_data) in body.basic_blocks().iter_enumerated() {
- let location = match bb_data.terminator().kind {
- TerminatorKind::Drop { ref location, unwind: Some(_), .. }
- | TerminatorKind::DropAndReplace { ref location, unwind: Some(_), .. } => location,
+ let place = match bb_data.terminator().kind {
+ TerminatorKind::Drop { ref place, unwind: Some(_), .. }
+ | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => place,
_ => continue,
};
debug!("find_dead_unwinds @ {:?}: {:?}", bb, bb_data);
- let path = match env.move_data.rev_lookup.find(location.as_ref()) {
+ let path = match env.move_data.rev_lookup.find(place.as_ref()) {
LookupResult::Exact(e) => e,
LookupResult::Parent(..) => {
debug!("find_dead_unwinds: has parent; skipping");
debug!(
"find_dead_unwinds @ {:?}: path({:?})={:?}; init_data={:?}",
bb,
- location,
+ place,
path,
flow_inits.get()
);
fn collect_drop_flags(&mut self) {
for (bb, data) in self.body.basic_blocks().iter_enumerated() {
let terminator = data.terminator();
- let location = match terminator.kind {
- TerminatorKind::Drop { ref location, .. }
- | TerminatorKind::DropAndReplace { ref location, .. } => location,
+ let place = match terminator.kind {
+ TerminatorKind::Drop { ref place, .. }
+ | TerminatorKind::DropAndReplace { ref place, .. } => place,
_ => continue,
};
self.init_data.seek_before(self.body.terminator_loc(bb));
- let path = self.move_data().rev_lookup.find(location.as_ref());
- debug!("collect_drop_flags: {:?}, place {:?} ({:?})", bb, location, path);
+ let path = self.move_data().rev_lookup.find(place.as_ref());
+ debug!("collect_drop_flags: {:?}, place {:?} ({:?})", bb, place, path);
let path = match path {
LookupResult::Exact(e) => e,
terminator.source_info.span,
"drop of untracked, uninitialized value {:?}, place {:?} ({:?})",
bb,
- location,
+ place,
path
);
}
debug!(
"collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}",
child,
- location,
+ place,
path,
(maybe_live, maybe_dead)
);
let resume_block = self.patch.resume_block();
match terminator.kind {
- TerminatorKind::Drop { location, target, unwind } => {
+ TerminatorKind::Drop { place, target, unwind } => {
self.init_data.seek_before(loc);
- match self.move_data().rev_lookup.find(location.as_ref()) {
+ match self.move_data().rev_lookup.find(place.as_ref()) {
LookupResult::Exact(path) => elaborate_drop(
&mut Elaborator { ctxt: self },
terminator.source_info,
- location,
+ place,
path,
target,
if data.is_cleanup {
}
}
}
- TerminatorKind::DropAndReplace { location, ref value, target, unwind } => {
+ TerminatorKind::DropAndReplace { place, ref value, target, unwind } => {
assert!(!data.is_cleanup);
- self.elaborate_replace(loc, location, value, target, unwind);
+ self.elaborate_replace(loc, place, value, target, unwind);
}
_ => continue,
}
fn elaborate_replace(
&mut self,
loc: Location,
- location: Place<'tcx>,
+ place: Place<'tcx>,
value: &Operand<'tcx>,
target: BasicBlock,
unwind: Option<BasicBlock>,
assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported");
let assign = Statement {
- kind: StatementKind::Assign(box (location, Rvalue::Use(value.clone()))),
+ kind: StatementKind::Assign(box (place, Rvalue::Use(value.clone()))),
source_info: terminator.source_info,
};
is_cleanup: false,
});
- match self.move_data().rev_lookup.find(location.as_ref()) {
+ match self.move_data().rev_lookup.find(place.as_ref()) {
LookupResult::Exact(path) => {
debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path);
self.init_data.seek_before(loc);
elaborate_drop(
&mut Elaborator { ctxt: self },
terminator.source_info,
- location,
+ place,
path,
target,
Unwind::To(unwind),
debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent);
self.patch.patch_terminator(
bb,
- TerminatorKind::Drop { location, target, unwind: Some(unwind) },
+ TerminatorKind::Drop { place, target, unwind: Some(unwind) },
);
}
}
use rustc_hir::lang_items::{GeneratorStateLangItem, PinTypeLangItem};
use rustc_index::bit_set::{BitMatrix, BitSet};
use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::mir::visit::{MutVisitor, PlaceContext};
+use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::GeneratorSubsts;
use rustc_target::abi::VariantIdx;
use rustc_target::spec::PanicStrategy;
use std::borrow::Cow;
-use std::iter;
+use std::{iter, ops};
pub struct StateTransform;
}
}
- fn visit_terminator_kind(&mut self, kind: &mut TerminatorKind<'tcx>, location: Location) {
- match kind {
+ fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
+ match terminator.kind {
TerminatorKind::Return => {
// Do not replace the implicit `_0` access here, as that's not possible. The
// transform already handles `return` correctly.
}
- _ => self.super_terminator_kind(kind, location),
+ _ => self.super_terminator(terminator, location),
}
}
}
struct LivenessInfo {
/// Which locals are live across any suspension point.
- ///
- /// GeneratorSavedLocal is indexed in terms of the elements in this set;
- /// i.e. GeneratorSavedLocal::new(1) corresponds to the second local
- /// included in this set.
- live_locals: BitSet<Local>,
+ saved_locals: GeneratorSavedLocals,
/// The set of saved locals live at each suspension point.
live_locals_at_suspension_points: Vec<BitSet<GeneratorSavedLocal>>,
+ /// Parallel vec to the above with SourceInfo for each yield terminator.
+ source_info_at_suspension_points: Vec<SourceInfo>,
+
/// For every saved local, the set of other saved locals that are
/// storage-live at the same time as this local. We cannot overlap locals in
/// the layout which have conflicting storage.
let mut storage_liveness_map = IndexVec::from_elem(None, body.basic_blocks());
let mut live_locals_at_suspension_points = Vec::new();
+ let mut source_info_at_suspension_points = Vec::new();
let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len());
for (block, data) in body.basic_blocks().iter_enumerated() {
live_locals_at_any_suspension_point.union(&live_locals);
live_locals_at_suspension_points.push(live_locals);
+ source_info_at_suspension_points.push(data.terminator().source_info);
}
}
+
debug!("live_locals_anywhere = {:?}", live_locals_at_any_suspension_point);
+ let saved_locals = GeneratorSavedLocals(live_locals_at_any_suspension_point);
// Renumber our liveness_map bitsets to include only the locals we are
// saving.
let live_locals_at_suspension_points = live_locals_at_suspension_points
.iter()
- .map(|live_here| renumber_bitset(&live_here, &live_locals_at_any_suspension_point))
+ .map(|live_here| saved_locals.renumber_bitset(&live_here))
.collect();
let storage_conflicts = compute_storage_conflicts(
body_ref,
- &live_locals_at_any_suspension_point,
+ &saved_locals,
always_live_locals.clone(),
requires_storage_results,
);
LivenessInfo {
- live_locals: live_locals_at_any_suspension_point,
+ saved_locals,
live_locals_at_suspension_points,
+ source_info_at_suspension_points,
storage_conflicts,
storage_liveness: storage_liveness_map,
}
}
-/// Renumbers the items present in `stored_locals` and applies the renumbering
-/// to 'input`.
+/// The set of `Local`s that must be saved across yield points.
///
-/// For example, if `stored_locals = [1, 3, 5]`, this would be renumbered to
-/// `[0, 1, 2]`. Thus, if `input = [3, 5]` we would return `[1, 2]`.
-fn renumber_bitset(
- input: &BitSet<Local>,
- stored_locals: &BitSet<Local>,
-) -> BitSet<GeneratorSavedLocal> {
- assert!(stored_locals.superset(&input), "{:?} not a superset of {:?}", stored_locals, input);
- let mut out = BitSet::new_empty(stored_locals.count());
- for (idx, local) in stored_locals.iter().enumerate() {
- let saved_local = GeneratorSavedLocal::from(idx);
- if input.contains(local) {
- out.insert(saved_local);
+/// `GeneratorSavedLocal` is indexed in terms of the elements in this set;
+/// i.e. `GeneratorSavedLocal::new(1)` corresponds to the second local
+/// included in this set.
+struct GeneratorSavedLocals(BitSet<Local>);
+
+impl GeneratorSavedLocals {
+ /// Returns an iterator over each `GeneratorSavedLocal` along with the `Local` it corresponds
+ /// to.
+ fn iter_enumerated(&self) -> impl '_ + Iterator<Item = (GeneratorSavedLocal, Local)> {
+ self.iter().enumerate().map(|(i, l)| (GeneratorSavedLocal::from(i), l))
+ }
+
+ /// Transforms a `BitSet<Local>` that contains only locals saved across yield points to the
+ /// equivalent `BitSet<GeneratorSavedLocal>`.
+ fn renumber_bitset(&self, input: &BitSet<Local>) -> BitSet<GeneratorSavedLocal> {
+ assert!(self.superset(&input), "{:?} not a superset of {:?}", self.0, input);
+ let mut out = BitSet::new_empty(self.count());
+ for (saved_local, local) in self.iter_enumerated() {
+ if input.contains(local) {
+ out.insert(saved_local);
+ }
}
+ out
+ }
+
+ fn get(&self, local: Local) -> Option<GeneratorSavedLocal> {
+ if !self.contains(local) {
+ return None;
+ }
+
+ let idx = self.iter().take_while(|&l| l < local).count();
+ Some(GeneratorSavedLocal::new(idx))
+ }
+}
+
+impl ops::Deref for GeneratorSavedLocals {
+ type Target = BitSet<Local>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
}
- debug!("renumber_bitset({:?}, {:?}) => {:?}", input, stored_locals, out);
- out
}
/// For every saved local, looks for which locals are StorageLive at the same
/// computation; see `GeneratorLayout` for more.
fn compute_storage_conflicts(
body: &'mir Body<'tcx>,
- stored_locals: &BitSet<Local>,
+ saved_locals: &GeneratorSavedLocals,
always_live_locals: storage::AlwaysLiveLocals,
requires_storage: dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
- assert_eq!(body.local_decls.len(), stored_locals.domain_size());
+ assert_eq!(body.local_decls.len(), saved_locals.domain_size());
debug!("compute_storage_conflicts({:?})", body.span);
debug!("always_live = {:?}", always_live_locals);
// Locals that are always live or ones that need to be stored across
// suspension points are not eligible for overlap.
let mut ineligible_locals = always_live_locals.into_inner();
- ineligible_locals.intersect(stored_locals);
+ ineligible_locals.intersect(saved_locals);
// Compute the storage conflicts for all eligible locals.
let mut visitor = StorageConflictVisitor {
body,
- stored_locals: &stored_locals,
+ saved_locals: &saved_locals,
local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()),
};
// However, in practice these bitsets are not usually large. The layout code
// also needs to keep track of how many conflicts each local has, so it's
// simpler to keep it this way for now.
- let mut storage_conflicts = BitMatrix::new(stored_locals.count(), stored_locals.count());
- for (idx_a, local_a) in stored_locals.iter().enumerate() {
- let saved_local_a = GeneratorSavedLocal::new(idx_a);
+ let mut storage_conflicts = BitMatrix::new(saved_locals.count(), saved_locals.count());
+ for (saved_local_a, local_a) in saved_locals.iter_enumerated() {
if ineligible_locals.contains(local_a) {
// Conflicts with everything.
storage_conflicts.insert_all_into_row(saved_local_a);
} else {
// Keep overlap information only for stored locals.
- for (idx_b, local_b) in stored_locals.iter().enumerate() {
- let saved_local_b = GeneratorSavedLocal::new(idx_b);
+ for (saved_local_b, local_b) in saved_locals.iter_enumerated() {
if local_conflicts.contains(local_a, local_b) {
storage_conflicts.insert(saved_local_a, saved_local_b);
}
struct StorageConflictVisitor<'mir, 'tcx, 's> {
body: &'mir Body<'tcx>,
- stored_locals: &'s BitSet<Local>,
+ saved_locals: &'s GeneratorSavedLocals,
// FIXME(tmandry): Consider using sparse bitsets here once we have good
// benchmarks for generators.
local_conflicts: BitMatrix<Local, Local>,
}
let mut eligible_storage_live = flow_state.clone();
- eligible_storage_live.intersect(&self.stored_locals);
+ eligible_storage_live.intersect(&self.saved_locals);
for local in eligible_storage_live.iter() {
self.local_conflicts.union_row_with(&eligible_storage_live, local);
}
}
-/// Validates the typeck view of the generator against the actual set of types retained between
+/// Validates the typeck view of the generator against the actual set of types saved between
/// yield points.
fn sanitize_witness<'tcx>(
tcx: TyCtxt<'tcx>,
did: DefId,
witness: Ty<'tcx>,
upvars: &Vec<Ty<'tcx>>,
- retained: &BitSet<Local>,
+ saved_locals: &GeneratorSavedLocals,
) {
let allowed_upvars = tcx.erase_regions(upvars);
let allowed = match witness.kind {
let param_env = tcx.param_env(did);
for (local, decl) in body.local_decls.iter_enumerated() {
- // Ignore locals which are internal or not retained between yields.
- if !retained.contains(local) || decl.internal {
+ // Ignore locals which are internal or not saved between yields.
+ if !saved_locals.contains(local) || decl.internal {
continue;
}
let decl_ty = tcx.normalize_erasing_regions(param_env, decl.ty);
}
fn compute_layout<'tcx>(
- tcx: TyCtxt<'tcx>,
- source: MirSource<'tcx>,
- upvars: &Vec<Ty<'tcx>>,
- interior: Ty<'tcx>,
- always_live_locals: &storage::AlwaysLiveLocals,
- movable: bool,
+ liveness: LivenessInfo,
body: &mut Body<'tcx>,
) -> (
FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>,
GeneratorLayout<'tcx>,
IndexVec<BasicBlock, Option<BitSet<Local>>>,
) {
- // Use a liveness analysis to compute locals which are live across a suspension point
let LivenessInfo {
- live_locals,
+ saved_locals,
live_locals_at_suspension_points,
+ source_info_at_suspension_points,
storage_conflicts,
storage_liveness,
- } = locals_live_across_suspend_points(tcx, body, source, always_live_locals, movable);
-
- sanitize_witness(tcx, body, source.def_id(), interior, upvars, &live_locals);
+ } = liveness;
// Gather live local types and their indices.
let mut locals = IndexVec::<GeneratorSavedLocal, _>::new();
let mut tys = IndexVec::<GeneratorSavedLocal, _>::new();
- for (idx, local) in live_locals.iter().enumerate() {
+ for (saved_local, local) in saved_locals.iter_enumerated() {
locals.push(local);
tys.push(body.local_decls[local].ty);
- debug!("generator saved local {:?} => {:?}", GeneratorSavedLocal::from(idx), local);
+ debug!("generator saved local {:?} => {:?}", saved_local, local);
}
// Leave empty variants for the UNRESUMED, RETURNED, and POISONED states.
+ // In debuginfo, these will correspond to the beginning (UNRESUMED) or end
+ // (RETURNED, POISONED) of the function.
const RESERVED_VARIANTS: usize = 3;
+ let body_span = body.source_scopes[OUTERMOST_SOURCE_SCOPE].span;
+ let mut variant_source_info: IndexVec<VariantIdx, SourceInfo> = [
+ SourceInfo::outermost(body_span.shrink_to_lo()),
+ SourceInfo::outermost(body_span.shrink_to_hi()),
+ SourceInfo::outermost(body_span.shrink_to_hi()),
+ ]
+ .iter()
+ .copied()
+ .collect();
// Build the generator variant field list.
// Create a map from local indices to generator struct indices.
remap.entry(locals[saved_local]).or_insert((tys[saved_local], variant_index, idx));
}
variant_fields.push(fields);
+ variant_source_info.push(source_info_at_suspension_points[suspension_point_idx]);
}
debug!("generator variant_fields = {:?}", variant_fields);
debug!("generator storage_conflicts = {:#?}", storage_conflicts);
- let layout = GeneratorLayout { field_tys: tys, variant_fields, storage_conflicts };
+ let layout =
+ GeneratorLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts };
(remap, layout, storage_liveness)
}
for (block, block_data) in body.basic_blocks().iter_enumerated() {
let (target, unwind, source_info) = match block_data.terminator() {
- Terminator { source_info, kind: TerminatorKind::Drop { location, target, unwind } } => {
- if let Some(local) = location.as_local() {
+ Terminator { source_info, kind: TerminatorKind::Drop { place, target, unwind } } => {
+ if let Some(local) = place.as_local() {
if local == SELF_ARG {
(target, unwind, source_info)
} else {
fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
let return_block = insert_term_block(body, TerminatorKind::Return);
- let term = TerminatorKind::Drop {
- location: Place::from(SELF_ARG),
- target: return_block,
- unwind: None,
- };
+ let term =
+ TerminatorKind::Drop { place: Place::from(SELF_ARG), target: return_block, unwind: None };
let source_info = SourceInfo::outermost(body.span);
// Create a block to destroy an unresumed generators. This can only destroy upvars.
let always_live_locals = storage::AlwaysLiveLocals::new(&body);
+ let liveness_info =
+ locals_live_across_suspend_points(tcx, body, source, &always_live_locals, movable);
+
+ sanitize_witness(tcx, body, def_id, interior, &upvars, &liveness_info.saved_locals);
+
+ if tcx.sess.opts.debugging_opts.validate_mir {
+ let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias {
+ assigned_local: None,
+ saved_locals: &liveness_info.saved_locals,
+ storage_conflicts: &liveness_info.storage_conflicts,
+ };
+
+ vis.visit_body(body);
+ }
+
// Extract locals which are live across suspension point into `layout`
// `remap` gives a mapping from local indices onto generator struct indices
// `storage_liveness` tells us which locals have live storage at suspension points
- let (remap, layout, storage_liveness) =
- compute_layout(tcx, source, &upvars, interior, &always_live_locals, movable, body);
+ let (remap, layout, storage_liveness) = compute_layout(liveness_info, body);
let can_return = can_return(tcx, body);
create_generator_resume_function(tcx, transform, source, body, can_return);
}
}
+
+/// Looks for any assignments between locals (e.g., `_4 = _5`) that will both be converted to fields
+/// in the generator state machine but whose storage is not marked as conflicting
+///
+/// Validation needs to happen immediately *before* `TransformVisitor` is invoked, not after.
+///
+/// This condition would arise when the assignment is the last use of `_5` but the initial
+/// definition of `_4` if we weren't extra careful to mark all locals used inside a statement as
+/// conflicting. Non-conflicting generator saved locals may be stored at the same location within
+/// the generator state machine, which would result in ill-formed MIR: the left-hand and right-hand
+/// sides of an assignment may not alias. This caused a miscompilation in [#73137].
+///
+/// [#73137]: https://github.com/rust-lang/rust/issues/73137
+struct EnsureGeneratorFieldAssignmentsNeverAlias<'a> {
+ saved_locals: &'a GeneratorSavedLocals,
+ storage_conflicts: &'a BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
+ assigned_local: Option<GeneratorSavedLocal>,
+}
+
+impl EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
+ fn saved_local_for_direct_place(&self, place: Place<'_>) -> Option<GeneratorSavedLocal> {
+ if place.is_indirect() {
+ return None;
+ }
+
+ self.saved_locals.get(place.local)
+ }
+
+ fn check_assigned_place(&mut self, place: Place<'tcx>, f: impl FnOnce(&mut Self)) {
+ if let Some(assigned_local) = self.saved_local_for_direct_place(place) {
+ assert!(self.assigned_local.is_none(), "`check_assigned_place` must not recurse");
+
+ self.assigned_local = Some(assigned_local);
+ f(self);
+ self.assigned_local = None;
+ }
+ }
+}
+
+impl Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
+ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
+ let lhs = match self.assigned_local {
+ Some(l) => l,
+ None => {
+ // This visitor only invokes `visit_place` for the right-hand side of an assignment
+ // and only after setting `self.assigned_local`. However, the default impl of
+ // `Visitor::super_body` may call `visit_place` with a `NonUseContext` for places
+ // with debuginfo. Ignore them here.
+ assert!(!context.is_use());
+ return;
+ }
+ };
+
+ let rhs = match self.saved_local_for_direct_place(*place) {
+ Some(l) => l,
+ None => return,
+ };
+
+ if !self.storage_conflicts.contains(lhs, rhs) {
+ bug!(
+ "Assignment between generator saved locals whose storage is not \
+ marked as conflicting: {:?}: {:?} = {:?}",
+ location,
+ lhs,
+ rhs,
+ );
+ }
+ }
+
+ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
+ match &statement.kind {
+ StatementKind::Assign(box (lhs, rhs)) => {
+ self.check_assigned_place(*lhs, |this| this.visit_rvalue(rhs, location));
+ }
+
+ // FIXME: Does `llvm_asm!` have any aliasing requirements?
+ StatementKind::LlvmInlineAsm(_) => {}
+
+ StatementKind::FakeRead(..)
+ | StatementKind::SetDiscriminant { .. }
+ | StatementKind::StorageLive(_)
+ | StatementKind::StorageDead(_)
+ | StatementKind::Retag(..)
+ | StatementKind::AscribeUserType(..)
+ | StatementKind::Nop => {}
+ }
+ }
+
+ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+ // Checking for aliasing in terminators is probably overkill, but until we have actual
+ // semantics, we should be conservative here.
+ match &terminator.kind {
+ TerminatorKind::Call {
+ func,
+ args,
+ destination: Some((dest, _)),
+ cleanup: _,
+ from_hir_call: _,
+ fn_span: _,
+ } => {
+ self.check_assigned_place(*dest, |this| {
+ this.visit_operand(func, location);
+ for arg in args {
+ this.visit_operand(arg, location);
+ }
+ });
+ }
+
+ TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
+ self.check_assigned_place(*resume_arg, |this| this.visit_operand(value, location));
+ }
+
+ // FIXME: Does `asm!` have any aliasing requirements?
+ TerminatorKind::InlineAsm { .. } => {}
+
+ TerminatorKind::Call { .. }
+ | TerminatorKind::Goto { .. }
+ | TerminatorKind::SwitchInt { .. }
+ | TerminatorKind::Resume
+ | TerminatorKind::Abort
+ | TerminatorKind::Return
+ | TerminatorKind::Unreachable
+ | TerminatorKind::Drop { .. }
+ | TerminatorKind::DropAndReplace { .. }
+ | TerminatorKind::Assert { .. }
+ | TerminatorKind::GeneratorDrop
+ | TerminatorKind::FalseEdge { .. }
+ | TerminatorKind::FalseUnwind { .. } => {}
+ }
+ }
+}
use rustc_middle::mir::*;
use rustc_middle::ty::subst::{Subst, SubstsRef};
use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
-use rustc_session::config::Sanitizer;
use rustc_target::spec::abi::Abi;
use super::simplify::{remove_dead_blocks, CfgSimplifier};
// Avoid inlining functions marked as no_sanitize if sanitizer is enabled,
// since instrumentation might be enabled and performed on the caller.
- match self.tcx.sess.opts.debugging_opts.sanitizer {
- Some(Sanitizer::Address) => {
- if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_ADDRESS) {
- return false;
- }
- }
- Some(Sanitizer::Memory) => {
- if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_MEMORY) {
- return false;
- }
- }
- Some(Sanitizer::Thread) => {
- if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_THREAD) {
- return false;
- }
- }
- Some(Sanitizer::Leak) => {}
- None => {}
+ if self.tcx.sess.opts.debugging_opts.sanitizer.intersects(codegen_fn_attrs.no_sanitize) {
+ return false;
}
let hinted = match codegen_fn_attrs.inline {
let term = blk.terminator();
let mut is_drop = false;
match term.kind {
- TerminatorKind::Drop { ref location, target, unwind }
- | TerminatorKind::DropAndReplace { ref location, target, unwind, .. } => {
+ TerminatorKind::Drop { ref place, target, unwind }
+ | TerminatorKind::DropAndReplace { ref place, target, unwind, .. } => {
is_drop = true;
work_list.push(target);
- // If the location doesn't actually need dropping, treat it like
+ // If the place doesn't actually need dropping, treat it like
// a regular goto.
- let ty = location.ty(callee_body, tcx).subst(tcx, callsite.substs).ty;
+ let ty = place.ty(callee_body, tcx).subst(tcx, callsite.substs).ty;
if ty.needs_drop(tcx, param_env) {
cost += CALL_PENALTY;
if let Some(unwind) = unwind {
}
}
- fn visit_terminator_kind(&mut self, kind: &mut TerminatorKind<'tcx>, loc: Location) {
+ fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, loc: Location) {
// Don't try to modify the implicit `_0` access on return (`return` terminators are
// replaced down below anyways).
- if !matches!(kind, TerminatorKind::Return) {
- self.super_terminator_kind(kind, loc);
+ if !matches!(terminator.kind, TerminatorKind::Return) {
+ self.super_terminator(terminator, loc);
}
- match *kind {
+ match terminator.kind {
TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => bug!(),
TerminatorKind::Goto { ref mut target } => {
*target = self.update_target(*target);
}
}
TerminatorKind::Return => {
- *kind = TerminatorKind::Goto { target: self.return_block };
+ terminator.kind = TerminatorKind::Goto { target: self.return_block };
}
TerminatorKind::Resume => {
if let Some(tgt) = self.cleanup_block {
- *kind = TerminatorKind::Goto { target: tgt }
+ terminator.kind = TerminatorKind::Goto { target: tgt }
}
}
TerminatorKind::Abort => {}
--- /dev/null
+use crate::transform::{MirPass, MirSource};
+use crate::util::patch::MirPatch;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir::lang_items;
+use rustc_middle::hir;
+use rustc_middle::ich::StableHashingContext;
+use rustc_middle::mir::interpret::{ConstValue, Scalar};
+use rustc_middle::mir::{
+ self, traversal, BasicBlock, BasicBlockData, CoverageData, Operand, Place, SourceInfo,
+ StatementKind, Terminator, TerminatorKind, START_BLOCK,
+};
+use rustc_middle::ty;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{ConstKind, FnDef};
+use rustc_span::def_id::DefId;
+use rustc_span::Span;
+
+/// Inserts call to count_code_region() as a placeholder to be replaced during code generation with
+/// the intrinsic llvm.instrprof.increment.
+pub struct InstrumentCoverage;
+
+/// The `query` provider for `CoverageData`, requested by `codegen_intrinsic_call()` when
+/// constructing the arguments for `llvm.instrprof.increment`.
+pub(crate) fn provide(providers: &mut Providers<'_>) {
+ providers.coverage_data = |tcx, def_id| {
+ let mir_body = tcx.optimized_mir(def_id);
+ // FIXME(richkadel): The current implementation assumes the MIR for the given DefId
+ // represents a single function. Validate and/or correct if inlining and/or monomorphization
+ // invalidates these assumptions.
+ let count_code_region_fn =
+ tcx.require_lang_item(lang_items::CountCodeRegionFnLangItem, None);
+ let mut num_counters: u32 = 0;
+ // The `num_counters` argument to `llvm.instrprof.increment` is the number of injected
+ // counters, with each counter having an index from `0..num_counters-1`. MIR optimization
+ // may split and duplicate some BasicBlock sequences. Simply counting the calls may not
+ // not work; but computing the num_counters by adding `1` to the highest index (for a given
+ // instrumented function) is valid.
+ for (_, data) in traversal::preorder(mir_body) {
+ if let Some(terminator) = &data.terminator {
+ if let TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
+ &terminator.kind
+ {
+ if let FnDef(called_fn_def_id, _) = func.literal.ty.kind {
+ if called_fn_def_id == count_code_region_fn {
+ if let Operand::Constant(constant) =
+ args.get(0).expect("count_code_region has at least one arg")
+ {
+ if let ConstKind::Value(ConstValue::Scalar(value)) =
+ constant.literal.val
+ {
+ let index = value
+ .to_u32()
+ .expect("count_code_region index at arg0 is u32");
+ num_counters = std::cmp::max(num_counters, index + 1);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ let hash = if num_counters > 0 { hash_mir_source(tcx, def_id) } else { 0 };
+ CoverageData { num_counters, hash }
+ };
+}
+
+struct Instrumentor<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ num_counters: u32,
+}
+
+impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, mir_body: &mut mir::Body<'tcx>) {
+ if tcx.sess.opts.debugging_opts.instrument_coverage {
+ // If the InstrumentCoverage pass is called on promoted MIRs, skip them.
+ // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601
+ if src.promoted.is_none() {
+ debug!(
+ "instrumenting {:?}, span: {}",
+ src.def_id(),
+ tcx.sess.source_map().span_to_string(mir_body.span)
+ );
+ Instrumentor::new(tcx).inject_counters(mir_body);
+ }
+ }
+ }
+}
+
+impl<'tcx> Instrumentor<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>) -> Self {
+ Self { tcx, num_counters: 0 }
+ }
+
+ fn next_counter(&mut self) -> u32 {
+ let next = self.num_counters;
+ self.num_counters += 1;
+ next
+ }
+
+ fn inject_counters(&mut self, mir_body: &mut mir::Body<'tcx>) {
+ // FIXME(richkadel): As a first step, counters are only injected at the top of each
+ // function. The complete solution will inject counters at each conditional code branch.
+ let top_of_function = START_BLOCK;
+ let entire_function = mir_body.span;
+
+ self.inject_counter(mir_body, top_of_function, entire_function);
+ }
+
+ fn inject_counter(
+ &mut self,
+ mir_body: &mut mir::Body<'tcx>,
+ next_block: BasicBlock,
+ code_region: Span,
+ ) {
+ let injection_point = code_region.shrink_to_lo();
+
+ let count_code_region_fn = function_handle(
+ self.tcx,
+ self.tcx.require_lang_item(lang_items::CountCodeRegionFnLangItem, None),
+ injection_point,
+ );
+ let counter_index = Operand::const_from_scalar(
+ self.tcx,
+ self.tcx.types.u32,
+ Scalar::from_u32(self.next_counter()),
+ injection_point,
+ );
+
+ let mut patch = MirPatch::new(mir_body);
+
+ let temp = patch.new_temp(self.tcx.mk_unit(), code_region);
+ let new_block = patch.new_block(placeholder_block(code_region));
+ patch.patch_terminator(
+ new_block,
+ TerminatorKind::Call {
+ func: count_code_region_fn,
+ args: vec![counter_index],
+ // new_block will swapped with the next_block, after applying patch
+ destination: Some((Place::from(temp), new_block)),
+ cleanup: None,
+ from_hir_call: false,
+ fn_span: injection_point,
+ },
+ );
+
+ patch.add_statement(new_block.start_location(), StatementKind::StorageLive(temp));
+ patch.add_statement(next_block.start_location(), StatementKind::StorageDead(temp));
+
+ patch.apply(mir_body);
+
+ // To insert the `new_block` in front of the first block in the counted branch (the
+ // `next_block`), just swap the indexes, leaving the rest of the graph unchanged.
+ mir_body.basic_blocks_mut().swap(next_block, new_block);
+ }
+}
+
+fn function_handle<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: DefId, span: Span) -> Operand<'tcx> {
+ let ret_ty = tcx.fn_sig(fn_def_id).output();
+ let ret_ty = ret_ty.no_bound_vars().unwrap();
+ let substs = tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(ret_ty)));
+ Operand::function_handle(tcx, fn_def_id, substs, span)
+}
+
+fn placeholder_block(span: Span) -> BasicBlockData<'tcx> {
+ BasicBlockData {
+ statements: vec![],
+ terminator: Some(Terminator {
+ source_info: SourceInfo::outermost(span),
+ // this gets overwritten by the counter Call
+ kind: TerminatorKind::Unreachable,
+ }),
+ is_cleanup: false,
+ }
+}
+
+fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> u64 {
+ let hir_node = tcx.hir().get_if_local(def_id).expect("DefId is local");
+ let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body");
+ let hir_body = tcx.hir().body(fn_body_id);
+ let mut hcx = tcx.create_no_span_stable_hashing_context();
+ hash(&mut hcx, &hir_body.value).to_smaller_hash()
+}
+
+fn hash(
+ hcx: &mut StableHashingContext<'tcx>,
+ node: &impl HashStable<StableHashingContext<'tcx>>,
+) -> Fingerprint {
+ let mut stable_hasher = StableHasher::new();
+ node.hash_stable(hcx, &mut stable_hasher);
+ stable_hasher.finish()
+}
pub mod generator;
pub mod inline;
pub mod instcombine;
+pub mod instrument_coverage;
pub mod no_landing_pads;
pub mod nrvo;
pub mod promote_consts;
promoted_mir,
..*providers
};
+ instrument_coverage::provide(providers);
}
fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// What we need to run borrowck etc.
&promote_pass,
&simplify::SimplifyCfg::new("qualify-consts"),
+ // If the `instrument-coverage` option is enabled, analyze the CFG, identify each
+ // conditional branch, construct a coverage map to be passed to LLVM, and inject counters
+ // where needed.
+ &instrument_coverage::InstrumentCoverage,
]],
);
self.tcx
}
- fn visit_terminator_kind(&mut self, kind: &mut TerminatorKind<'tcx>, location: Location) {
- if let Some(unwind) = kind.unwind_mut() {
+ fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
+ if let Some(unwind) = terminator.kind.unwind_mut() {
unwind.take();
}
- self.super_terminator_kind(kind, location);
+ self.super_terminator(terminator, location);
}
}
ccx: &'a ConstCx<'a, 'tcx>,
temps: IndexVec<Local, TempState>,
candidates: Vec<Candidate>,
- span: Span,
}
impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
}
}
- fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Location) {
- self.super_terminator_kind(kind, location);
+ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+ self.super_terminator(terminator, location);
- match *kind {
+ match terminator.kind {
TerminatorKind::Call { ref func, .. } => {
if let ty::FnDef(def_id, _) = func.ty(self.ccx.body, self.ccx.tcx).kind {
let fn_sig = self.ccx.tcx.fn_sig(def_id);
_ => {}
}
}
-
- fn visit_source_info(&mut self, source_info: &SourceInfo) {
- self.span = source_info.span;
- }
}
pub fn collect_temps_and_candidates(
let mut collector = Collector {
temps: IndexVec::from_elem(TempState::Undefined, &ccx.body.local_decls),
candidates: vec![],
- span: ccx.body.span,
ccx,
};
for (bb, data) in rpo {
Place::ty_from(place.local, proj_base, self.body, self.tcx)
.projection_ty(self.tcx, elem)
.ty;
- if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) {
+ if ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) {
has_mut_interior = false;
break;
}
let ty = Place::ty_from(place.local, proj_base, self.body, self.tcx)
.projection_ty(self.tcx, elem)
.ty;
- if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) {
+ if ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) {
has_mut_interior = false;
break;
}
0,
vec![],
body.span,
- vec![],
body.generator_kind,
);
promoted.ignore_interior_mut_in_const_validation = true;
_ => true,
});
let terminator = block.terminator_mut();
- if let TerminatorKind::Drop { location: place, target, .. } = &terminator.kind {
+ if let TerminatorKind::Drop { place, target, .. } = &terminator.kind {
if let Some(index) = place.as_local() {
if promoted(index) {
terminator.kind = TerminatorKind::Goto { target: *target };
check_rvalue(tcx, body, def_id, rval, span)
}
- StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _)
- if !feature_allowed(tcx, def_id, sym::const_if_match) =>
- {
- Err((span, "loops and conditional expressions are not stable in const fn".into()))
- }
-
StatementKind::FakeRead(_, place) => check_place(tcx, **place, span, def_id, body),
// just an assignment
| TerminatorKind::Resume
| TerminatorKind::Unreachable => Ok(()),
- TerminatorKind::Drop { location, .. } => check_place(tcx, *location, span, def_id, body),
- TerminatorKind::DropAndReplace { location, value, .. } => {
- check_place(tcx, *location, span, def_id, body)?;
+ TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, def_id, body),
+ TerminatorKind::DropAndReplace { place, value, .. } => {
+ check_place(tcx, *place, span, def_id, body)?;
check_operand(tcx, value, span, def_id, body)
}
- TerminatorKind::SwitchInt { .. } if !feature_allowed(tcx, def_id, sym::const_if_match) => {
- Err((span, "loops and conditional expressions are not stable in const fn".into()))
- }
-
TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => {
check_operand(tcx, discr, span, def_id, body)
}
BasicBlock, Body, Location, Operand, Rvalue, Statement, StatementKind, Terminator,
TerminatorKind,
},
- ty::{self, ParamEnv, TyCtxt},
+ ty::{
+ self,
+ relate::{Relate, RelateResult, TypeRelation},
+ ParamEnv, Ty, TyCtxt,
+ },
};
-use rustc_span::def_id::DefId;
#[derive(Copy, Clone, Debug)]
enum EdgeKind {
impl<'tcx> MirPass<'tcx> for Validator {
fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
- let def_id = source.def_id();
- let param_env = tcx.param_env(def_id);
- TypeChecker { when: &self.when, def_id, body, tcx, param_env }.visit_body(body);
+ let param_env = tcx.param_env(source.def_id());
+ TypeChecker { when: &self.when, source, body, tcx, param_env }.visit_body(body);
}
}
+/// Returns whether the two types are equal up to lifetimes.
+/// All lifetimes, including higher-ranked ones, get ignored for this comparison.
+/// (This is unlike the `erasing_regions` methods, which keep higher-ranked lifetimes for soundness reasons.)
+///
+/// The point of this function is to approximate "equal up to subtyping". However,
+/// the approximation is incorrect as variance is ignored.
+pub fn equal_up_to_regions(
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ src: Ty<'tcx>,
+ dest: Ty<'tcx>,
+) -> bool {
+ // Fast path.
+ if src == dest {
+ return true;
+ }
+
+ struct LifetimeIgnoreRelation<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ }
+
+ impl TypeRelation<'tcx> for LifetimeIgnoreRelation<'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ self.param_env
+ }
+
+ fn tag(&self) -> &'static str {
+ "librustc_mir::transform::validate"
+ }
+
+ fn a_is_expected(&self) -> bool {
+ true
+ }
+
+ fn relate_with_variance<T: Relate<'tcx>>(
+ &mut self,
+ _: ty::Variance,
+ a: &T,
+ b: &T,
+ ) -> RelateResult<'tcx, T> {
+ // Ignore variance, require types to be exactly the same.
+ self.relate(a, b)
+ }
+
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ if a == b {
+ // Short-circuit.
+ return Ok(a);
+ }
+ ty::relate::super_relate_tys(self, a, b)
+ }
+
+ fn regions(
+ &mut self,
+ a: ty::Region<'tcx>,
+ _b: ty::Region<'tcx>,
+ ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+ // Ignore regions.
+ Ok(a)
+ }
+
+ fn consts(
+ &mut self,
+ a: &'tcx ty::Const<'tcx>,
+ b: &'tcx ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+ ty::relate::super_relate_consts(self, a, b)
+ }
+
+ fn binders<T>(
+ &mut self,
+ a: &ty::Binder<T>,
+ b: &ty::Binder<T>,
+ ) -> RelateResult<'tcx, ty::Binder<T>>
+ where
+ T: Relate<'tcx>,
+ {
+ self.relate(a.skip_binder(), b.skip_binder())?;
+ Ok(a.clone())
+ }
+ }
+
+ // Instantiate and run relation.
+ let mut relator: LifetimeIgnoreRelation<'tcx> = LifetimeIgnoreRelation { tcx: tcx, param_env };
+ relator.relate(&src, &dest).is_ok()
+}
+
struct TypeChecker<'a, 'tcx> {
when: &'a str,
- def_id: DefId,
+ source: MirSource<'tcx>,
body: &'a Body<'tcx>,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
span,
&format!(
"broken MIR in {:?} ({}) at {:?}:\n{}",
- self.def_id,
+ self.source.instance,
self.when,
location,
msg.as_ref()
self.fail(location, format!("encountered jump to invalid basic block {:?}", bb))
}
}
+
+ /// Check if src can be assigned into dest.
+ /// This is not precise, it will accept some incorrect assignments.
+ fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
+ // Fast path before we normalize.
+ if src == dest {
+ // Equal types, all is good.
+ return true;
+ }
+ // Normalize projections and things like that.
+ // FIXME: We need to reveal_all, as some optimizations change types in ways
+ // that require unfolding opaque types.
+ let param_env = self.param_env.with_reveal_all();
+ let src = self.tcx.normalize_erasing_regions(param_env, src);
+ let dest = self.tcx.normalize_erasing_regions(param_env, dest);
+
+ // Type-changing assignments can happen when subtyping is used. While
+ // all normal lifetimes are erased, higher-ranked types with their
+ // late-bound lifetimes are still around and can lead to type
+ // differences. So we compare ignoring lifetimes.
+ equal_up_to_regions(self.tcx, param_env, src, dest)
+ }
}
impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
let ty = place.ty(&self.body.local_decls, self.tcx).ty;
let span = self.body.source_info(location).span;
- if !ty.is_copy_modulo_regions(self.tcx, self.param_env, span) {
+ if !ty.is_copy_modulo_regions(self.tcx.at(span), self.param_env) {
self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty));
}
}
}
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
- // The sides of an assignment must not alias. Currently this just checks whether the places
- // are identical.
- if let StatementKind::Assign(box (dest, rvalue)) = &statement.kind {
- match rvalue {
- Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => {
- if dest == src {
- self.fail(
- location,
- "encountered `Assign` statement with overlapping memory",
- );
+ match &statement.kind {
+ StatementKind::Assign(box (dest, rvalue)) => {
+ // LHS and RHS of the assignment must have the same type.
+ let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty;
+ let right_ty = rvalue.ty(&self.body.local_decls, self.tcx);
+ if !self.mir_assign_valid_types(right_ty, left_ty) {
+ self.fail(
+ location,
+ format!(
+ "encountered `Assign` statement with incompatible types:\n\
+ left-hand side has type: {}\n\
+ right-hand side has type: {}",
+ left_ty, right_ty,
+ ),
+ );
+ }
+ // The sides of an assignment must not alias. Currently this just checks whether the places
+ // are identical.
+ match rvalue {
+ Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => {
+ if dest == src {
+ self.fail(
+ location,
+ "encountered `Assign` statement with overlapping memory",
+ );
+ }
}
+ _ => {}
}
- _ => {}
}
+ _ => {}
}
}
TerminatorKind::Goto { target } => {
self.check_edge(location, *target, EdgeKind::Normal);
}
- TerminatorKind::SwitchInt { targets, values, .. } => {
+ TerminatorKind::SwitchInt { targets, values, switch_ty, discr } => {
+ let ty = discr.ty(&self.body.local_decls, self.tcx);
+ if ty != *switch_ty {
+ self.fail(
+ location,
+ format!(
+ "encountered `SwitchInt` terminator with type mismatch: {:?} != {:?}",
+ ty, switch_ty,
+ ),
+ );
+ }
if targets.len() != values.len() + 1 {
self.fail(
location,
self.elaborator.patch().patch_terminator(
bb,
TerminatorKind::Drop {
- location: self.place,
+ place: self.place,
target: self.succ,
unwind: self.unwind.into_option(),
},
self.elaborator.patch().patch_terminator(
drop_block,
TerminatorKind::Drop {
- location: tcx.mk_place_deref(ptr),
+ place: tcx.mk_place_deref(ptr),
target: loop_block,
unwind: unwind.into_option(),
},
fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
let block =
- TerminatorKind::Drop { location: self.place, target, unwind: unwind.into_option() };
+ TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_option() };
self.new_block(unwind, block)
}
}
writeln!(file, " {} {}", disambiguator, pass_name)?;
if let Some(ref layout) = body.generator_layout {
- writeln!(file, "// generator_layout = {:?}", layout)?;
+ writeln!(file, "/* generator_layout = {:#?} */", layout)?;
}
writeln!(file)?;
extra_data(PassWhere::BeforeCFG, &mut file)?;
if !ty.is_sized(tcx.at(span), param_env) {
// !sized means !copy, so this is an unsized move
- assert!(!ty.is_copy_modulo_regions(tcx, param_env, span));
+ assert!(!ty.is_copy_modulo_regions(tcx.at(span), param_env));
// As described above, detect the case where we are passing a value of unsized
// type, and that value is coming from the deref of a box.
block,
Operand::Move(is_min),
false,
- AssertKind::OverflowNeg,
+ AssertKind::OverflowNeg(arg.to_copy()),
expr_span,
);
}
block,
source_info,
result_value,
- Rvalue::CheckedBinaryOp(op, lhs, rhs),
+ Rvalue::CheckedBinaryOp(op, lhs.to_copy(), rhs.to_copy()),
);
let val_fld = Field::new(0);
let of_fld = Field::new(1);
let val = tcx.mk_place_field(result_value, val_fld, ty);
let of = tcx.mk_place_field(result_value, of_fld, bool_ty);
- let err = AssertKind::Overflow(op);
+ let err = AssertKind::Overflow(op, lhs, rhs);
block = self.assert(block, Operand::Move(of), false, err, span);
// and 2. there are two possible failure cases, divide-by-zero and overflow.
let zero_err = if op == BinOp::Div {
- AssertKind::DivisionByZero
+ AssertKind::DivisionByZero(lhs.to_copy())
} else {
- AssertKind::RemainderByZero
+ AssertKind::RemainderByZero(lhs.to_copy())
};
- let overflow_err = AssertKind::Overflow(op);
+ let overflow_err = AssertKind::Overflow(op, lhs.to_copy(), rhs.to_copy());
// Check for / 0
let is_zero = self.temp(bool_ty, span);
let tcx = hir.tcx();
let owner_id = tcx.hir().body_owner(body_id);
let span = tcx.hir().span(owner_id);
- let ty = tcx.types.err;
+ let ty = tcx.ty_error();
let num_params = match hir.body_owner_kind {
hir::BodyOwnerKind::Fn => tcx.hir().fn_decl_by_hir_id(owner_id).unwrap().inputs.len(),
hir::BodyOwnerKind::Closure => {
self.arg_count,
self.var_debug_info,
self.fn_span,
- self.hir.control_flow_destroyed(),
self.generator_kind,
)
}
self.local_decls[local].mutability = mutability;
self.local_decls[local].source_info.scope = self.source_scope;
self.local_decls[local].local_info = if let Some(kind) = self_binding {
- Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind))))
+ Some(box LocalInfo::User(ClearCrossCrate::Set(
+ BindingForm::ImplicitSelf(*kind),
+ )))
} else {
let binding_mode = ty::BindingMode::BindByValue(mutability);
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
&mut self,
block: BasicBlock,
span: Span,
- location: Place<'tcx>,
+ place: Place<'tcx>,
value: Operand<'tcx>,
) -> BlockAnd<()> {
let source_info = self.source_info(span);
block,
source_info,
TerminatorKind::DropAndReplace {
- location,
+ place,
value,
target: next_target,
unwind: Some(diverge_target),
block,
source_info,
TerminatorKind::Drop {
- location: local.into(),
+ place: local.into(),
target: next,
unwind: Some(unwind_to),
},
block,
source_info(drop_data.span),
TerminatorKind::Drop {
- location: drop_data.local.into(),
+ place: drop_data.local.into(),
target,
unwind: None,
},
} else {
// FIXME overflow
match (op.node, cx.constness) {
- // Destroy control flow if `#![feature(const_if_match)]` is not enabled.
- (hir::BinOpKind::And, hir::Constness::Const)
- if !cx.tcx.features().const_if_match =>
- {
- cx.control_flow_destroyed.push((op.span, "`&&` operator".into()));
- ExprKind::Binary { op: BinOp::BitAnd, lhs: lhs.to_ref(), rhs: rhs.to_ref() }
- }
- (hir::BinOpKind::Or, hir::Constness::Const)
- if !cx.tcx.features().const_if_match =>
- {
- cx.control_flow_destroyed.push((op.span, "`||` operator".into()));
- ExprKind::Binary { op: BinOp::BitOr, lhs: lhs.to_ref(), rhs: rhs.to_ref() }
- }
-
(hir::BinOpKind::And, _) => ExprKind::LogicalOp {
op: LogicalOp::And,
lhs: lhs.to_ref(),
);
// Not a real fn, but we're not reaching codegen anyways...
- ty = cx.tcx.types.err;
+ ty = cx.tcx.ty_error();
InlineAsmOperand::SymFn {
expr: Expr {
ty,
/// Whether this constant/function needs overflow checks.
check_overflow: bool,
-
- /// See field with the same name on `mir::Body`.
- control_flow_destroyed: Vec<(Span, String)>,
}
impl<'a, 'tcx> Cx<'a, 'tcx> {
body_owner: src_def_id.to_def_id(),
body_owner_kind,
check_overflow,
- control_flow_destroyed: Vec::new(),
}
}
-
- crate fn control_flow_destroyed(self) -> Vec<(Span, String)> {
- self.control_flow_destroyed
- }
}
impl<'a, 'tcx> Cx<'a, 'tcx> {
assert!(!adt.is_enum());
VariantIdx::new(0)
}
- ConstantValue(c) => cx.tcx.destructure_const(cx.param_env.and(c)).variant,
+ ConstantValue(c) => cx
+ .tcx
+ .destructure_const(cx.param_env.and(c))
+ .variant
+ .expect("destructed const of adt without variant id"),
_ => bug!("bad constructor {:?} for adt {:?}", self, adt),
}
}
/// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`.
fn is_binding_by_move(cx: &MatchVisitor<'_, '_>, hir_id: HirId, span: Span) -> bool {
- !cx.tables.node_type(hir_id).is_copy_modulo_regions(cx.tcx, cx.param_env, span)
+ !cx.tables.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env)
}
/// Check the legality of legality of by-move bindings.
cv.ty, structural
);
+ // This can occur because const qualification treats all associated constants as
+ // opaque, whereas `search_for_structural_match_violation` tries to monomorphize them
+ // before it runs.
+ //
+ // FIXME(#73448): Find a way to bring const qualification into parity with
+ // `search_for_structural_match_violation`.
if structural.is_none() && mir_structural_match_violation {
- bug!("MIR const-checker found novel structural match violation");
+ warn!("MIR const-checker found novel structural match violation. See #73448.");
+ return inlined_const_as_pat;
}
if let Some(non_sm_ty) = structural {
PatKind::Variant {
adt_def,
substs,
- variant_index: destructured.variant,
+ variant_index: destructured
+ .variant
+ .expect("destructed const of adt without variant id"),
subpatterns: field_pats(destructured.fields),
}
}
fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
let mut ty = self.tables.node_type(pat.hir_id);
- if let ty::Error = ty.kind {
+ if let ty::Error(_) = ty.kind {
// Avoid ICEs (e.g., #50577 and #50585).
return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) };
}
if adt_def.is_enum() {
let substs = match ty.kind {
ty::Adt(_, substs) | ty::FnDef(_, substs) => substs,
- ty::Error => {
+ ty::Error(_) => {
// Avoid ICE (#50585)
return PatKind::Wild;
}
let b_bits = b.try_eval_bits(tcx, param_env, ty);
if let (Some(a), Some(b)) = (a_bits, b_bits) {
- use ::rustc_apfloat::Float;
+ use rustc_apfloat::Float;
return match ty.kind {
ty::Float(ast::FloatTy::F32) => {
let l = ::rustc_apfloat::ieee::Single::from_bits(a);
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(crate_visibility_modifier)]
}
rustc_lexer::LiteralKind::Byte { terminated } => {
if !terminated {
- self.fatal_span_(start + BytePos(1), suffix_start, "unterminated byte constant")
- .raise()
+ self.sess
+ .span_diagnostic
+ .struct_span_fatal_with_code(
+ self.mk_sp(start + BytePos(1), suffix_start),
+ "unterminated byte constant",
+ error_code!(E0763),
+ )
+ .emit();
+ FatalError.raise();
}
(token::Byte, Mode::Byte, 2, 1) // b' '
}
rustc_lexer::LiteralKind::Str { terminated } => {
if !terminated {
- self.fatal_span_(start, suffix_start, "unterminated double quote string")
- .raise()
+ self.sess
+ .span_diagnostic
+ .struct_span_fatal_with_code(
+ self.mk_sp(start, suffix_start),
+ "unterminated double quote string",
+ error_code!(E0765),
+ )
+ .emit();
+ FatalError.raise();
}
(token::Str, Mode::Str, 1, 1) // " "
}
rustc_lexer::LiteralKind::ByteStr { terminated } => {
if !terminated {
- self.fatal_span_(
- start + BytePos(1),
- suffix_start,
- "unterminated double quote byte string",
- )
- .raise()
+ self.sess
+ .span_diagnostic
+ .struct_span_fatal_with_code(
+ self.mk_sp(start + BytePos(1), suffix_start),
+ "unterminated double quote byte string",
+ error_code!(E0766),
+ )
+ .emit();
+ FatalError.raise();
}
(token::ByteStr, Mode::ByteStr, 2, 1) // b" "
}
/// The delimiters or `=` are still put into the resulting token stream.
pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> {
let item = match self.token.kind {
- token::Interpolated(ref nt) => match **nt {
+ token::Interpolated(ref nt, _) => match **nt {
Nonterminal::NtMeta(ref item) => Some(item.clone().into_inner()),
_ => None,
},
/// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
let nt_meta = match self.token.kind {
- token::Interpolated(ref nt) => match **nt {
+ token::Interpolated(ref nt, _) => match **nt {
token::NtMeta(ref e) => Some(e.clone()),
_ => None,
},
self.bump();
let sp = self.prev_token.span;
self.struct_span_err(sp, &msg)
- .span_suggestion(sp, "change this to `;`", ";".to_string(), appl)
+ .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl)
.emit();
return Ok(());
} else if self.look_ahead(0, |t| {
/// `token::Interpolated` tokens.
macro_rules! maybe_whole_expr {
($p:expr) => {
- if let token::Interpolated(nt) = &$p.token.kind {
+ if let token::Interpolated(nt, _) = &$p.token.kind {
match &**nt {
token::NtExpr(e) | token::NtLiteral(e) => {
let e = e.clone();
}
fn parse_const_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, GenericParam> {
- let lo = self.token.span;
+ let const_span = self.token.span;
self.expect_keyword(kw::Const)?;
let ident = self.parse_ident()?;
self.expect(&token::Colon)?;
let ty = self.parse_ty()?;
- self.sess.gated_spans.gate(sym::const_generics, lo.to(self.prev_token.span));
+ self.sess.gated_spans.gate(sym::const_generics, const_span.to(self.prev_token.span));
Ok(GenericParam {
ident,
id: ast::DUMMY_NODE_ID,
attrs: preceding_attrs.into(),
bounds: Vec::new(),
- kind: GenericParamKind::Const { ty },
+ kind: GenericParamKind::Const { ty, kw_span: const_span },
is_placeholder: false,
})
}
fn is_named_param(&self) -> bool {
let offset = match self.token.kind {
- token::Interpolated(ref nt) => match **nt {
+ token::Interpolated(ref nt, _) => match **nt {
token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
_ => 0,
},
#[macro_export]
macro_rules! maybe_whole {
($p:expr, $constructor:ident, |$x:ident| $e:expr) => {
- if let token::Interpolated(nt) = &$p.token.kind {
+ if let token::Interpolated(nt, _) = &$p.token.kind {
if let token::$constructor(x) = &**nt {
let $x = x.clone();
$p.bump();
macro_rules! maybe_recover_from_interpolated_ty_qpath {
($self: expr, $allow_qpath_recovery: expr) => {
if $allow_qpath_recovery && $self.look_ahead(1, |t| t == &token::ModSep) {
- if let token::Interpolated(nt) = &$self.token.kind {
+ if let token::Interpolated(nt, _) = &$self.token.kind {
if let token::NtTy(ty) = &**nt {
let ty = ty.clone();
$self.bump();
if self.eat(&token::Eq) {
let eq_span = self.prev_token.span;
let mut is_interpolated_expr = false;
- if let token::Interpolated(nt) = &self.token.kind {
+ if let token::Interpolated(nt, _) = &self.token.kind {
if let token::NtExpr(..) = **nt {
is_interpolated_expr = true;
}
/// This restriction shouldn't be an issue in practice,
/// since this function is used to record the tokens for
/// a parsed AST item, which always has matching delimiters.
- fn collect_tokens<R>(
+ pub fn collect_tokens<R>(
&mut self,
f: impl FnOnce(&mut Self) -> PResult<'a, R>,
) -> PResult<'a, (R, TokenStream)> {
self.recover_additional_muts();
// Make sure we don't allow e.g. `let mut $p;` where `$p:pat`.
- if let token::Interpolated(ref nt) = self.token.kind {
+ if let token::Interpolated(ref nt, _) = self.token.kind {
if let token::NtPat(_) = **nt {
self.expected_ident_found().emit();
}
}
/// Parses the RHS of a local variable declaration (e.g., '= 14;').
- fn parse_initializer(&mut self, skip_eq: bool) -> PResult<'a, Option<P<Expr>>> {
- if self.eat(&token::Eq) || skip_eq { Ok(Some(self.parse_expr()?)) } else { Ok(None) }
+ fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option<P<Expr>>> {
+ let eq_consumed = match self.token.kind {
+ token::BinOpEq(..) => {
+ // Recover `let x <op>= 1` as `let x = 1`
+ self.struct_span_err(
+ self.token.span,
+ "can't reassign to an uninitialized variable",
+ )
+ .span_suggestion_short(
+ self.token.span,
+ "initialize the variable",
+ "=".to_string(),
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ self.bump();
+ true
+ }
+ _ => self.eat(&token::Eq),
+ };
+
+ Ok(if eq_consumed || eq_optional { Some(self.parse_expr()?) } else { None })
}
/// Parses a block. No inner attributes are allowed.
/// Error messages accumulated during parsing
pub errors: Vec<ParseError>,
/// Current position of implicit positional argument pointer
- curarg: usize,
+ pub curarg: usize,
/// `Some(raw count)` when the string is "raw", used to position spans correctly
style: Option<usize>,
/// Start and end byte offset of every successfully parsed argument
_ => Some(String(self.string(pos))),
}
} else {
- if self.is_literal && self.cur_line_start != self.input.len() {
+ if self.is_literal {
let start = self.to_span_index(self.cur_line_start);
let end = self.to_span_index(self.input.len());
- self.line_spans.push(start.to(end));
- self.cur_line_start = self.input.len();
+ let span = start.to(end);
+ if self.line_spans.last() != Some(&span) {
+ self.line_spans.push(span);
+ }
}
None
}
use rustc_ast::attr;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{self, HirId, Item, ItemKind, TraitItem};
use rustc_hir::{MethodKind, Target};
use rustc_span::symbol::sym;
use rustc_span::Span;
-fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
+pub(crate) fn target_from_impl_item<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_item: &hir::ImplItem<'_>,
+) -> Target {
match impl_item.kind {
hir::ImplItemKind::Const(..) => Target::AssocConst,
hir::ImplItemKind::Fn(..) => {
}
}
-fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir()
.visit_item_likes_in_module(module_def_id, &mut CheckAttrVisitor { tcx }.as_deep_visitor());
}
//! errors. We still look for those primitives in the MIR const-checker to ensure nothing slips
//! through, but errors for structured control flow in a `const` should be emitted here.
+use rustc_attr as attr;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::query::Providers;
enum NonConstExpr {
Loop(hir::LoopSource),
Match(hir::MatchSource),
- OrPattern,
}
impl NonConstExpr {
match self {
Self::Loop(src) => format!("`{}`", src.name()),
Self::Match(src) => format!("`{}`", src.name()),
- Self::OrPattern => "or-pattern".to_string(),
}
}
use hir::MatchSource::*;
let gates: &[_] = match self {
- Self::Match(Normal)
- | Self::Match(IfDesugar { .. })
- | Self::Match(IfLetDesugar { .. })
- | Self::OrPattern => &[sym::const_if_match],
-
- Self::Loop(Loop) => &[sym::const_loop],
-
- Self::Loop(While)
- | Self::Loop(WhileLet)
- | Self::Match(WhileDesugar | WhileLetDesugar) => {
- &[sym::const_loop, sym::const_if_match]
+ // A `for` loop's desugaring contains a call to `IntoIterator::into_iter`,
+ // so they are not yet allowed.
+ // Likewise, `?` desugars to a call to `Try::into_result`.
+ Self::Loop(ForLoop) | Self::Match(ForLoopDesugar | TryDesugar | AwaitDesugar) => {
+ return None;
}
- // A `for` loop's desugaring contains a call to `IntoIterator::into_iter`,
- // so they are not yet allowed with `#![feature(const_loop)]`.
- _ => return None,
+ // All other expressions are allowed.
+ Self::Loop(Loop | While | WhileLet)
+ | Self::Match(
+ WhileDesugar | WhileLetDesugar | Normal | IfDesugar { .. } | IfLetDesugar { .. },
+ ) => &[],
};
Some(gates)
}
}
-fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
let mut vis = CheckConstVisitor::new(tcx);
tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
}
struct CheckConstVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
const_kind: Option<hir::ConstContext>,
+ def_id: Option<LocalDefId>,
}
impl<'tcx> CheckConstVisitor<'tcx> {
fn new(tcx: TyCtxt<'tcx>) -> Self {
- CheckConstVisitor { tcx, const_kind: None }
+ CheckConstVisitor { tcx, const_kind: None, def_id: None }
}
/// Emits an error when an unsupported expression is found in a const context.
fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
- let features = self.tcx.features();
+ let Self { tcx, def_id, const_kind } = *self;
+
+ let features = tcx.features();
let required_gates = expr.required_feature_gates();
+
+ let is_feature_allowed = |feature_gate| {
+ // All features require that the corresponding gate be enabled,
+ // even if the function has `#[allow_internal_unstable(the_gate)]`.
+ if !tcx.features().enabled(feature_gate) {
+ return false;
+ }
+
+ // If `def_id` is `None`, we don't need to consider stability attributes.
+ let def_id = match def_id {
+ Some(x) => x.to_def_id(),
+ None => return true,
+ };
+
+ // If this crate is not using stability attributes, or this function is not claiming to be a
+ // stable `const fn`, that is all that is required.
+ if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
+ return true;
+ }
+
+ // However, we cannot allow stable `const fn`s to use unstable features without an explicit
+ // opt-in via `allow_internal_unstable`.
+ attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic())
+ .map_or(false, |mut features| features.any(|name| name == feature_gate))
+ };
+
match required_gates {
// Don't emit an error if the user has enabled the requisite feature gates.
- Some(gates) if gates.iter().all(|&g| features.enabled(g)) => return,
+ Some(gates) if gates.iter().copied().all(is_feature_allowed) => return,
// `-Zunleash-the-miri-inside-of-you` only works for expressions that don't have a
// corresponding feature gate. This encourages nightly users to use feature gates when
// possible.
- None if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you => {
- self.tcx.sess.span_warn(span, "skipping const checks");
+ None if tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you => {
+ tcx.sess.span_warn(span, "skipping const checks");
return;
}
_ => {}
}
- let const_kind = self
- .const_kind
- .expect("`const_check_violated` may only be called inside a const context");
+ let const_kind =
+ const_kind.expect("`const_check_violated` may only be called inside a const context");
let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());
required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
match missing_gates.as_slice() {
- &[] => struct_span_err!(self.tcx.sess, span, E0744, "{}", msg).emit(),
-
- // If the user enabled `#![feature(const_loop)]` but not `#![feature(const_if_match)]`,
- // explain why their `while` loop is being rejected.
- &[gate @ sym::const_if_match] if required_gates.contains(&sym::const_loop) => {
- feature_err(&self.tcx.sess.parse_sess, gate, span, &msg)
- .note(
- "`#![feature(const_loop)]` alone is not sufficient, \
- since this loop expression contains an implicit conditional",
- )
- .emit();
- }
+ &[] => struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(),
&[missing_primary, ref missing_secondary @ ..] => {
- let mut err = feature_err(&self.tcx.sess.parse_sess, missing_primary, span, &msg);
+ let mut err = feature_err(&tcx.sess.parse_sess, missing_primary, span, &msg);
// If multiple feature gates would be required to enable this expression, include
// them as help messages. Don't emit a separate error for each missing feature gate.
}
/// Saves the parent `const_kind` before calling `f` and restores it afterwards.
- fn recurse_into(&mut self, kind: Option<hir::ConstContext>, f: impl FnOnce(&mut Self)) {
+ fn recurse_into(
+ &mut self,
+ kind: Option<hir::ConstContext>,
+ def_id: Option<LocalDefId>,
+ f: impl FnOnce(&mut Self),
+ ) {
+ let parent_def_id = self.def_id;
let parent_kind = self.const_kind;
+ self.def_id = def_id;
self.const_kind = kind;
f(self);
+ self.def_id = parent_def_id;
self.const_kind = parent_kind;
}
}
fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
let kind = Some(hir::ConstContext::Const);
- self.recurse_into(kind, |this| intravisit::walk_anon_const(this, anon));
+ self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
}
fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
let owner = self.tcx.hir().body_owner_def_id(body.id());
let kind = self.tcx.hir().body_const_context(owner);
- self.recurse_into(kind, |this| intravisit::walk_body(this, body));
- }
-
- fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
- if self.const_kind.is_some() {
- if let hir::PatKind::Or { .. } = p.kind {
- self.const_check_violated(NonConstExpr::OrPattern, p.span);
- }
- }
- intravisit::walk_pat(self, p)
+ self.recurse_into(kind, Some(owner), |this| intravisit::walk_body(this, body));
}
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
par_iter(&hir_map.krate().modules).for_each(|(module_id, _)| {
let local_def_id = hir_map.local_def_id(*module_id);
hir_map.visit_item_likes_in_module(
- local_def_id.to_def_id(),
+ local_def_id,
&mut OuterVisitor { hir_map, errors: &errors },
);
});
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_index::vec::Idx;
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
use rustc_target::asm::{InlineAsmRegOrRegClass, InlineAsmType};
use rustc_target::spec::abi::Abi::RustIntrinsic;
-fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx }.as_deep_visitor());
}
_ => unreachable!(),
};
let asm_ty = match ty.kind {
- ty::Never | ty::Error => return None,
+ ty::Never | ty::Error(_) => return None,
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8),
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16),
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32),
let fields = &adt.non_enum_variant().fields;
let elem_ty = fields[0].ty(self.tcx, substs);
match elem_ty.kind {
- ty::Never | ty::Error => return None,
+ ty::Never | ty::Error(_) => return None,
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => {
Some(InlineAsmType::VecI8(fields.len() as u64))
}
// Check that the type implements Copy. The only case where this can
// possibly fail is for SIMD types which don't #[derive(Copy)].
- if !ty.is_copy_modulo_regions(self.tcx, self.param_env, DUMMY_SP) {
+ if !ty.is_copy_modulo_regions(self.tcx.at(DUMMY_SP), self.param_env) {
let msg = "arguments for inline assembly must be copyable";
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
err.note(&format!("`{}` does not implement the Copy trait", ty));
//! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
//! * Functions called by the compiler itself.
+use crate::check_attr::target_from_impl_item;
use crate::weak_lang_items;
use rustc_middle::middle::cstore::ExternCrate;
use rustc_middle::ty::TyCtxt;
+use rustc_ast::ast::Attribute;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::lang_items::{extract, ITEM_REFS};
-use rustc_hir::{LangItem, LanguageItems, Target};
+use rustc_hir::{HirId, LangItem, LanguageItems, Target};
use rustc_middle::ty::query::Providers;
impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
- if let Some((value, span)) = extract(&item.attrs) {
- let actual_target = Target::from_item(item);
+ self.check_for_lang(Target::from_item(item), item.hir_id, item.attrs)
+ }
+
+ fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
+ self.check_for_lang(
+ Target::from_trait_item(trait_item),
+ trait_item.hir_id,
+ trait_item.attrs,
+ )
+ }
+
+ fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
+ self.check_for_lang(
+ target_from_impl_item(self.tcx, impl_item),
+ impl_item.hir_id,
+ impl_item.attrs,
+ )
+ }
+}
+
+impl LanguageItemCollector<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
+ LanguageItemCollector { tcx, items: LanguageItems::new() }
+ }
+
+ fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId, attrs: &[Attribute]) {
+ if let Some((value, span)) = extract(&attrs) {
match ITEM_REFS.get(&*value.as_str()).cloned() {
// Known lang item with attribute on correct target.
Some((item_index, expected_target)) if actual_target == expected_target => {
- let def_id = self.tcx.hir().local_def_id(item.hir_id);
+ let def_id = self.tcx.hir().local_def_id(hir_id);
self.collect_item(item_index, def_id.to_def_id());
}
// Known lang item with attribute on incorrect target.
}
}
- fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {
- // At present, lang items are always items, not trait items.
- }
-
- fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {
- // At present, lang items are always items, not impl items.
- }
-}
-
-impl LanguageItemCollector<'tcx> {
- fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
- LanguageItemCollector { tcx, items: LanguageItems::new() }
- }
-
fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
// Check for duplicates.
if let Some(original_def_id) = self.items.items[item_index] {
if original_def_id != item_def_id {
- let name = LangItem::from_u32(item_index as u32).unwrap().name();
+ let lang_item = LangItem::from_u32(item_index as u32).unwrap();
+ let name = lang_item.name();
let mut err = match self.tcx.hir().span_if_local(item_def_id) {
Some(span) => struct_span_err!(
self.tcx.sess,
// Matched.
self.items.items[item_index] = Some(item_def_id);
+ if let Some(group) = LangItem::from_u32(item_index as u32).unwrap().group() {
+ self.items.groups[group as usize].push(item_def_id);
+ }
}
}
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::*;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet, Node};
use rustc_middle::hir::map::Map;
}
}
-fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().visit_item_likes_in_module(
module_def_id,
&mut IrMaps::new(tcx, module_def_id).as_deep_visitor(),
struct IrMaps<'tcx> {
tcx: TyCtxt<'tcx>,
- body_owner: DefId,
+ body_owner: LocalDefId,
num_live_nodes: usize,
num_vars: usize,
live_node_map: HirIdMap<LiveNode>,
}
impl IrMaps<'tcx> {
- fn new(tcx: TyCtxt<'tcx>, body_owner: DefId) -> IrMaps<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>, body_owner: LocalDefId) -> IrMaps<'tcx> {
IrMaps {
tcx,
body_owner,
// swap in a new set of IR maps for this function body:
let def_id = ir.tcx.hir().local_def_id(id);
- let mut fn_maps = IrMaps::new(ir.tcx, def_id.to_def_id());
+ let mut fn_maps = IrMaps::new(ir.tcx, def_id);
// Don't run unused pass for #[derive()]
if let FnKind::Method(..) = fk {
}
ir.set_captures(expr.hir_id, call_caps);
let old_body_owner = ir.body_owner;
- ir.body_owner = closure_def_id.to_def_id();
+ ir.body_owner = closure_def_id;
intravisit::walk_expr(ir, expr);
ir.body_owner = old_body_owner;
}
for (&var_hir_id, upvar) in upvars.iter().rev() {
let upvar_id = ty::UpvarId {
var_path: ty::UpvarPath { hir_id: var_hir_id },
- closure_expr_id: self.ir.body_owner.expect_local(),
+ closure_expr_id: self.ir.body_owner,
};
match self.tables.upvar_capture(upvar_id) {
ty::UpvarCapture::ByRef(_) => {
let var = self.variable(var_hir_id, upvar.span);
let upvar_id = ty::UpvarId {
var_path: ty::UpvarPath { hir_id: var_hir_id },
- closure_expr_id: self.ir.body_owner.expect_local(),
+ closure_expr_id: self.ir.body_owner,
};
match self.tables.upvar_capture(upvar_id) {
ty::UpvarCapture::ByValue => {}
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{Destination, Movability, Node};
use rustc_middle::hir::map::Map;
cx: Context,
}
-fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().visit_item_likes_in_module(
module_def_id,
&mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal }.as_deep_visitor(),
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{Generics, HirId, Item, StructField, Variant};
use rustc_middle::hir::map::Map;
/// Cross-references the feature names of unstable APIs with enabled
/// features and possibly prints errors.
-fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx }.as_deep_visitor());
}
use rustc_hir as hir;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::lang_items;
+use rustc_hir::lang_items::ITEM_REFS;
use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
use rustc_middle::middle::lang_items::whitelisted;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::CrateType;
+use rustc_span::symbol::sym;
use rustc_span::symbol::Symbol;
use rustc_span::Span;
}
impl<'a, 'tcx> Context<'a, 'tcx> {
- fn register(&mut self, name: Symbol, span: Span) {
+ fn register(&mut self, name: Symbol, span: Span, hir_id: hir::HirId) {
if let Some(&item) = WEAK_ITEMS_REFS.get(&name) {
if self.items.require(item).is_err() {
self.items.missing.push(item);
}
+ } else if name == sym::count_code_region {
+ // `core::intrinsics::code_count_region()` is (currently) the only `extern` lang item
+ // that is never actually linked. It is not a `weak_lang_item` that can be registered
+ // when used, and should be registered here instead.
+ if let Some((item_index, _)) = ITEM_REFS.get(&*name.as_str()).cloned() {
+ if self.items.items[item_index].is_none() {
+ let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
+ self.items.items[item_index] = Some(item_def_id);
+ }
+ }
} else {
struct_span_err!(self.tcx.sess, span, E0264, "unknown external lang item: `{}`", name)
.emit();
fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) {
if let Some((lang_item, _)) = hir::lang_items::extract(&i.attrs) {
- self.register(lang_item, i.span);
+ self.register(lang_item, i.span, i.hir_id);
}
intravisit::walk_foreign_item(self, i)
}
| ty::Ref(..)
| ty::FnPtr(..)
| ty::Param(..)
- | ty::Error
+ | ty::Error(_)
| ty::GeneratorWitness(..) => {}
ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => {
bug!("unexpected type: {:?}", ty)
#![feature(bool_to_option)]
#![feature(const_fn)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_panic)]
#![feature(core_intrinsics)]
#![feature(hash_raw_entry)]
#![feature(min_specialization)]
#![feature(stmt_expr_attributes)]
-#![feature(vec_remove_item)]
#[macro_use]
extern crate log;
// Remove the queries in our cycle from the list of jobs to look at
for r in &stack {
- jobs.remove_item(&r.1);
+ if let Some(pos) = jobs.iter().position(|j| j == &r.1) {
+ jobs.remove(pos);
+ }
}
// Find the queries in the cycle which are
rustc_expand = { path = "../librustc_expand" }
rustc_feature = { path = "../librustc_feature" }
rustc_hir = { path = "../librustc_hir" }
+rustc_index = { path = "../librustc_index" }
rustc_metadata = { path = "../librustc_metadata" }
rustc_session = { path = "../librustc_session" }
rustc_span = { path = "../librustc_span" }
use rustc_ast::ast::{AssocItem, AssocItemKind, MetaItemKind, StmtKind};
use rustc_ast::token::{self, Token};
use rustc_ast::visit::{self, AssocCtxt, Visitor};
+use rustc_ast_lowering::ResolverAstLowering;
use rustc_attr as attr;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{struct_span_err, Applicability};
fragment: &AstFragment,
parent_scope: ParentScope<'a>,
) -> MacroRulesScope<'a> {
- collect_definitions(&mut self.definitions, fragment, parent_scope.expansion);
+ collect_definitions(self, fragment, parent_scope.expansion);
let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope };
fragment.visit_with(&mut visitor);
visitor.parent_scope.macro_rules
module_path.push(Segment {
ident: Ident { name: kw::PathRoot, span: source.ident.span },
id: Some(self.r.next_node_id()),
+ has_generic_args: false,
});
source.ident.name = crate_name;
}
} else if orig_name == Some(kw::SelfLower) {
self.r.graph_root
} else {
- let def_id = self.r.definitions.local_def_id(item.id);
+ let def_id = self.r.local_def_id(item.id);
let crate_id =
- self.r.crate_loader.process_extern_crate(item, &self.r.definitions);
+ self.r.crate_loader.process_extern_crate(item, &self.r.definitions, def_id);
self.r.extern_crate_map.insert(def_id, crate_id);
self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
};
ItemKind::Mod(..) if ident.name == kw::Invalid => {} // Crate root
ItemKind::Mod(..) => {
- let def_id = self.r.definitions.local_def_id(item.id);
+ let def_id = self.r.local_def_id(item.id);
let module_kind = ModuleKind::Def(DefKind::Mod, def_id.to_def_id(), ident.name);
let module = self.r.arenas.alloc_module(ModuleData {
no_implicit_prelude: parent.no_implicit_prelude || {
// These items live in the value namespace.
ItemKind::Static(..) => {
- let res =
- Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id).to_def_id());
+ let res = Res::Def(DefKind::Static, self.r.local_def_id(item.id).to_def_id());
self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
}
ItemKind::Const(..) => {
- let res =
- Res::Def(DefKind::Const, self.r.definitions.local_def_id(item.id).to_def_id());
+ let res = Res::Def(DefKind::Const, self.r.local_def_id(item.id).to_def_id());
self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
}
ItemKind::Fn(..) => {
- let res =
- Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id).to_def_id());
+ let res = Res::Def(DefKind::Fn, self.r.local_def_id(item.id).to_def_id());
self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
// Functions introducing procedural macros reserve a slot
// These items live in the type namespace.
ItemKind::TyAlias(..) => {
- let res = Res::Def(
- DefKind::TyAlias,
- self.r.definitions.local_def_id(item.id).to_def_id(),
- );
+ let res = Res::Def(DefKind::TyAlias, self.r.local_def_id(item.id).to_def_id());
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
}
ItemKind::Enum(_, _) => {
- let def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+ let def_id = self.r.local_def_id(item.id).to_def_id();
self.r.variant_vis.insert(def_id, vis);
let module_kind = ModuleKind::Def(DefKind::Enum, def_id, ident.name);
let module = self.r.new_module(
}
ItemKind::TraitAlias(..) => {
- let res = Res::Def(
- DefKind::TraitAlias,
- self.r.definitions.local_def_id(item.id).to_def_id(),
- );
+ let res = Res::Def(DefKind::TraitAlias, self.r.local_def_id(item.id).to_def_id());
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
}
// These items live in both the type and value namespaces.
ItemKind::Struct(ref vdata, _) => {
// Define a name in the type namespace.
- let def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+ let def_id = self.r.local_def_id(item.id).to_def_id();
let res = Res::Def(DefKind::Struct, def_id);
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
}
let ctor_res = Res::Def(
DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(vdata)),
- self.r.definitions.local_def_id(ctor_node_id).to_def_id(),
+ self.r.local_def_id(ctor_node_id).to_def_id(),
);
self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis));
}
ItemKind::Union(ref vdata, _) => {
- let def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+ let def_id = self.r.local_def_id(item.id).to_def_id();
let res = Res::Def(DefKind::Union, def_id);
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
}
ItemKind::Trait(..) => {
- let def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+ let def_id = self.r.local_def_id(item.id).to_def_id();
// Add all the items within to a new module.
let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name);
/// Constructs the reduced graph for one foreign item.
fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) {
let (res, ns) = match item.kind {
- ForeignItemKind::Fn(..) => (
- Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id).to_def_id()),
- ValueNS,
- ),
- ForeignItemKind::Static(..) => (
- Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id).to_def_id()),
- ValueNS,
- ),
- ForeignItemKind::TyAlias(..) => (
- Res::Def(DefKind::ForeignTy, self.r.definitions.local_def_id(item.id).to_def_id()),
- TypeNS,
- ),
+ ForeignItemKind::Fn(..) => {
+ (Res::Def(DefKind::Fn, self.r.local_def_id(item.id).to_def_id()), ValueNS)
+ }
+ ForeignItemKind::Static(..) => {
+ (Res::Def(DefKind::Static, self.r.local_def_id(item.id).to_def_id()), ValueNS)
+ }
+ ForeignItemKind::TyAlias(..) => {
+ (Res::Def(DefKind::ForeignTy, self.r.local_def_id(item.id).to_def_id()), TypeNS)
+ }
ForeignItemKind::MacCall(_) => unreachable!(),
};
let parent = self.parent_scope.module;
fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScope<'a> {
let parent_scope = self.parent_scope;
let expansion = parent_scope.expansion;
- let def_id = self.r.definitions.local_def_id(item.id);
+ let def_id = self.r.local_def_id(item.id);
let (ext, ident, span, macro_rules) = match &item.kind {
ItemKind::MacroDef(def) => {
let ext = Lrc::new(self.r.compile_macro(item, self.r.session.edition()));
}
// Add the item to the trait info.
- let item_def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+ let item_def_id = self.r.local_def_id(item.id).to_def_id();
let (res, ns) = match item.kind {
AssocItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS),
AssocItemKind::Fn(_, ref sig, _, _) => {
}
fn visit_token(&mut self, t: Token) {
- if let token::Interpolated(nt) = t.kind {
+ if let token::Interpolated(nt, _) = t.kind {
if let token::NtExpr(ref expr) = *nt {
if let ast::ExprKind::MacCall(..) = expr.kind {
self.visit_invoc(expr.id);
let ident = variant.ident;
// Define a name in the type namespace.
- let def_id = self.r.definitions.local_def_id(variant.id).to_def_id();
+ let def_id = self.r.local_def_id(variant.id).to_def_id();
let res = Res::Def(DefKind::Variant, def_id);
self.r.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id));
// It's ok to use the variant's id as a ctor id since an
// error will be reported on any use of such resolution anyway.
let ctor_node_id = variant.data.ctor_id().unwrap_or(variant.id);
- let ctor_def_id = self.r.definitions.local_def_id(ctor_node_id).to_def_id();
+ let ctor_def_id = self.r.local_def_id(ctor_node_id).to_def_id();
let ctor_kind = CtorKind::from_ast(&variant.data);
let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
use rustc_ast::ast;
use rustc_ast::node_id::NodeMap;
use rustc_ast::visit::{self, Visitor};
+use rustc_ast_lowering::ResolverAstLowering;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::pluralize;
use rustc_middle::ty;
fn check_import(&mut self, id: ast::NodeId) {
let mut used = false;
self.r.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
- let def_id = self.r.definitions.local_def_id(id);
+ let def_id = self.r.local_def_id(id);
if !used {
if self.r.maybe_unused_trait_imports.contains(&def_id) {
// Check later.
}
}
ImportKind::ExternCrate { .. } => {
- let def_id = self.definitions.local_def_id(import.id);
+ let def_id = self.local_def_id(import.id);
self.maybe_unused_extern_crates.push((def_id, import.span));
}
ImportKind::MacroUse => {
+use crate::Resolver;
use log::debug;
use rustc_ast::ast::*;
use rustc_ast::token::{self, Token};
use rustc_ast::visit::{self, FnKind};
use rustc_ast::walk_list;
+use rustc_ast_lowering::ResolverAstLowering;
use rustc_expand::expand::AstFragment;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::definitions::*;
use rustc_span::Span;
crate fn collect_definitions(
- definitions: &mut Definitions,
+ resolver: &mut Resolver<'_>,
fragment: &AstFragment,
expansion: ExpnId,
) {
- let parent_def = definitions.invocation_parent(expansion);
- fragment.visit_with(&mut DefCollector { definitions, parent_def, expansion });
+ let parent_def = resolver.invocation_parents[&expansion];
+ fragment.visit_with(&mut DefCollector { resolver, parent_def, expansion });
}
/// Creates `DefId`s for nodes in the AST.
-struct DefCollector<'a> {
- definitions: &'a mut Definitions,
+struct DefCollector<'a, 'b> {
+ resolver: &'a mut Resolver<'b>,
parent_def: LocalDefId,
expansion: ExpnId,
}
-impl<'a> DefCollector<'a> {
+impl<'a, 'b> DefCollector<'a, 'b> {
fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId {
let parent_def = self.parent_def;
debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
- self.definitions.create_def_with_parent(parent_def, node_id, data, self.expansion, span)
+ self.resolver.create_def(parent_def, node_id, data, self.expansion, span)
}
fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) {
let index = |this: &Self| {
index.unwrap_or_else(|| {
let node_id = NodeId::placeholder_from_expn_id(this.expansion);
- this.definitions.placeholder_field_index(node_id)
+ this.resolver.placeholder_field_indices[&node_id]
})
};
if field.is_placeholder {
- self.definitions.set_placeholder_field_index(field.id, index(self));
+ let old_index = self.resolver.placeholder_field_indices.insert(field.id, index(self));
+ assert!(old_index.is_none(), "placeholder field index is reset for a node ID");
self.visit_macro_invoc(field.id);
} else {
let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name);
}
fn visit_macro_invoc(&mut self, id: NodeId) {
- self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def);
+ let old_parent =
+ self.resolver.invocation_parents.insert(id.placeholder_to_expn_id(), self.parent_def);
+ assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation");
}
}
-impl<'a> visit::Visitor<'a> for DefCollector<'a> {
+impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
fn visit_item(&mut self, i: &'a Item) {
debug!("visit_item: {:?}", i);
}
fn visit_token(&mut self, t: Token) {
- if let token::Interpolated(nt) = t.kind {
+ if let token::Interpolated(nt, _) = t.kind {
if let token::NtExpr(ref expr) = *nt {
if let ExprKind::MacCall(..) = expr.kind {
self.visit_macro_invoc(expr.id);
pub did: Option<DefId>,
pub descr: &'static str,
pub path: Path,
+ pub accessible: bool,
}
/// Adjust the impl span so that just the `impl` keyword is taken by removing
match outer_res {
Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
if let Some(impl_span) =
- maybe_impl_defid.and_then(|def_id| self.definitions.opt_span(def_id))
+ maybe_impl_defid.and_then(|def_id| self.opt_span(def_id))
{
err.span_label(
reduce_impl_span_to_impl_keyword(sm, impl_span),
return err;
}
Res::Def(DefKind::TyParam, def_id) => {
- if let Some(span) = self.definitions.opt_span(def_id) {
+ if let Some(span) = self.opt_span(def_id) {
err.span_label(span, "type parameter from outer function");
}
}
Res::Def(DefKind::ConstParam, def_id) => {
- if let Some(span) = self.definitions.opt_span(def_id) {
+ if let Some(span) = self.opt_span(def_id) {
err.span_label(span, "const parameter from outer function");
}
}
let mut candidates = Vec::new();
let mut seen_modules = FxHashSet::default();
let not_local_module = crate_name.name != kw::Crate;
- let mut worklist = vec![(start_module, Vec::<ast::PathSegment>::new(), not_local_module)];
-
- while let Some((in_module, path_segments, in_module_is_extern)) = worklist.pop() {
+ let mut worklist =
+ vec![(start_module, Vec::<ast::PathSegment>::new(), true, not_local_module)];
+ let mut worklist_via_import = vec![];
+
+ while let Some((in_module, path_segments, accessible, in_module_is_extern)) =
+ match worklist.pop() {
+ None => worklist_via_import.pop(),
+ Some(x) => Some(x),
+ }
+ {
// We have to visit module children in deterministic order to avoid
// instabilities in reported imports (#43552).
in_module.for_each_child(self, |this, ident, ns, name_binding| {
- // avoid imports entirely
- if name_binding.is_import() && !name_binding.is_extern_crate() {
+ // avoid non-importable candidates
+ if !name_binding.is_importable() {
return;
}
- // avoid non-importable candidates as well
- if !name_binding.is_importable() {
+
+ let child_accessible =
+ accessible && this.is_accessible_from(name_binding.vis, parent_scope.module);
+
+ // do not venture inside inaccessible items of other crates
+ if in_module_is_extern && !child_accessible {
+ return;
+ }
+
+ let via_import = name_binding.is_import() && !name_binding.is_extern_crate();
+
+ // There is an assumption elsewhere that paths of variants are in the enum's
+ // declaration and not imported. With this assumption, the variant component is
+ // chopped and the rest of the path is assumed to be the enum's own path. For
+ // errors where a variant is used as the type instead of the enum, this causes
+ // funny looking invalid suggestions, i.e `foo` instead of `foo::MyEnum`.
+ if via_import && name_binding.is_possibly_imported_variant() {
return;
}
segms.push(ast::PathSegment::from_ident(ident));
let path = Path { span: name_binding.span, segments: segms };
- // the entity is accessible in the following cases:
- // 1. if it's defined in the same crate, it's always
- // accessible (since private entities can be made public)
- // 2. if it's defined in another crate, it's accessible
- // only if both the module is public and the entity is
- // declared as public (due to pruning, we don't explore
- // outside crate private modules => no need to check this)
- if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
- let did = match res {
- Res::Def(DefKind::Ctor(..), did) => this.parent(did),
- _ => res.opt_def_id(),
- };
- if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
- candidates.push(ImportSuggestion { did, descr: res.descr(), path });
+ let did = match res {
+ Res::Def(DefKind::Ctor(..), did) => this.parent(did),
+ _ => res.opt_def_id(),
+ };
+
+ if child_accessible {
+ // Remove invisible match if exists
+ if let Some(idx) = candidates
+ .iter()
+ .position(|v: &ImportSuggestion| v.did == did && !v.accessible)
+ {
+ candidates.remove(idx);
}
}
+
+ if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
+ candidates.push(ImportSuggestion {
+ did,
+ descr: res.descr(),
+ path,
+ accessible: child_accessible,
+ });
+ }
}
}
let is_extern_crate_that_also_appears_in_prelude =
name_binding.is_extern_crate() && lookup_ident.span.rust_2018();
- let is_visible_to_user =
- !in_module_is_extern || name_binding.vis == ty::Visibility::Public;
-
- if !is_extern_crate_that_also_appears_in_prelude && is_visible_to_user {
- // add the module to the lookup
+ if !is_extern_crate_that_also_appears_in_prelude {
let is_extern = in_module_is_extern || name_binding.is_extern_crate();
+ // add the module to the lookup
if seen_modules.insert(module.def_id().unwrap()) {
- worklist.push((module, path_segments, is_extern));
+ if via_import { &mut worklist_via_import } else { &mut worklist }
+ .push((module, path_segments, child_accessible, is_extern));
}
}
}
})
}
+ // If only some candidates are accessible, take just them
+ if !candidates.iter().all(|v: &ImportSuggestion| !v.accessible) {
+ candidates = candidates.into_iter().filter(|x| x.accessible).collect();
+ }
+
candidates
}
Applicability::MaybeIncorrect,
);
let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate {
- LOCAL_CRATE => self.definitions.opt_span(def_id),
+ LOCAL_CRATE => self.opt_span(def_id),
_ => Some(
self.session
.source_map()
use rustc_ast::ast::NodeId;
use rustc_ast::unwrap_or;
use rustc_ast::util::lev_distance::find_best_match_for_name;
+use rustc_ast_lowering::ResolverAstLowering;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::ptr_key::PtrKey;
use rustc_errors::{pluralize, struct_span_err, Applicability};
let is_good_import =
binding.is_import() && !binding.is_ambiguity() && !ident.span.from_expansion();
if is_good_import || binding.is_macro_def() {
- let res = binding.res().map_id(|id| this.definitions.local_def_id(id));
+ let res = binding.res().map_id(|id| this.local_def_id(id));
if res != def::Res::Err {
reexports.push(Export { ident, res, span: binding.span, vis: binding.vis });
}
use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{unwrap_or, walk_list};
+use rustc_ast_lowering::ResolverAstLowering;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::DiagnosticId;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::TraitCandidate;
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
+use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use smallvec::{smallvec, SmallVec};
for param in &generics.params {
match param.kind {
- GenericParamKind::Lifetime { .. } => self.visit_generic_param(param),
- GenericParamKind::Type { ref default, .. } => {
+ GenericParamKind::Lifetime => self.visit_generic_param(param),
+ GenericParamKind::Type { ref default } => {
for bound in ¶m.bounds {
self.visit_param_bound(bound);
}
// Allow all following defaults to refer to this type parameter.
default_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
}
- GenericParamKind::Const { ref ty } => {
+ GenericParamKind::Const { ref ty, kw_span: _ } => {
for bound in ¶m.bounds {
self.visit_param_bound(bound);
}
}
fn with_scope<T>(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
- let id = self.r.definitions.local_def_id(id);
+ let id = self.r.local_def_id(id);
let module = self.r.module_map.get(&id).cloned(); // clones a reference
if let Some(module) = module {
// Move down in the graph.
debug!("resolve_adt");
self.with_current_self_item(item, |this| {
this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
- let item_def_id = this.r.definitions.local_def_id(item.id).to_def_id();
+ let item_def_id = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| {
visit::walk_item(this, item);
});
ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => {
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
- let local_def_id = this.r.definitions.local_def_id(item.id).to_def_id();
+ let local_def_id = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds);
ItemKind::TraitAlias(ref generics, ref bounds) => {
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
- let local_def_id = this.r.definitions.local_def_id(item.id).to_def_id();
+ let local_def_id = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds);
seen_bindings.entry(ident).or_insert(param.ident.span);
// Plain insert (no renaming).
- let res = Res::Def(def_kind, self.r.definitions.local_def_id(param.id).to_def_id());
+ let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id());
match param.kind {
GenericParamKind::Type { .. } => {
this.with_self_rib(Res::SelfTy(None, None), |this| {
// Resolve the trait reference, if necessary.
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
- let item_def_id = this.r.definitions.local_def_id(item_id).to_def_id();
+ let item_def_id = this.r.local_def_id(item_id).to_def_id();
this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| {
if let Some(trait_ref) = opt_trait_reference.as_ref() {
// Resolve type arguments in the trait path.
if let StmtKind::Item(ref item) = stmt.kind {
if let ItemKind::MacroDef(..) = item.kind {
num_macro_definition_ribs += 1;
- let res = self.r.definitions.local_def_id(item.id).to_def_id();
+ let res = self.r.local_def_id(item.id).to_def_id();
self.ribs[ValueNS].push(Rib::new(MacroDefinition(res)));
self.label_ribs.push(Rib::new(MacroDefinition(res)));
}
&mut self,
mut ident: Ident,
ns: Namespace,
- ) -> Vec<TraitCandidate<NodeId>> {
+ ) -> Vec<TraitCandidate> {
debug!("(getting traits containing item) looking for '{}'", ident.name);
let mut found_traits = Vec::new();
ident: Ident,
ns: Namespace,
module: Module<'a>,
- found_traits: &mut Vec<TraitCandidate<NodeId>>,
+ found_traits: &mut Vec<TraitCandidate>,
) {
assert!(ns == TypeNS || ns == ValueNS);
let mut traits = module.traits.borrow_mut();
&mut self,
mut kind: &NameBindingKind<'_>,
trait_name: Ident,
- ) -> SmallVec<[NodeId; 1]> {
+ ) -> SmallVec<[LocalDefId; 1]> {
let mut import_ids = smallvec![];
while let NameBindingKind::Import { import, binding, .. } = kind {
- let id = self.r.definitions.local_def_id(import.id);
+ let id = self.r.local_def_id(import.id);
self.r.maybe_unused_trait_imports.insert(id);
self.r.add_to_glob_map(&import, trait_name);
- import_ids.push(import.id);
+ import_ids.push(id);
kind = &binding.kind;
}
import_ids
_ => {}
}
if !suggested {
- if let Some(span) = self.r.definitions.opt_span(def_id) {
+ if let Some(span) = self.r.opt_span(def_id) {
err.span_label(span, &format!("`{}` defined here", path_str));
}
err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", path_str));
if nightly_options::is_nightly_build() {
let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
`type` alias";
- if let Some(span) = self.r.definitions.opt_span(def_id) {
+ if let Some(span) = self.r.opt_span(def_id) {
err.span_help(span, msg);
} else {
err.help(msg);
bad_struct_syntax_suggestion(def_id);
}
(Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => {
- if let Some(span) = self.r.definitions.opt_span(def_id) {
+ if let Some(span) = self.r.opt_span(def_id) {
err.span_label(span, &format!("`{}` defined here", path_str));
}
err.span_label(span, format!("did you mean `{}( /* fields */ )`?", path_str));
let path = Path { span: name_binding.span, segments: path_segments };
result = Some((
module,
- ImportSuggestion { did: Some(def_id), descr: "module", path },
+ ImportSuggestion {
+ did: Some(def_id),
+ descr: "module",
+ path,
+ accessible: true,
+ },
));
} else {
// add the module to the lookup
&self,
path: &[Segment],
) -> Option<(Span, &'static str, String, Applicability)> {
- let ident = match path {
- [segment] => segment.ident,
+ let (ident, span) = match path {
+ [segment] if !segment.has_generic_args => {
+ (segment.ident.to_string(), segment.ident.span)
+ }
_ => return None,
};
- match (
- self.diagnostic_metadata.current_item,
- self.diagnostic_metadata.currently_processing_generics,
- ) {
- (Some(Item { kind: ItemKind::Fn(..), ident, .. }), true) if ident.name == sym::main => {
+ let mut iter = ident.chars().map(|c| c.is_uppercase());
+ let single_uppercase_char =
+ matches!(iter.next(), Some(true)) && matches!(iter.next(), None);
+ if !self.diagnostic_metadata.currently_processing_generics && !single_uppercase_char {
+ return None;
+ }
+ match (self.diagnostic_metadata.current_item, single_uppercase_char) {
+ (Some(Item { kind: ItemKind::Fn(..), ident, .. }), _) if ident.name == sym::main => {
// Ignore `fn main()` as we don't want to suggest `fn main<T>()`
}
- (Some(Item { kind, .. }), true) => {
+ (
+ Some(Item {
+ kind:
+ kind @ ItemKind::Fn(..)
+ | kind @ ItemKind::Enum(..)
+ | kind @ ItemKind::Struct(..)
+ | kind @ ItemKind::Union(..),
+ ..
+ }),
+ true,
+ )
+ | (Some(Item { kind, .. }), false) => {
// Likely missing type parameter.
if let Some(generics) = kind.generics() {
+ if span.overlaps(generics.span) {
+ // Avoid the following:
+ // error[E0405]: cannot find trait `A` in this scope
+ // --> $DIR/typo-suggestion-named-underscore.rs:CC:LL
+ // |
+ // L | fn foo<T: A>(x: T) {} // Shouldn't suggest underscore
+ // | ^- help: you might be missing a type parameter: `, A`
+ // | |
+ // | not found in this scope
+ return None;
+ }
let msg = "you might be missing a type parameter";
let (span, sugg) = if let [.., param] = &generics.params[..] {
let span = if let [.., bound] = ¶m.bounds[..] {
})
.collect();
if !lifetimes.is_empty() {
- self.trait_ref_hack = true;
let next_early_index = self.next_early_index();
let scope = Scope::Binder {
lifetimes,
let result = self.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &bound_generic_params);
this.visit_ty(&bounded_ty);
+ this.trait_ref_hack = true;
walk_list!(this, visit_param_bound, bounds);
+ this.trait_ref_hack = false;
});
- self.trait_ref_hack = false;
result
} else {
self.visit_ty(&bounded_ty);
debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref);
- if !self.trait_ref_hack
+
+ let trait_ref_hack = take(&mut self.trait_ref_hack);
+ if !trait_ref_hack
|| trait_ref.bound_generic_params.iter().any(|param| match param.kind {
GenericParamKind::Lifetime { .. } => true,
_ => false,
})
{
- if self.trait_ref_hack {
+ if trait_ref_hack {
struct_span_err!(
self.tcx.sess,
trait_ref.span,
this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
this.visit_trait_ref(&trait_ref.trait_ref);
- })
+ });
} else {
self.visit_trait_ref(&trait_ref.trait_ref);
}
+ self.trait_ref_hack = trait_ref_hack;
if should_pop_missing_lt {
self.missing_named_lifetime_spots.pop();
}
use rustc_ast::node_id::NodeMap;
use rustc_ast::unwrap_or;
use rustc_ast::visit::{self, Visitor};
+use rustc_ast_lowering::ResolverAstLowering;
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::ptr_key::PtrKey;
use rustc_hir::def::Namespace::*;
use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
-use rustc_hir::definitions::{DefKey, Definitions};
+use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
use rustc_hir::PrimTy::{self, Bool, Char, Float, Int, Str, Uint};
-use rustc_hir::TraitMap;
+use rustc_hir::TraitCandidate;
+use rustc_index::vec::IndexVec;
use rustc_metadata::creader::{CStore, CrateLoader};
use rustc_middle::hir::exports::ExportMap;
use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn};
ModuleOnly(Span),
}
-// A minimal representation of a path segment. We use this in resolve because
-// we synthesize 'path segments' which don't have the rest of an AST or HIR
-// `PathSegment`.
+/// A minimal representation of a path segment. We use this in resolve because we synthesize 'path
+/// segments' which don't have the rest of an AST or HIR `PathSegment`.
#[derive(Clone, Copy, Debug)]
pub struct Segment {
ident: Ident,
id: Option<NodeId>,
+ /// Signals whether this `PathSegment` has generic arguments. Used to avoid providing
+ /// nonsensical suggestions.
+ has_generic_args: bool,
}
impl Segment {
}
fn from_ident(ident: Ident) -> Segment {
- Segment { ident, id: None }
+ Segment { ident, id: None, has_generic_args: false }
}
fn names_to_string(segments: &[Segment]) -> String {
impl<'a> From<&'a ast::PathSegment> for Segment {
fn from(seg: &'a ast::PathSegment) -> Segment {
- Segment { ident: seg.ident, id: Some(seg.id) }
+ Segment { ident: seg.ident, id: Some(seg.id), has_generic_args: seg.args.is_some() }
}
}
-struct UsePlacementFinder<'d> {
- definitions: &'d Definitions,
- target_module: LocalDefId,
+struct UsePlacementFinder {
+ target_module: NodeId,
span: Option<Span>,
found_use: bool,
}
-impl<'d> UsePlacementFinder<'d> {
- fn check(
- definitions: &'d Definitions,
- krate: &Crate,
- target_module: DefId,
- ) -> (Option<Span>, bool) {
- if let Some(target_module) = target_module.as_local() {
- let mut finder =
- UsePlacementFinder { definitions, target_module, span: None, found_use: false };
- visit::walk_crate(&mut finder, krate);
- (finder.span, finder.found_use)
- } else {
- (None, false)
- }
+impl UsePlacementFinder {
+ fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, bool) {
+ let mut finder = UsePlacementFinder { target_module, span: None, found_use: false };
+ visit::walk_crate(&mut finder, krate);
+ (finder.span, finder.found_use)
}
}
-impl<'tcx, 'd> Visitor<'tcx> for UsePlacementFinder<'d> {
+impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
fn visit_mod(
&mut self,
module: &'tcx ast::Mod,
if self.span.is_some() {
return;
}
- if self.definitions.local_def_id(node_id) != self.target_module {
+ if node_id != self.target_module {
visit::walk_mod(self, module);
return;
}
}
}
+ fn is_possibly_imported_variant(&self) -> bool {
+ match self.kind {
+ NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(),
+ _ => self.is_variant(),
+ }
+ }
+
// We sometimes need to treat variants as `pub` for backwards compatibility.
fn pseudo_vis(&self) -> ty::Visibility {
if self.is_variant() && self.res().def_id().is_local() {
/// `CrateNum` resolutions of `extern crate` items.
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
export_map: ExportMap<LocalDefId>,
- trait_map: TraitMap<NodeId>,
+ trait_map: NodeMap<Vec<TraitCandidate>>,
/// A map from nodes to anonymous modules.
/// Anonymous modules are pseudo-modules that are implicitly created around items
lint_buffer: LintBuffer,
next_node_id: NodeId,
+
+ def_id_to_span: IndexVec<LocalDefId, Span>,
+
+ node_id_to_def_id: FxHashMap<ast::NodeId, LocalDefId>,
+ def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>,
+
+ /// Indices of unnamed struct or variant fields with unresolved attributes.
+ placeholder_field_indices: FxHashMap<NodeId, usize>,
+ /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
+ /// we know what parent node that fragment should be attached to thanks to this table.
+ invocation_parents: FxHashMap<ExpnId, LocalDefId>,
+
+ next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
}
/// Nothing really interesting here; it just provides memory for the rest of the crate.
/// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that
/// the resolver is no longer needed as all the relevant information is inline.
-impl rustc_ast_lowering::Resolver for Resolver<'_> {
+impl ResolverAstLowering for Resolver<'_> {
fn def_key(&mut self, id: DefId) -> DefKey {
if let Some(id) = id.as_local() {
self.definitions().def_key(id)
fn next_node_id(&mut self) -> NodeId {
self.next_node_id()
}
+
+ fn trait_map(&self) -> &NodeMap<Vec<TraitCandidate>> {
+ &self.trait_map
+ }
+
+ fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
+ self.node_id_to_def_id.get(&node).copied()
+ }
+
+ fn local_def_id(&self, node: NodeId) -> LocalDefId {
+ self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
+ }
+
+ /// Adds a definition with a parent definition.
+ fn create_def(
+ &mut self,
+ parent: LocalDefId,
+ node_id: ast::NodeId,
+ data: DefPathData,
+ expn_id: ExpnId,
+ span: Span,
+ ) -> LocalDefId {
+ assert!(
+ !self.node_id_to_def_id.contains_key(&node_id),
+ "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
+ node_id,
+ data,
+ self.definitions.def_key(self.node_id_to_def_id[&node_id]),
+ );
+
+ // Find the next free disambiguator for this key.
+ let next_disambiguator = &mut self.next_disambiguator;
+ let next_disambiguator = |parent, data| {
+ let next_disamb = next_disambiguator.entry((parent, data)).or_insert(0);
+ let disambiguator = *next_disamb;
+ *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
+ disambiguator
+ };
+
+ let def_id = self.definitions.create_def(parent, data, expn_id, next_disambiguator);
+
+ assert_eq!(self.def_id_to_span.push(span), def_id);
+
+ // Some things for which we allocate `LocalDefId`s don't correspond to
+ // anything in the AST, so they don't have a `NodeId`. For these cases
+ // we don't need a mapping from `NodeId` to `LocalDefId`.
+ if node_id != ast::DUMMY_NODE_ID {
+ debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
+ self.node_id_to_def_id.insert(node_id, def_id);
+ }
+ assert_eq!(self.def_id_to_node_id.push(node_id), def_id);
+
+ def_id
+ }
}
impl<'a> Resolver<'a> {
let mut module_map = FxHashMap::default();
module_map.insert(LocalDefId { local_def_index: CRATE_DEF_INDEX }, graph_root);
- let mut definitions = Definitions::default();
- definitions.create_root_def(crate_name, session.local_crate_disambiguator());
+ let definitions = Definitions::new(crate_name, session.local_crate_disambiguator());
+ let root = definitions.get_root_def();
+
+ let mut def_id_to_span = IndexVec::default();
+ assert_eq!(def_id_to_span.push(rustc_span::DUMMY_SP), root);
+ let mut def_id_to_node_id = IndexVec::default();
+ assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), root);
+ let mut node_id_to_def_id = FxHashMap::default();
+ node_id_to_def_id.insert(CRATE_NODE_ID, root);
+
+ let mut invocation_parents = FxHashMap::default();
+ invocation_parents.insert(ExpnId::root(), root);
let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = session
.opts
variant_vis: Default::default(),
lint_buffer: LintBuffer::default(),
next_node_id: NodeId::from_u32(1),
+ def_id_to_span,
+ node_id_to_def_id,
+ def_id_to_node_id,
+ placeholder_field_indices: Default::default(),
+ invocation_parents,
+ next_disambiguator: Default::default(),
}
}
let definitions = self.definitions;
let extern_crate_map = self.extern_crate_map;
let export_map = self.export_map;
- let trait_map = self
- .trait_map
- .into_iter()
- .map(|(k, v)| {
- (
- definitions.node_id_to_hir_id(k),
- v.into_iter()
- .map(|tc| tc.map_import_ids(|id| definitions.node_id_to_hir_id(id)))
- .collect(),
- )
- })
- .collect();
let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
let maybe_unused_extern_crates = self.maybe_unused_extern_crates;
let glob_map = self.glob_map;
cstore: Box::new(self.crate_loader.into_cstore()),
extern_crate_map,
export_map,
- trait_map,
glob_map,
maybe_unused_trait_imports,
maybe_unused_extern_crates,
cstore: Box::new(self.cstore().clone()),
extern_crate_map: self.extern_crate_map.clone(),
export_map: self.export_map.clone(),
- trait_map: self
- .trait_map
- .iter()
- .map(|(&k, v)| {
- (
- self.definitions.node_id_to_hir_id(k),
- v.iter()
- .cloned()
- .map(|tc| {
- tc.map_import_ids(|id| self.definitions.node_id_to_hir_id(id))
- })
- .collect(),
- )
- })
- .collect(),
glob_map: self.glob_map.clone(),
maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(),
maybe_unused_extern_crates: self.maybe_unused_extern_crates.clone(),
#[inline]
fn add_to_glob_map(&mut self, import: &Import<'_>, ident: Ident) {
if import.is_glob() {
- let def_id = self.definitions.local_def_id(import.id);
+ let def_id = self.local_def_id(import.id);
self.glob_map.entry(def_id).or_default().insert(ident.name);
}
}
path, opt_ns, record_used, path_span, crate_lint,
);
- for (i, &Segment { ident, id }) in path.iter().enumerate() {
+ for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() {
debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
let record_segment_res = |this: &mut Self, res| {
if record_used {
for UseError { mut err, candidates, def_id, instead, suggestion } in
self.use_injections.drain(..)
{
- let (span, found_use) = UsePlacementFinder::check(&self.definitions, krate, def_id);
+ let (span, found_use) = if let Some(def_id) = def_id.as_local() {
+ UsePlacementFinder::check(krate, self.def_id_to_node_id[def_id])
+ } else {
+ (None, false)
+ };
if !candidates.is_empty() {
diagnostics::show_candidates(&mut err, span, &candidates, instead, found_use);
} else if let Some((span, msg, sugg, appl)) = suggestion {
pub fn all_macros(&self) -> &FxHashMap<Symbol, Res> {
&self.all_macros
}
+
+ /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
+ #[inline]
+ pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
+ if let Some(def_id) = def_id.as_local() { Some(self.def_id_to_span[def_id]) } else { None }
+ }
}
fn names_to_string(names: &[Symbol]) -> String {
use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak};
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
use rustc_ast::ast::{self, NodeId};
+use rustc_ast_lowering::ResolverAstLowering;
use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, StabilityLevel};
use rustc_data_structures::fx::FxHashSet;
-use rustc_expand::base::SyntaxExtension;
-use rustc_expand::base::{self, Indeterminate, InvocationRes};
+use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
use rustc_expand::compile_declarative_macro;
use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
use rustc_feature::is_builtin_attr_name;
(registered_attrs, registered_tools)
}
-impl<'a> base::Resolver for Resolver<'a> {
+impl<'a> ResolverExpand for Resolver<'a> {
fn next_node_id(&mut self) -> NodeId {
self.next_node_id()
}
)));
let parent_scope = if let Some(module_id) = parent_module_id {
- let parent_def_id = self.definitions.local_def_id(module_id);
+ let parent_def_id = self.local_def_id(module_id);
self.definitions.add_parent_module_of_macro_def(expn_id, parent_def_id.to_def_id());
self.module_map[&parent_def_id]
} else {
}
fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId {
- self.definitions.lint_node_id(expn_id)
+ self.invocation_parents
+ .get(&expn_id)
+ .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[*id])
}
fn has_derive_copy(&self, expn_id: ExpnId) -> bool {
}
pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> {
- let hir_node = self.tcx.hir().expect_expr(expr.hir_id);
- let ty = self.tables.expr_ty_adjusted_opt(&hir_node);
- if ty.is_none() || ty.unwrap().kind == ty::Error {
+ let ty = self.tables.expr_ty_adjusted_opt(expr)?;
+ if matches!(ty.kind, ty::Error(_)) {
return None;
}
match expr.kind {
hir::ExprKind::Field(ref sub_ex, ident) => {
- let hir_node = match self.tcx.hir().find(sub_ex.hir_id) {
- Some(Node::Expr(expr)) => expr,
- _ => {
- debug!(
- "Missing or weird node for sub-expression {} in {:?}",
- sub_ex.hir_id, expr
- );
- return None;
- }
- };
- match self.tables.expr_ty_adjusted(&hir_node).kind {
+ match self.tables.expr_ty_adjusted(&sub_ex).kind {
ty::Adt(def, _) if !def.is_enum() => {
let variant = &def.non_enum_variant();
filter!(self.span_utils, ident.span);
hir::QPath::Resolved(_, path) => path.segments.last().unwrap(),
hir::QPath::TypeRelative(_, segment) => segment,
};
- match self.tables.expr_ty_adjusted(&hir_node).kind {
- ty::Adt(def, _) if !def.is_enum() => {
+ match ty.kind {
+ ty::Adt(def, _) => {
let sub_span = segment.ident.span;
filter!(self.span_utils, sub_span);
let span = self.span_from_span(sub_span);
}))
}
_ => {
- // FIXME ty could legitimately be an enum, but then we will fail
- // later if we try to look up the fields.
- debug!("expected struct or union, found {:?}", ty);
+ debug!("expected adt, found {:?}", ty);
None
}
}
path = "lib.rs"
[dependencies]
+bitflags = "1.2.1"
getopts = "0.2"
log = "0.4"
rustc_errors = { path = "../librustc_errors" }
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::impl_stable_hash_via_hash;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_target::spec::{Target, TargetTriple};
pub ptr_width: u32,
}
-#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
-pub enum Sanitizer {
- Address,
- Leak,
- Memory,
- Thread,
+bitflags! {
+ #[derive(Default, RustcEncodable, RustcDecodable)]
+ pub struct SanitizerSet: u8 {
+ const ADDRESS = 1 << 0;
+ const LEAK = 1 << 1;
+ const MEMORY = 1 << 2;
+ const THREAD = 1 << 3;
+ }
}
-impl fmt::Display for Sanitizer {
+/// Formats a sanitizer set as a comma separated list of sanitizers' names.
+impl fmt::Display for SanitizerSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- Sanitizer::Address => "address".fmt(f),
- Sanitizer::Leak => "leak".fmt(f),
- Sanitizer::Memory => "memory".fmt(f),
- Sanitizer::Thread => "thread".fmt(f),
+ let mut first = true;
+ for s in *self {
+ let name = match s {
+ SanitizerSet::ADDRESS => "address",
+ SanitizerSet::LEAK => "leak",
+ SanitizerSet::MEMORY => "memory",
+ SanitizerSet::THREAD => "thread",
+ _ => panic!("unrecognized sanitizer {:?}", s),
+ };
+ if !first {
+ f.write_str(",")?;
+ }
+ f.write_str(name)?;
+ first = false;
}
+ Ok(())
}
}
-impl FromStr for Sanitizer {
- type Err = ();
- fn from_str(s: &str) -> Result<Sanitizer, ()> {
- match s {
- "address" => Ok(Sanitizer::Address),
- "leak" => Ok(Sanitizer::Leak),
- "memory" => Ok(Sanitizer::Memory),
- "thread" => Ok(Sanitizer::Thread),
- _ => Err(()),
- }
+impl IntoIterator for SanitizerSet {
+ type Item = SanitizerSet;
+ type IntoIter = std::vec::IntoIter<SanitizerSet>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ [SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD]
+ .iter()
+ .copied()
+ .filter(|&s| self.contains(s))
+ .collect::<Vec<_>>()
+ .into_iter()
+ }
+}
+
+impl<CTX> HashStable<CTX> for SanitizerSet {
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ self.bits().hash_stable(ctx, hasher);
}
}
Symbols,
}
-/// The different settings that the `-Z control_flow_guard` flag can have.
+/// The different settings that the `-Z control-flow-guard` flag can have.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum CFGuard {
/// Do not emit Control Flow Guard metadata or checks.
}
}
}
- if let Some(s) = &sess.opts.debugging_opts.sanitizer {
+
+ for s in sess.opts.debugging_opts.sanitizer {
let symbol = Symbol::intern(&s.to_string());
ret.insert((sym::sanitize, Some(symbol)));
}
+
if sess.opts.debug_assertions {
ret.insert((Symbol::intern("debug_assertions"), None));
}
}
}
};
+ log::debug!("got unpretty option: {:?}", first);
first
}
}
use PpMode::*;
use PpSourceMode::*;
match *self {
- PpmSource(PpmNormal | PpmEveryBodyLoops | PpmIdentified) => false,
+ PpmSource(PpmNormal | PpmIdentified) => false,
- PpmSource(PpmExpanded | PpmExpandedIdentified | PpmExpandedHygiene)
+ PpmSource(
+ PpmExpanded | PpmEveryBodyLoops | PpmExpandedIdentified | PpmExpandedHygiene,
+ )
| PpmHir(_)
| PpmHirTree(_)
| PpmMir
crate mod dep_tracking {
use super::{
CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
- OutputTypes, Passes, Sanitizer, SourceFileHashAlgorithm, SwitchWithOptPath,
+ OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm, SwitchWithOptPath,
SymbolManglingVersion,
};
use crate::lint;
impl_dep_tracking_hash_via_hash!(UnstableFeatures);
impl_dep_tracking_hash_via_hash!(OutputTypes);
impl_dep_tracking_hash_via_hash!(NativeLibKind);
- impl_dep_tracking_hash_via_hash!(Sanitizer);
- impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
+ impl_dep_tracking_hash_via_hash!(SanitizerSet);
impl_dep_tracking_hash_via_hash!(CFGuard);
impl_dep_tracking_hash_via_hash!(TargetTriple);
impl_dep_tracking_hash_via_hash!(Edition);
impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
- impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
impl<T1, T2> DepTrackingHash for (T1, T2)
where
make_target_lib_path(self.sysroot, self.triple)
}
+ pub fn get_self_contained_lib_path(&self) -> PathBuf {
+ self.get_lib_path().join("self-contained")
+ }
+
pub fn search<F>(&self, mut pick: F)
where
F: FnMut(&SearchPathFile, PathKind) -> FileMatch,
}
// Returns a list of directories where target-specific tool binaries are located.
- pub fn get_tools_search_paths(&self) -> Vec<PathBuf> {
+ pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
let mut p = PathBuf::from(self.sysroot);
p.push(find_libdir(self.sysroot).as_ref());
p.push(RUST_LIB_DIR);
p.push(&self.triple);
p.push("bin");
- vec![p]
+ if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p.clone()] }
}
}
#![feature(crate_visibility_modifier)]
#![feature(or_patterns)]
+#[macro_use]
+extern crate bitflags;
+
pub mod cgu_reuse_tracker;
pub mod utils;
#[macro_use]
/// `Some` if this lint is feature gated, otherwise `None`.
pub feature_gate: Option<Symbol>,
+
+ pub crate_level_only: bool,
}
/// Extra information for a future incompatibility lint.
report_in_external_macro: false,
future_incompatible: None,
feature_gate: None,
+ crate_level_only: false,
}
}
future_incompatible: None,
is_plugin: true,
feature_gate: None,
+ crate_level_only: false,
};
);
}
reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>",
edition: None,
};
+ crate_level_only
}
declare_lint! {
declare_lint! {
pub UNUSED_CRATE_DEPENDENCIES,
Allow,
- "crate dependencies that are never used"
+ "crate dependencies that are never used",
+ crate_level_only
}
declare_lint! {
declare_lint! {
pub UNKNOWN_CRATE_TYPES,
Deny,
- "unknown crate type found in `#[crate_type]` directive"
+ "unknown crate type found in `#[crate_type]` directive",
+ crate_level_only
}
declare_lint! {
declare_lint! {
pub ELIDED_LIFETIMES_IN_PATHS,
Allow,
- "hidden lifetime parameters in types are deprecated"
+ "hidden lifetime parameters in types are deprecated",
+ crate_level_only
}
declare_lint! {
reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>",
edition: None,
};
+ crate_level_only
}
declare_lint! {
@feature_gate = sym::unsafe_block_in_unsafe_fn;
}
+declare_lint! {
+ pub CENUM_IMPL_DROP_CAST,
+ Warn,
+ "a C-like enum implementing Drop is cast",
+ @future_incompatible = FutureIncompatibleInfo {
+ reference: "issue #73333 <https://github.com/rust-lang/rust/issues/73333>",
+ edition: None,
+ };
+}
+
declare_lint_pass! {
/// Does nothing as a lint pass, but registers some `Lint`s
/// that are used by other parts of the compiler.
ASM_SUB_REGISTER,
UNSAFE_OP_IN_UNSAFE_FN,
INCOMPLETE_INCLUDE,
+ CENUM_IMPL_DROP_CAST,
]
}
pub const parse_passes: &str = "a space-separated list of passes, or `all`";
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
- pub const parse_sanitizer: &str = "one of: `address`, `leak`, `memory` or `thread`";
- pub const parse_sanitizer_list: &str = "comma separated list of sanitizers";
+ pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `leak`, `memory` or `thread`";
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
- pub const parse_cfguard: &str = "either `disabled`, `nochecks`, or `checks`";
+ pub const parse_cfguard: &str =
+ "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of();
pub const parse_optimization_fuel: &str = "crate=integer";
true
}
- fn parse_sanitizer(slot: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
- if let Some(Ok(s)) = v.map(str::parse) {
- *slot = Some(s);
- true
- } else {
- false
- }
- }
-
- fn parse_sanitizer_list(slot: &mut Vec<Sanitizer>, v: Option<&str>) -> bool {
+ fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
if let Some(v) = v {
- for s in v.split(',').map(str::parse) {
- if let Ok(s) = s {
- if !slot.contains(&s) {
- slot.push(s);
- }
- } else {
- return false;
+ for s in v.split(',') {
+ *slot |= match s {
+ "address" => SanitizerSet::ADDRESS,
+ "leak" => SanitizerSet::LEAK,
+ "memory" => SanitizerSet::MEMORY,
+ "thread" => SanitizerSet::THREAD,
+ _ => return false,
}
}
true
}
fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool {
- match v {
- Some("disabled") => *slot = CFGuard::Disabled,
- Some("nochecks") => *slot = CFGuard::NoChecks,
- Some("checks") => *slot = CFGuard::Checks,
- _ => return false,
+ if v.is_some() {
+ let mut bool_arg = None;
+ if parse_opt_bool(&mut bool_arg, v) {
+ *slot = if bool_arg.unwrap() {
+ CFGuard::Checks
+ } else {
+ CFGuard::Disabled
+ };
+ return true
+ }
}
+
+ *slot = match v {
+ None => CFGuard::Checks,
+ Some("checks") => CFGuard::Checks,
+ Some("nochecks") => CFGuard::NoChecks,
+ Some(_) => return false,
+ };
true
}
"enable the experimental Chalk-based trait solving engine"),
codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
"the backend to use"),
- control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [UNTRACKED],
- "use Windows Control Flow Guard (`disabled`, `nochecks` or `checks`)"),
+ control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED],
+ "use Windows Control Flow Guard (default: no)"),
crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
"inject the given attribute in the crate"),
debug_macros: bool = (false, parse_bool, [TRACKED],
"fix undefined behavior when a thread doesn't eventually make progress \
(such as entering an empty infinite loop) by inserting llvm.sideeffect \
(default: no)"),
+ instrument_coverage: bool = (false, parse_bool, [TRACKED],
+ "instrument the generated code with LLVM code region counters to (in the \
+ future) generate coverage reports (default: no; note, the compiler build \
+ config must include `profiler = true`)"),
instrument_mcount: bool = (false, parse_bool, [TRACKED],
"insert function instrument code for mcount-based tracing (default: no)"),
keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
"keep hygiene data after analysis (default: no)"),
link_native_libraries: bool = (true, parse_bool, [UNTRACKED],
"link native libraries in the linker invocation (default: yes)"),
+ link_self_contained: Option<bool> = (None, parse_opt_bool, [TRACKED],
+ "control whether to link Rust provided C objects/libraries or rely
+ on C toolchain installed in the system"),
link_only: bool = (false, parse_bool, [TRACKED],
"link the `.rlink` file generated by `-Z no-link` (default: no)"),
llvm_time_trace: bool = (false, parse_bool, [UNTRACKED],
// soon.
run_dsymutil: bool = (true, parse_bool, [TRACKED],
"if on Mac, run `dsymutil` and delete intermediate object files (default: yes)"),
- sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
+ sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
"use a sanitizer"),
sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
"enable origins tracking in MemorySanitizer"),
- sanitizer_recover: Vec<Sanitizer> = (vec![], parse_sanitizer_list, [TRACKED],
+ sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
"enable recovery for selected sanitizers"),
saturating_float_casts: Option<bool> = (None, parse_opt_bool, [TRACKED],
"make float->int casts UB-free: numbers outside the integer type's range are clipped to \
use rustc_span::source_map::{FilePathMapping, SourceMap};
use rustc_span::{MultiSpan, Span, Symbol};
+use std::collections::BTreeMap;
use std::path::PathBuf;
use std::str;
#[derive(Default)]
pub struct SymbolGallery {
/// All symbols occurred and their first occurrance span.
- pub symbols: Lock<FxHashMap<Symbol, Span>>,
+ pub symbols: Lock<BTreeMap<Symbol, Span>>,
}
impl SymbolGallery {
pub symbol_gallery: SymbolGallery,
/// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
pub reached_eof: Lock<bool>,
+ /// Environment variables accessed during the build and their values when they exist.
+ pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>,
}
impl ParseSess {
gated_spans: GatedSpans::default(),
symbol_gallery: SymbolGallery::default(),
reached_eof: Lock::new(false),
+ env_depinfo: Default::default(),
}
}
use crate::cgu_reuse_tracker::CguReuseTracker;
use crate::code_stats::CodeStats;
pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
-use crate::config::{self, CrateType, OutputType, PrintRequest, Sanitizer, SwitchWithOptPath};
+use crate::config::{self, CrateType, OutputType, PrintRequest, SanitizerSet, SwitchWithOptPath};
use crate::filesearch;
use crate::lint;
use crate::parse::ParseSess;
}
pub fn fewer_names(&self) -> bool {
let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
- || self.opts.output_types.contains_key(&OutputType::Bitcode);
-
- // Address sanitizer and memory sanitizer use alloca name when reporting an issue.
- let more_names = match self.opts.debugging_opts.sanitizer {
- Some(Sanitizer::Address) => true,
- Some(Sanitizer::Memory) => true,
- _ => more_names,
- };
+ || self.opts.output_types.contains_key(&OutputType::Bitcode)
+ // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
+ || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
self.opts.debugging_opts.fewer_names || !more_names
}
/// Checks if LLVM lifetime markers should be emitted.
pub fn emit_lifetime_markers(&self) -> bool {
- match self.opts.debugging_opts.sanitizer {
- // AddressSanitizer uses lifetimes to detect use after scope bugs.
- // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
- Some(Sanitizer::Address | Sanitizer::Memory) => true,
- _ => self.opts.optimize != config::OptLevel::No,
- }
+ self.opts.optimize != config::OptLevel::No
+ // AddressSanitizer uses lifetimes to detect use after scope bugs.
+ // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
+ || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY)
}
}
}
}
(config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new(
- JsonEmitter::stderr(Some(registry), source_map, pretty, json_rendered, macro_backtrace)
- .ui_testing(sopts.debugging_opts.ui_testing),
+ JsonEmitter::stderr(
+ Some(registry),
+ source_map,
+ pretty,
+ json_rendered,
+ sopts.debugging_opts.terminal_width,
+ macro_backtrace,
+ )
+ .ui_testing(sopts.debugging_opts.ui_testing),
),
(config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new(
JsonEmitter::new(
source_map,
pretty,
json_rendered,
+ sopts.debugging_opts.terminal_width,
macro_backtrace,
)
.ui_testing(sopts.debugging_opts.ui_testing),
);
}
+ const ASAN_SUPPORTED_TARGETS: &[&str] = &[
+ "aarch64-fuchsia",
+ "aarch64-unknown-linux-gnu",
+ "x86_64-apple-darwin",
+ "x86_64-fuchsia",
+ "x86_64-unknown-linux-gnu",
+ ];
+ const LSAN_SUPPORTED_TARGETS: &[&str] =
+ &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
+ const MSAN_SUPPORTED_TARGETS: &[&str] =
+ &["aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu"];
+ const TSAN_SUPPORTED_TARGETS: &[&str] =
+ &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
+
// Sanitizers can only be used on some tested platforms.
- if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
- const ASAN_SUPPORTED_TARGETS: &[&str] = &[
- "x86_64-unknown-linux-gnu",
- "x86_64-apple-darwin",
- "x86_64-fuchsia",
- "aarch64-fuchsia",
- ];
- const TSAN_SUPPORTED_TARGETS: &[&str] =
- &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
- const LSAN_SUPPORTED_TARGETS: &[&str] =
- &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
- const MSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
-
- let supported_targets = match *sanitizer {
- Sanitizer::Address => ASAN_SUPPORTED_TARGETS,
- Sanitizer::Thread => TSAN_SUPPORTED_TARGETS,
- Sanitizer::Leak => LSAN_SUPPORTED_TARGETS,
- Sanitizer::Memory => MSAN_SUPPORTED_TARGETS,
+ for s in sess.opts.debugging_opts.sanitizer {
+ let supported_targets = match s {
+ SanitizerSet::ADDRESS => ASAN_SUPPORTED_TARGETS,
+ SanitizerSet::LEAK => LSAN_SUPPORTED_TARGETS,
+ SanitizerSet::MEMORY => MSAN_SUPPORTED_TARGETS,
+ SanitizerSet::THREAD => TSAN_SUPPORTED_TARGETS,
+ _ => panic!("unrecognized sanitizer {}", s),
};
-
if !supported_targets.contains(&&*sess.opts.target_triple.triple()) {
sess.err(&format!(
- "{:?}Sanitizer only works with the `{}` target",
- sanitizer,
- supported_targets.join("` or `")
+ "`-Zsanitizer={}` only works with targets: {}",
+ s,
+ supported_targets.join(", ")
+ ));
+ }
+ let conflicting = sess.opts.debugging_opts.sanitizer - s;
+ if !conflicting.is_empty() {
+ sess.err(&format!(
+ "`-Zsanitizer={}` is incompatible with `-Zsanitizer={}`",
+ s, conflicting,
));
+ // Don't report additional errors.
+ break;
}
}
}
Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false))
}
config::ErrorOutputType::Json { pretty, json_rendered } => {
- Box::new(JsonEmitter::basic(pretty, json_rendered, false))
+ Box::new(JsonEmitter::basic(pretty, json_rendered, None, false))
}
};
let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false))
}
config::ErrorOutputType::Json { pretty, json_rendered } => {
- Box::new(JsonEmitter::basic(pretty, json_rendered, false))
+ Box::new(JsonEmitter::basic(pretty, json_rendered, None, false))
}
};
let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
Async,
Await,
ForLoop(ForLoopLoc),
- Operator,
}
/// A location in the desugaring of a `for` loop
DesugaringKind::TryBlock => "`try` block",
DesugaringKind::OpaqueTy => "`impl Trait`",
DesugaringKind::ForLoop(_) => "`for` loop",
- DesugaringKind::Operator => "operator",
}
}
}
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(crate_visibility_modifier)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(negative_impls)]
pub mod edition;
use edition::Edition;
pub mod hygiene;
+pub use hygiene::SyntaxContext;
use hygiene::Transparency;
-pub use hygiene::{
- DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind, SyntaxContext,
-};
+pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind};
pub mod def_id;
use def_id::{CrateNum, DefId, LOCAL_CRATE};
mod span_encoding;
assume_init,
async_await,
async_closure,
+ atomics,
attr,
attributes,
attr_literals,
copy_closures,
core,
core_intrinsics,
+ count_code_region,
crate_id,
crate_in_paths,
crate_local,
from_method,
from_ok,
from_usize,
+ from_trait,
fundamental,
future,
Future,
proc_macro_mod,
proc_macro_non_items,
proc_macro_path_invoc,
+ profiler_builtins,
profiler_runtime,
+ ptr_guaranteed_eq,
+ ptr_guaranteed_ne,
ptr_offset_from,
pub_restricted,
pure,
v1,
val,
var,
+ variant_count,
vec,
Vec,
version,
ty::Never => "z",
// Placeholders (should be demangled as `_`).
- ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error => "p",
+ ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => "p",
_ => "",
};
ty::Tuple(_) if ty.is_unit() => unreachable!(),
// Placeholders, also handled as part of basic types.
- ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error => {
+ ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
unreachable!()
}
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
Single { index: VariantIdx },
- /// Enum-likes with more than one inhabited variant: for each case there is
- /// a struct, and they all have space reserved for the discriminant.
- /// For enums this is the sole field of the layout.
+ /// Enum-likes with more than one inhabited variant: each variant comes with
+ /// a *discriminant* (usually the same as the variant index but the user can
+ /// assign explicit discriminant values). That discriminant is encoded
+ /// as a *tag* on the machine. The layout of each variant is
+ /// a struct, and they all have space reserved for the tag.
+ /// For enums, the tag is the sole field of the layout.
Multiple {
- discr: Scalar,
- discr_kind: DiscriminantKind,
- discr_index: usize,
+ tag: Scalar,
+ tag_encoding: TagEncoding,
+ tag_field: usize,
variants: IndexVec<VariantIdx, Layout>,
},
}
#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub enum DiscriminantKind {
- /// Integer tag holding the discriminant value itself.
- Tag,
+pub enum TagEncoding {
+ /// The tag directly stores the discriminant, but possibly with a smaller layout
+ /// (so converting the tag to the discriminant can require sign extension).
+ Direct,
/// Niche (values invalid for a type) encoding the discriminant:
- /// the variant `dataful_variant` contains a niche at an arbitrary
- /// offset (field `discr_index` of the enum), which for a variant with
+ /// Discriminant and variant index coincide.
+ /// The variant `dataful_variant` contains a niche at an arbitrary
+ /// offset (field `tag_field` of the enum), which for a variant with
/// discriminant `d` is set to
/// `(d - niche_variants.start).wrapping_add(niche_start)`.
///
use super::{InlineAsmArch, InlineAsmType};
+use crate::spec::Target;
use rustc_macros::HashStable_Generic;
use std::fmt;
}
}
+// This uses the same logic as useR7AsFramePointer in LLVM
+fn frame_pointer_is_r7(mut has_feature: impl FnMut(&str) -> bool, target: &Target) -> bool {
+ target.options.is_like_osx || (!target.options.is_like_windows && has_feature("thumb-mode"))
+}
+
+fn frame_pointer_r11(
+ _arch: InlineAsmArch,
+ has_feature: impl FnMut(&str) -> bool,
+ target: &Target,
+ _allocating: bool,
+) -> Result<(), &'static str> {
+ if !frame_pointer_is_r7(has_feature, target) {
+ Err("the frame pointer (r11) cannot be used as an operand for inline asm")
+ } else {
+ Ok(())
+ }
+}
+
+fn frame_pointer_r7(
+ _arch: InlineAsmArch,
+ has_feature: impl FnMut(&str) -> bool,
+ target: &Target,
+ _allocating: bool,
+) -> Result<(), &'static str> {
+ if frame_pointer_is_r7(has_feature, target) {
+ Err("the frame pointer (r7) cannot be used as an operand for inline asm")
+ } else {
+ Ok(())
+ }
+}
+
def_regs! {
Arm ArmInlineAsmReg ArmInlineAsmRegClass {
r0: reg, reg_thumb = ["r0", "a1"],
r3: reg, reg_thumb = ["r3", "a4"],
r4: reg, reg_thumb = ["r4", "v1"],
r5: reg, reg_thumb = ["r5", "v2"],
- r6: reg, reg_thumb = ["r6", "v3"],
- r7: reg, reg_thumb = ["r7", "v4"],
+ r7: reg, reg_thumb = ["r7", "v4"] % frame_pointer_r7,
r8: reg = ["r8", "v5"],
r9: reg = ["r9", "v6", "rfp"],
r10: reg = ["r10", "sl"],
+ r11: reg = ["r11", "fp"] % frame_pointer_r11,
r12: reg = ["r12", "ip"],
r14: reg = ["r14", "lr"],
s0: sreg, sreg_low16 = ["s0"],
q13: qreg = ["q13"],
q14: qreg = ["q14"],
q15: qreg = ["q15"],
- #error = ["r11", "fp"] =>
- "the frame pointer cannot be used as an operand for inline asm",
+ #error = ["r6", "v3"] =>
+ "r6 is used internally by LLVM and cannot be used as an operand for inline asm",
#error = ["r13", "sp"] =>
"the stack pointer cannot be used as an operand for inline asm",
#error = ["r15", "pc"] =>
--- /dev/null
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use std::fmt;
+
+def_reg_class! {
+ Hexagon HexagonInlineAsmRegClass {
+ reg,
+ }
+}
+
+impl HexagonInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'static str)> {
+ None
+ }
+
+ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+ None
+ }
+
+ pub fn supported_types(
+ self,
+ _arch: InlineAsmArch,
+ ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ match self {
+ Self::reg => types! { _: I8, I16, I32, F32; },
+ }
+ }
+}
+
+def_regs! {
+ Hexagon HexagonInlineAsmReg HexagonInlineAsmRegClass {
+ r0: reg = ["r0"],
+ r1: reg = ["r1"],
+ r2: reg = ["r2"],
+ r3: reg = ["r3"],
+ r4: reg = ["r4"],
+ r5: reg = ["r5"],
+ r6: reg = ["r6"],
+ r7: reg = ["r7"],
+ r8: reg = ["r8"],
+ r9: reg = ["r9"],
+ r10: reg = ["r10"],
+ r11: reg = ["r11"],
+ r12: reg = ["r12"],
+ r13: reg = ["r13"],
+ r14: reg = ["r14"],
+ r15: reg = ["r15"],
+ r16: reg = ["r16"],
+ r17: reg = ["r17"],
+ r18: reg = ["r18"],
+ r19: reg = ["r19"],
+ r20: reg = ["r20"],
+ r21: reg = ["r21"],
+ r22: reg = ["r22"],
+ r23: reg = ["r23"],
+ r24: reg = ["r24"],
+ r25: reg = ["r25"],
+ r26: reg = ["r26"],
+ r27: reg = ["r27"],
+ r28: reg = ["r28"],
+ #error = ["r29", "sp"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ #error = ["r30", "fr"] =>
+ "the frame register cannot be used as an operand for inline asm",
+ #error = ["r31", "lr"] =>
+ "the link register cannot be used as an operand for inline asm",
+ }
+}
+
+impl HexagonInlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ _modifier: Option<char>,
+ ) -> fmt::Result {
+ out.write_str(self.name())
+ }
+
+ pub fn overlapping_regs(self, mut _cb: impl FnMut(HexagonInlineAsmReg)) {}
+}
use crate::abi::Size;
+use crate::spec::Target;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_macros::HashStable_Generic;
use rustc_span::Symbol;
pub fn parse(
_arch: super::InlineAsmArch,
mut _has_feature: impl FnMut(&str) -> bool,
+ _target: &crate::spec::Target,
name: &str,
) -> Result<Self, &'static str> {
match name {
$(
$($alias)|* | $reg_name => {
- $($filter(_arch, &mut _has_feature, false)?;)?
+ $($filter(_arch, &mut _has_feature, _target, false)?;)?
Ok(Self::$reg)
}
)*
pub(super) fn fill_reg_map(
_arch: super::InlineAsmArch,
mut _has_feature: impl FnMut(&str) -> bool,
+ _target: &crate::spec::Target,
_map: &mut rustc_data_structures::fx::FxHashMap<
super::InlineAsmRegClass,
rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
#[allow(unused_imports)]
use super::{InlineAsmReg, InlineAsmRegClass};
$(
- if $($filter(_arch, &mut _has_feature, true).is_ok() &&)? true {
+ if $($filter(_arch, &mut _has_feature, _target, true).is_ok() &&)? true {
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
}
mod aarch64;
mod arm;
+mod hexagon;
mod nvptx;
mod riscv;
mod x86;
pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
+pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
RiscV32,
RiscV64,
Nvptx64,
+ Hexagon,
}
impl FromStr for InlineAsmArch {
"riscv32" => Ok(Self::RiscV32),
"riscv64" => Ok(Self::RiscV64),
"nvptx64" => Ok(Self::Nvptx64),
+ "hexagon" => Ok(Self::Hexagon),
_ => Err(()),
}
}
AArch64(AArch64InlineAsmReg),
RiscV(RiscVInlineAsmReg),
Nvptx(NvptxInlineAsmReg),
+ Hexagon(HexagonInlineAsmReg),
}
impl InlineAsmReg {
Self::Arm(r) => r.name(),
Self::AArch64(r) => r.name(),
Self::RiscV(r) => r.name(),
+ Self::Hexagon(r) => r.name(),
}
}
Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
+ Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
}
}
pub fn parse(
arch: InlineAsmArch,
has_feature: impl FnMut(&str) -> bool,
+ target: &Target,
name: Symbol,
) -> Result<Self, &'static str> {
// FIXME: use direct symbol comparison for register names
let name = name.as_str();
Ok(match arch {
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
- Self::X86(X86InlineAsmReg::parse(arch, has_feature, &name)?)
+ Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
+ }
+ InlineAsmArch::Arm => {
+ Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
- InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, &name)?),
InlineAsmArch::AArch64 => {
- Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, &name)?)
+ Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
}
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
- Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, &name)?)
+ Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
InlineAsmArch::Nvptx64 => {
- Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, &name)?)
+ Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
+ }
+ InlineAsmArch::Hexagon => {
+ Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
})
}
Self::Arm(r) => r.emit(out, arch, modifier),
Self::AArch64(r) => r.emit(out, arch, modifier),
Self::RiscV(r) => r.emit(out, arch, modifier),
+ Self::Hexagon(r) => r.emit(out, arch, modifier),
}
}
Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
Self::AArch64(_) => cb(self),
Self::RiscV(_) => cb(self),
+ Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
}
}
}
AArch64(AArch64InlineAsmRegClass),
RiscV(RiscVInlineAsmRegClass),
Nvptx(NvptxInlineAsmRegClass),
+ Hexagon(HexagonInlineAsmRegClass),
}
impl InlineAsmRegClass {
Self::AArch64(r) => r.name(),
Self::RiscV(r) => r.name(),
Self::Nvptx(r) => r.name(),
+ Self::Hexagon(r) => r.name(),
}
}
Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
+ Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
}
}
Self::AArch64(r) => r.suggest_modifier(arch, ty),
Self::RiscV(r) => r.suggest_modifier(arch, ty),
Self::Nvptx(r) => r.suggest_modifier(arch, ty),
+ Self::Hexagon(r) => r.suggest_modifier(arch, ty),
}
}
Self::AArch64(r) => r.default_modifier(arch),
Self::RiscV(r) => r.default_modifier(arch),
Self::Nvptx(r) => r.default_modifier(arch),
+ Self::Hexagon(r) => r.default_modifier(arch),
}
}
Self::AArch64(r) => r.supported_types(arch),
Self::RiscV(r) => r.supported_types(arch),
Self::Nvptx(r) => r.supported_types(arch),
+ Self::Hexagon(r) => r.supported_types(arch),
}
}
Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
}
InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
+ InlineAsmArch::Hexagon => {
+ Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?)
+ }
})
})
}
Self::AArch64(r) => r.valid_modifiers(arch),
Self::RiscV(r) => r.valid_modifiers(arch),
Self::Nvptx(r) => r.valid_modifiers(arch),
+ Self::Hexagon(r) => r.valid_modifiers(arch),
}
}
}
pub fn allocatable_registers(
arch: InlineAsmArch,
has_feature: impl FnMut(&str) -> bool,
+ target: &crate::spec::Target,
) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
match arch {
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
let mut map = x86::regclass_map();
- x86::fill_reg_map(arch, has_feature, &mut map);
+ x86::fill_reg_map(arch, has_feature, target, &mut map);
map
}
InlineAsmArch::Arm => {
let mut map = arm::regclass_map();
- arm::fill_reg_map(arch, has_feature, &mut map);
+ arm::fill_reg_map(arch, has_feature, target, &mut map);
map
}
InlineAsmArch::AArch64 => {
let mut map = aarch64::regclass_map();
- aarch64::fill_reg_map(arch, has_feature, &mut map);
+ aarch64::fill_reg_map(arch, has_feature, target, &mut map);
map
}
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
let mut map = riscv::regclass_map();
- riscv::fill_reg_map(arch, has_feature, &mut map);
+ riscv::fill_reg_map(arch, has_feature, target, &mut map);
map
}
InlineAsmArch::Nvptx64 => {
let mut map = nvptx::regclass_map();
- nvptx::fill_reg_map(arch, has_feature, &mut map);
+ nvptx::fill_reg_map(arch, has_feature, target, &mut map);
+ map
+ }
+ InlineAsmArch::Hexagon => {
+ let mut map = hexagon::regclass_map();
+ hexagon::fill_reg_map(arch, has_feature, target, &mut map);
map
}
}
use super::{InlineAsmArch, InlineAsmType};
+use crate::spec::Target;
use rustc_macros::HashStable_Generic;
use std::fmt;
fn not_e(
_arch: InlineAsmArch,
mut has_feature: impl FnMut(&str) -> bool,
+ _target: &Target,
_allocating: bool,
) -> Result<(), &'static str> {
if has_feature("e") {
use super::{InlineAsmArch, InlineAsmType};
+use crate::spec::Target;
use rustc_macros::HashStable_Generic;
use std::fmt;
fn x86_64_only(
arch: InlineAsmArch,
_has_feature: impl FnMut(&str) -> bool,
+ _target: &Target,
_allocating: bool,
) -> Result<(), &'static str> {
match arch {
fn high_byte(
arch: InlineAsmArch,
_has_feature: impl FnMut(&str) -> bool,
+ _target: &Target,
allocating: bool,
) -> Result<(), &'static str> {
match arch {
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(bool_to_option)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(nll)]
let pre_link_args = build_pre_link_args(arch, os)?;
Ok(TargetOptions {
cpu: target_cpu(arch),
- dynamic_linking: false,
executables: true,
pre_link_args,
link_env_remove: link_env_remove(arch),
"ENCLAVE_SIZE",
"CFGDATA_BASE",
"DEBUG",
- "EH_FRM_HDR_BASE",
- "EH_FRM_HDR_SIZE",
+ "EH_FRM_HDR_OFFSET",
+ "EH_FRM_HDR_LEN",
+ "EH_FRM_OFFSET",
+ "EH_FRM_LEN",
"TEXT_BASE",
"TEXT_SIZE",
];
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.stack_probes = true;
+ base.static_position_independent_executables = true;
Ok(Target {
llvm_target: "x86_64-unknown-linux-musl".to_string(),
--- /dev/null
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::traits::{self, TraitEngine};
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_infer::infer::InferCtxt;
+use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
+use rustc_middle::ty::{ToPredicate, TypeFoldable};
+use rustc_session::DiagnosticMessageId;
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
+
+#[derive(Copy, Clone, Debug)]
+pub enum AutoderefKind {
+ Builtin,
+ Overloaded,
+}
+
+struct AutoderefSnapshot<'tcx> {
+ at_start: bool,
+ reached_recursion_limit: bool,
+ steps: Vec<(Ty<'tcx>, AutoderefKind)>,
+ cur_ty: Ty<'tcx>,
+ obligations: Vec<traits::PredicateObligation<'tcx>>,
+}
+
+pub struct Autoderef<'a, 'tcx> {
+ // Meta infos:
+ infcx: &'a InferCtxt<'a, 'tcx>,
+ span: Span,
+ body_id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+
+ // Current state:
+ state: AutoderefSnapshot<'tcx>,
+
+ // Configurations:
+ include_raw_pointers: bool,
+ silence_errors: bool,
+}
+
+impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
+ type Item = (Ty<'tcx>, usize);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let tcx = self.infcx.tcx;
+
+ debug!("autoderef: steps={:?}, cur_ty={:?}", self.state.steps, self.state.cur_ty);
+ if self.state.at_start {
+ self.state.at_start = false;
+ debug!("autoderef stage #0 is {:?}", self.state.cur_ty);
+ return Some((self.state.cur_ty, 0));
+ }
+
+ // If we have reached the recursion limit, error gracefully.
+ if !tcx.sess.recursion_limit().value_within_limit(self.state.steps.len()) {
+ if !self.silence_errors {
+ report_autoderef_recursion_limit_error(tcx, self.span, self.state.cur_ty);
+ }
+ self.state.reached_recursion_limit = true;
+ return None;
+ }
+
+ if self.state.cur_ty.is_ty_var() {
+ return None;
+ }
+
+ // Otherwise, deref if type is derefable:
+ let (kind, new_ty) =
+ if let Some(mt) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
+ (AutoderefKind::Builtin, mt.ty)
+ } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
+ (AutoderefKind::Overloaded, ty)
+ } else {
+ return None;
+ };
+
+ if new_ty.references_error() {
+ return None;
+ }
+
+ self.state.steps.push((self.state.cur_ty, kind));
+ debug!(
+ "autoderef stage #{:?} is {:?} from {:?}",
+ self.step_count(),
+ new_ty,
+ (self.state.cur_ty, kind)
+ );
+ self.state.cur_ty = new_ty;
+
+ Some((self.state.cur_ty, self.step_count()))
+ }
+}
+
+impl<'a, 'tcx> Autoderef<'a, 'tcx> {
+ pub fn new(
+ infcx: &'a InferCtxt<'a, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ body_id: hir::HirId,
+ span: Span,
+ base_ty: Ty<'tcx>,
+ ) -> Autoderef<'a, 'tcx> {
+ Autoderef {
+ infcx,
+ span,
+ body_id,
+ param_env,
+ state: AutoderefSnapshot {
+ steps: vec![],
+ cur_ty: infcx.resolve_vars_if_possible(&base_ty),
+ obligations: vec![],
+ at_start: true,
+ reached_recursion_limit: false,
+ },
+ include_raw_pointers: false,
+ silence_errors: false,
+ }
+ }
+
+ fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+ debug!("overloaded_deref_ty({:?})", ty);
+
+ let tcx = self.infcx.tcx;
+
+ // <ty as Deref>
+ let trait_ref = TraitRef {
+ def_id: tcx.lang_items().deref_trait()?,
+ substs: tcx.mk_substs_trait(ty, &[]),
+ };
+
+ let cause = traits::ObligationCause::misc(self.span, self.body_id);
+
+ let obligation = traits::Obligation::new(
+ cause.clone(),
+ self.param_env,
+ trait_ref.without_const().to_predicate(tcx),
+ );
+ if !self.infcx.predicate_may_hold(&obligation) {
+ debug!("overloaded_deref_ty: cannot match obligation");
+ return None;
+ }
+
+ let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
+ let normalized_ty = fulfillcx.normalize_projection_type(
+ &self.infcx,
+ self.param_env,
+ ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, Ident::from_str("Target")),
+ cause,
+ );
+ if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
+ // This shouldn't happen, except for evaluate/fulfill mismatches,
+ // but that's not a reason for an ICE (`predicate_may_hold` is conservative
+ // by design).
+ debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e);
+ return None;
+ }
+ let obligations = fulfillcx.pending_obligations();
+ debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
+ self.state.obligations.extend(obligations);
+
+ Some(self.infcx.resolve_vars_if_possible(&normalized_ty))
+ }
+
+ /// Returns the final type we ended up with, which may be an inference
+ /// variable (we will resolve it first, if we want).
+ pub fn final_ty(&self, resolve: bool) -> Ty<'tcx> {
+ if resolve {
+ self.infcx.resolve_vars_if_possible(&self.state.cur_ty)
+ } else {
+ self.state.cur_ty
+ }
+ }
+
+ pub fn step_count(&self) -> usize {
+ self.state.steps.len()
+ }
+
+ pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
+ self.state.obligations
+ }
+
+ pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] {
+ &self.state.steps
+ }
+
+ pub fn span(&self) -> Span {
+ self.span.clone()
+ }
+
+ pub fn reached_recursion_limit(&self) -> bool {
+ self.state.reached_recursion_limit
+ }
+
+ /// also dereference through raw pointer types
+ /// e.g., assuming ptr_to_Foo is the type `*const Foo`
+ /// fcx.autoderef(span, ptr_to_Foo) => [*const Foo]
+ /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo]
+ pub fn include_raw_pointers(mut self) -> Self {
+ self.include_raw_pointers = true;
+ self
+ }
+
+ pub fn silence_errors(mut self) -> Self {
+ self.silence_errors = true;
+ self
+ }
+}
+
+pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
+ // We've reached the recursion limit, error gracefully.
+ let suggested_limit = tcx.sess.recursion_limit() * 2;
+ let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty);
+ let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
+ let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
+ if fresh {
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0055,
+ "reached the recursion limit while auto-dereferencing `{:?}`",
+ ty
+ )
+ .span_label(span, "deref recursion limit reached")
+ .help(&format!(
+ "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
+ suggested_limit, tcx.crate_name,
+ ))
+ .emit();
+ }
+}
let ty = self.resolve_vars_if_possible(&ty);
if !(param_env, ty).needs_infer() {
- return ty.is_copy_modulo_regions(self.tcx, param_env, span);
+ return ty.is_copy_modulo_regions(self.tcx.at(span), param_env);
}
let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem, None);
#[macro_use]
extern crate rustc_middle;
+pub mod autoderef;
pub mod infer;
pub mod opaque_types;
pub mod traits;
)
.emit();
- self.tcx().types.err
+ self.tcx().ty_error()
}
}
}
)
.emit();
- self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: ct.ty })
+ self.tcx().const_error(ct.ty)
}
}
}
tcx,
ty_op: |ty| {
if ty.references_error() {
- return tcx.types.err;
+ return tcx.ty_error();
} else if let ty::Opaque(def_id, substs) = ty.kind {
// Check that this is `impl Trait` type is
// declared by `parent_def_id` -- i.e., one whose
ChalkEnvironmentAndGoal, ChalkEnvironmentClause, FulfillmentError, FulfillmentErrorCode,
ObligationCause, PredicateObligation, SelectionError, TraitEngine,
};
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, Ty, TyCtxt};
pub struct FulfillmentContext<'tcx> {
- obligations: FxHashSet<PredicateObligation<'tcx>>,
+ obligations: FxIndexSet<PredicateObligation<'tcx>>,
}
impl FulfillmentContext<'tcx> {
crate fn new() -> Self {
- FulfillmentContext { obligations: FxHashSet::default() }
+ FulfillmentContext { obligations: FxIndexSet::default() }
}
}
};
// FIXME(eddyb) isn't the unordered nature of this a hazard?
- let mut inputs = FxHashSet::default();
+ let mut inputs = FxIndexSet::default();
match node_kind {
// In a trait impl, we assume that the header trait ref and all its
NodeKind::TraitImpl => {
let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
- inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk()));
+ // FIXME(chalk): this has problems because of late-bound regions
+ //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk()));
+ inputs.extend(trait_ref.substs.iter());
}
// In an inherent impl, we assume that the receiver type and all its
let environment = match obligation.param_env.def_id {
Some(def_id) => environment(infcx.tcx, def_id),
None if obligation.param_env.caller_bounds.is_empty() => ty::List::empty(),
- _ => bug!("non-empty `ParamEnv` with no def-id"),
+ // FIXME(chalk): this is hit in ui/where-clauses/where-clause-constraints-are-local-for-trait-impl
+ // and ui/generics/generic-static-methods
+ //_ => bug!("non-empty `ParamEnv` with no def-id"),
+ _ => ty::List::empty(),
};
ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }
infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
let mut errors = Vec::new();
- let mut next_round = FxHashSet::default();
+ let mut next_round = FxIndexSet::default();
let mut making_progress;
loop {
// We iterate over all obligations, and record if we are able
// to unambiguously prove at least one obligation.
- for obligation in self.obligations.drain() {
+ for obligation in self.obligations.drain(..) {
let goal_in_environment = in_environment(infcx, &obligation);
let mut orig_values = OriginalQueryValues::default();
let canonical_goal =
debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id);
selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| {
- overlap_within_probe(selcx, a_def_id, b_def_id, snapshot)
+ overlap_within_probe(selcx, skip_leak_check, a_def_id, b_def_id, snapshot)
})
}
fn overlap_within_probe(
selcx: &mut SelectionContext<'cx, 'tcx>,
+ skip_leak_check: SkipLeakCheck,
a_def_id: DefId,
b_def_id: DefId,
snapshot: &CombinedSnapshot<'_, 'tcx>,
return None;
}
+ if !skip_leak_check.is_yes() {
+ if let Err(_) = infcx.leak_check(true, snapshot) {
+ debug!("overlap: leak check failed");
+ return None;
+ }
+ }
+
let impl_header = selcx.infcx().resolve_vars_if_possible(&a_impl_header);
let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
}
}
- ty::Error => None,
+ ty::Error(_) => None,
ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
bug!("ty_is_local invoked on unexpected type: {:?}", ty)
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::intravisit::Visitor;
use rustc_hir::Node;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::error::ExpectedFound;
TypeFoldable, WithConstness,
};
use rustc_session::DiagnosticMessageId;
-use rustc_span::{ExpnKind, Span, DUMMY_SP};
+use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP};
use std::fmt;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
err.span_label(enclosing_scope_span, s.as_str());
}
+ self.suggest_dereferences(&obligation, &mut err, &trait_ref, points_at_arg);
self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg);
self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
ty::Generator(..) => Some(18),
ty::Foreign(..) => Some(19),
ty::GeneratorWitness(..) => Some(20),
- ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => None,
+ ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
}
}
err: &mut DiagnosticBuilder<'tcx>,
obligation: &PredicateObligation<'tcx>,
) {
- if let (
- ty::PredicateKind::Trait(pred, _),
- ObligationCauseCode::BindingObligation(item_def_id, span),
- ) = (obligation.predicate.kind(), &obligation.cause.code)
- {
- if let (Some(generics), true) = (
- self.tcx.hir().get_if_local(*item_def_id).as_ref().and_then(|n| n.generics()),
- Some(pred.def_id()) == self.tcx.lang_items().sized_trait(),
- ) {
- for param in generics.params {
- if param.span == *span
- && !param.bounds.iter().any(|bound| {
- bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id())
- == self.tcx.lang_items().sized_trait()
- })
- {
- let (span, separator) = match param.bounds {
- [] => (span.shrink_to_hi(), ":"),
- [.., bound] => (bound.span().shrink_to_hi(), " +"),
- };
- err.span_suggestion_verbose(
- span,
- "consider relaxing the implicit `Sized` restriction",
- format!("{} ?Sized", separator),
- Applicability::MachineApplicable,
+ let (pred, item_def_id, span) =
+ match (obligation.predicate.kind(), &obligation.cause.code.peel_derives()) {
+ (
+ ty::PredicateKind::Trait(pred, _),
+ ObligationCauseCode::BindingObligation(item_def_id, span),
+ ) => (pred, item_def_id, span),
+ _ => return,
+ };
+
+ let node = match (
+ self.tcx.hir().get_if_local(*item_def_id),
+ Some(pred.def_id()) == self.tcx.lang_items().sized_trait(),
+ ) {
+ (Some(node), true) => node,
+ _ => return,
+ };
+ let generics = match node.generics() {
+ Some(generics) => generics,
+ None => return,
+ };
+ for param in generics.params {
+ if param.span != *span
+ || param.bounds.iter().any(|bound| {
+ bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id())
+ == self.tcx.lang_items().sized_trait()
+ })
+ {
+ continue;
+ }
+ match node {
+ hir::Node::Item(
+ item
+ @
+ hir::Item {
+ kind:
+ hir::ItemKind::Enum(..)
+ | hir::ItemKind::Struct(..)
+ | hir::ItemKind::Union(..),
+ ..
+ },
+ ) => {
+ // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
+ // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
+ // is not.
+ let mut visitor = FindTypeParam {
+ param: param.name.ident().name,
+ invalid_spans: vec![],
+ nested: false,
+ };
+ visitor.visit_item(item);
+ if !visitor.invalid_spans.is_empty() {
+ let mut multispan: MultiSpan = param.span.into();
+ multispan.push_span_label(
+ param.span,
+ format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
+ );
+ for sp in visitor.invalid_spans {
+ multispan.push_span_label(
+ sp,
+ format!(
+ "...if indirection was used here: `Box<{}>`",
+ param.name.ident(),
+ ),
+ );
+ }
+ err.span_help(
+ multispan,
+ &format!(
+ "you could relax the implicit `Sized` bound on `{T}` if it were \
+ used through indirection like `&{T}` or `Box<{T}>`",
+ T = param.name.ident(),
+ ),
);
return;
}
}
+ _ => {}
}
+ let (span, separator) = match param.bounds {
+ [] => (span.shrink_to_hi(), ":"),
+ [.., bound] => (bound.span().shrink_to_hi(), " +"),
+ };
+ err.span_suggestion_verbose(
+ span,
+ "consider relaxing the implicit `Sized` restriction",
+ format!("{} ?Sized", separator),
+ Applicability::MachineApplicable,
+ );
+ return;
}
}
}
}
+/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
+/// `param: ?Sized` would be a valid constraint.
+struct FindTypeParam {
+ param: rustc_span::Symbol,
+ invalid_spans: Vec<Span>,
+ nested: bool,
+}
+
+impl<'v> Visitor<'v> for FindTypeParam {
+ type Map = rustc_hir::intravisit::ErasedMap<'v>;
+
+ fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
+ hir::intravisit::NestedVisitorMap::None
+ }
+
+ fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
+ // We collect the spans of all uses of the "bare" type param, like in `field: T` or
+ // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
+ // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
+ // obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases
+ // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors
+ // in that case should make what happened clear enough.
+ match ty.kind {
+ hir::TyKind::Ptr(_) | hir::TyKind::Rptr(..) | hir::TyKind::TraitObject(..) => {}
+ hir::TyKind::Path(hir::QPath::Resolved(None, path))
+ if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
+ {
+ if !self.nested {
+ self.invalid_spans.push(ty.span);
+ }
+ }
+ hir::TyKind::Path(_) => {
+ let prev = self.nested;
+ self.nested = true;
+ hir::intravisit::walk_ty(self, ty);
+ self.nested = prev;
+ }
+ _ => {
+ hir::intravisit::walk_ty(self, ty);
+ }
+ }
+ }
+}
+
pub fn recursive_type_with_infinite_size_error(
tcx: TyCtxt<'tcx>,
type_def_id: DefId,
SelectionContext,
};
+use crate::autoderef::Autoderef;
use crate::infer::InferCtxt;
use crate::traits::normalize_projection_type;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items;
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
-use rustc_middle::ty::TypeckTables;
use rustc_middle::ty::{
self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty,
TyCtxt, TypeFoldable, WithConstness,
};
+use rustc_middle::ty::{TypeAndMut, TypeckTables};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use std::fmt;
err: &mut DiagnosticBuilder<'_>,
);
+ fn suggest_dereferences(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut DiagnosticBuilder<'tcx>,
+ trait_ref: &ty::PolyTraitRef<'tcx>,
+ points_at_arg: bool,
+ );
+
fn get_closure_name(
&self,
def_id: DefId,
}
}
+ /// When after several dereferencing, the reference satisfies the trait
+ /// binding. This function provides dereference suggestion for this
+ /// specific situation.
+ fn suggest_dereferences(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut DiagnosticBuilder<'tcx>,
+ trait_ref: &ty::PolyTraitRef<'tcx>,
+ points_at_arg: bool,
+ ) {
+ // It only make sense when suggesting dereferences for arguments
+ if !points_at_arg {
+ return;
+ }
+ let param_env = obligation.param_env;
+ let body_id = obligation.cause.body_id;
+ let span = obligation.cause.span;
+ let real_trait_ref = match &obligation.cause.code {
+ ObligationCauseCode::ImplDerivedObligation(cause)
+ | ObligationCauseCode::DerivedObligation(cause)
+ | ObligationCauseCode::BuiltinDerivedObligation(cause) => &cause.parent_trait_ref,
+ _ => trait_ref,
+ };
+ let real_ty = match real_trait_ref.self_ty().no_bound_vars() {
+ Some(ty) => ty,
+ None => return,
+ };
+
+ if let ty::Ref(region, base_ty, mutbl) = real_ty.kind {
+ let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty);
+ if let Some(steps) = autoderef.find_map(|(ty, steps)| {
+ // Re-add the `&`
+ let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
+ let obligation =
+ self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_ref, ty);
+ Some(steps).filter(|_| self.predicate_may_hold(&obligation))
+ }) {
+ if steps > 0 {
+ if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) {
+ // Don't care about `&mut` because `DerefMut` is used less
+ // often and user will not expect autoderef happens.
+ if src.starts_with("&") && !src.starts_with("&mut ") {
+ let derefs = "*".repeat(steps);
+ err.span_suggestion(
+ span,
+ "consider adding dereference here",
+ format!("&{}{}", derefs, &src[1..]),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+
/// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
/// suggestion to borrow the initializer in order to use have a slice instead.
fn suggest_borrow_on_unsized_slice(
ty| {
let ty = self.resolve_vars_if_possible(&ty);
same &=
- ty.kind != ty::Error
+ !matches!(ty.kind, ty::Error(_))
&& last_ty.map_or(true, |last_ty| {
// FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes
// *after* in the dependency graph.
/// Collect all the returned expressions within the input expression.
/// Used to point at the return spans when we want to suggest some change to them.
#[derive(Default)]
-struct ReturnsVisitor<'v> {
- returns: Vec<&'v hir::Expr<'v>>,
+pub struct ReturnsVisitor<'v> {
+ pub returns: Vec<&'v hir::Expr<'v>>,
in_block_tail: bool,
}
ty::PredicateKind::Trait(ref data, _) => {
let trait_obligation = obligation.with(*data);
- if data.is_global() {
+ if obligation.predicate.is_global() {
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
if infcx.predicate_must_hold_considering_regions(&obligation) {
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::ErrorReported;
use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::{FnOnceTraitLangItem, GeneratorTraitLangItem};
+use rustc_hir::lang_items::{FnOnceOutputLangItem, FnOnceTraitLangItem, GeneratorTraitLangItem};
+use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::sym;
use rustc_span::DUMMY_SP;
pub use rustc_middle::traits::Reveal;
debug!("poly_project_and_unify_type(obligation={:?})", obligation);
let infcx = selcx.infcx();
- infcx.commit_if_ok(|snapshot| {
- let (placeholder_predicate, placeholder_map) =
+ infcx.commit_if_ok(|_snapshot| {
+ let (placeholder_predicate, _) =
infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
let placeholder_obligation = obligation.with(placeholder_predicate);
let result = project_and_unify_type(selcx, &placeholder_obligation)?;
- infcx
- .leak_check(false, &placeholder_map, snapshot)
- .map_err(|err| MismatchedProjectionTypes { err })?;
Ok(result)
})
}
// handle normalization within binders because
// otherwise we wind up a need to normalize when doing
// trait matching (since you can have a trait
- // obligation like `for<'a> T::B : Fn(&'a int)`), but
+ // obligation like `for<'a> T::B: Fn(&'a i32)`), but
// we can't normalize with bound regions in scope. So
// far now we just ignore binders but only normalize
// if all bound regions are gone (and then we still
impl<'tcx> Progress<'tcx> {
fn error(tcx: TyCtxt<'tcx>) -> Self {
- Progress { ty: tcx.types.err, obligations: vec![] }
+ Progress { ty: tcx.ty_error(), obligations: vec![] }
}
fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self {
let tcx = selcx.tcx();
// Check whether the self-type is itself a projection.
- let (def_id, substs) = match obligation_trait_ref.self_ty().kind {
- ty::Projection(ref data) => (data.trait_ref(tcx).def_id, data.substs),
- ty::Opaque(def_id, substs) => (def_id, substs),
+ // If so, extract what we know from the trait and try to come up with a good answer.
+ let bounds = match obligation_trait_ref.self_ty().kind {
+ ty::Projection(ref data) => {
+ tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs)
+ }
+ ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs),
ty::Infer(ty::TyVar(_)) => {
// If the self-type is an inference variable, then it MAY wind up
// being a projected type, so induce an ambiguity.
_ => return,
};
- // If so, extract what we know from the trait and try to come up with a good answer.
- let trait_predicates = tcx.predicates_of(def_id);
- let bounds = trait_predicates.instantiate(tcx, substs);
- let bounds = elaborate_predicates(tcx, bounds.predicates.into_iter()).map(|o| o.predicate);
assemble_candidates_from_predicates(
selcx,
obligation,
obligation_trait_ref,
candidate_set,
ProjectionTyCandidate::TraitDef,
- bounds,
+ bounds.iter(),
)
}
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..)
- | ty::Error => false,
+ | ty::Error(_) => false,
}
}
super::ImplSourceParam(..) => {
) -> Progress<'tcx> {
debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation);
- match candidate {
+ let mut progress = match candidate {
ProjectionTyCandidate::ParamEnv(poly_projection)
| ProjectionTyCandidate::TraitDef(poly_projection) => {
confirm_param_env_candidate(selcx, obligation, poly_projection)
ProjectionTyCandidate::Select(impl_source) => {
confirm_select_candidate(selcx, obligation, obligation_trait_ref, impl_source)
}
+ };
+ // When checking for cycle during evaluation, we compare predicates with
+ // "syntactic" equality. Since normalization generally introduces a type
+ // with new region variables, we need to resolve them to existing variables
+ // when possible for this to work. See `auto-trait-projection-recursion.rs`
+ // for a case where this matters.
+ if progress.ty.has_infer_regions() {
+ progress.ty = OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty);
}
+ progress
}
fn confirm_select_candidate<'cx, 'tcx>(
debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig);
- // the `Output` associated type is declared on `FnOnce`
let fn_once_def_id = tcx.require_lang_item(FnOnceTraitLangItem, None);
+ let fn_once_output_def_id = tcx.require_lang_item(FnOnceOutputLangItem, None);
let predicate = super::util::closure_trait_ref_and_return_type(
tcx,
flag,
)
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy::from_ref_and_name(
- tcx,
- trait_ref,
- Ident::with_dummy_span(rustc_hir::FN_OUTPUT_NAME),
- ),
+ projection_ty: ty::ProjectionTy {
+ substs: trait_ref.substs,
+ item_def_id: fn_once_output_def_id,
+ },
ty: ret_type,
});
obligation, poly_cache_entry, e,
);
debug!("confirm_param_env_candidate: {}", msg);
- infcx.tcx.sess.delay_span_bug(obligation.cause.span, &msg);
- Progress { ty: infcx.tcx.types.err, obligations: vec![] }
+ let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg);
+ Progress { ty: err, obligations: vec![] }
}
}
}
let param_env = obligation.param_env;
let assoc_ty = match assoc_ty_def(selcx, impl_def_id, assoc_item_id) {
Ok(assoc_ty) => assoc_ty,
- Err(ErrorReported) => return Progress { ty: tcx.types.err, obligations: nested },
+ Err(ErrorReported) => return Progress { ty: tcx.ty_error(), obligations: nested },
};
if !assoc_ty.item.defaultness.has_value() {
"confirm_impl_candidate: no associated type {:?} for {:?}",
assoc_ty.item.ident, obligation.predicate
);
- return Progress { ty: tcx.types.err, obligations: nested };
+ return Progress { ty: tcx.ty_error(), obligations: nested };
}
+ // If we're trying to normalize `<Vec<u32> as X>::A<S>` using
+ //`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then:
+ //
+ // * `obligation.predicate.substs` is `[Vec<u32>, S]`
+ // * `substs` is `[u32]`
+ // * `substs` ends up as `[u32, S]`
let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs);
let substs =
translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node);
let ty = tcx.type_of(assoc_ty.item.def_id);
if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() {
- tcx.sess
- .delay_span_bug(DUMMY_SP, "impl item and trait item have different parameter counts");
- Progress { ty: tcx.types.err, obligations: nested }
+ let err = tcx.ty_error_with_message(
+ DUMMY_SP,
+ "impl item and trait item have different parameter counts",
+ );
+ Progress { ty: err, obligations: nested }
} else {
Progress { ty: ty.subst(tcx, substs), obligations: nested }
}
| ty::Ref(..)
| ty::Str
| ty::Foreign(..)
- | ty::Error => true,
+ | ty::Error(_) => true,
// [T; N] and [T] have same properties as T.
ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty),
// handle normalization within binders because
// otherwise we wind up a need to normalize when doing
// trait matching (since you can have a trait
- // obligation like `for<'a> T::B : Fn(&'a int)`), but
+ // obligation like `for<'a> T::B: Fn(&'a i32)`), but
// we can't normalize with bound regions in scope. So
// far now we just ignore binders but only normalize
// if all bound regions are gone (and then we still
_ => return,
}
- let result = self.infcx.probe(|snapshot| {
- self.match_projection_obligation_against_definition_bounds(obligation, snapshot)
- });
+ let result = self
+ .infcx
+ .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
if result {
candidates.vec.push(ProjectionCandidate);
obligation.predicate.def_id(),
obligation.predicate.skip_binder().trait_ref.self_ty(),
|impl_def_id| {
- self.infcx.probe(|snapshot| {
- if let Ok(_substs) = self.match_impl(impl_def_id, obligation, snapshot) {
+ self.infcx.probe(|_| {
+ if let Ok(_substs) = self.match_impl(impl_def_id, obligation) {
candidates.vec.push(ImplCandidate(impl_def_id));
}
});
}
fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
- self.infcx.commit_unconditionally(|snapshot| {
- let result =
- self.match_projection_obligation_against_definition_bounds(obligation, snapshot);
+ self.infcx.commit_unconditionally(|_| {
+ let result = self.match_projection_obligation_against_definition_bounds(obligation);
assert!(result);
})
}
// First, create the substitutions by matching the impl again,
// this time not in a probe.
- self.infcx.commit_unconditionally(|snapshot| {
- let substs = self.rematch_impl(impl_def_id, obligation, snapshot);
+ self.infcx.commit_unconditionally(|_| {
+ let substs = self.rematch_impl(impl_def_id, obligation);
debug!("confirm_impl_candidate: substs={:?}", substs);
let cause = obligation.derived_cause(ImplDerivedObligation);
ensure_sufficient_stack(|| {
///
/// Here is an example. Imagine we have a closure expression
/// and we desugared it so that the type of the expression is
- /// `Closure`, and `Closure` expects an int as argument. Then it
+ /// `Closure`, and `Closure` expects `i32` as argument. Then it
/// is "as if" the compiler generated this impl:
///
- /// impl Fn(int) for Closure { ... }
+ /// impl Fn(i32) for Closure { ... }
///
- /// Now imagine our obligation is `Fn(usize) for Closure`. So far
+ /// Now imagine our obligation is `Closure: Fn(usize)`. So far
/// we have matched the self type `Closure`. At this point we'll
- /// compare the `int` to `usize` and generate an error.
+ /// compare the `i32` to `usize` and generate an error.
///
/// Note that this checking occurs *after* the impl has selected,
/// because these output type parameters should not affect the
// Require that the traits involved in this upcast are **equal**;
// only the **lifetime bound** is changed.
- //
- // FIXME: This condition is arguably too strong -- it would
- // suffice for the source trait to be a *subtype* of the target
- // trait. In particular, changing from something like
- // `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be
- // permitted. And, indeed, in the in commit
- // 904a0bde93f0348f69914ee90b1f8b6e4e0d7cbc, this
- // condition was loosened. However, when the leak check was
- // added back, using subtype here actually guides the coercion
- // code in such a way that it accepts `old-lub-glb-object.rs`.
- // This is probably a good thing, but I've modified this to `.eq`
- // because I want to continue rejecting that test (as we have
- // done for quite some time) before we are firmly comfortable
- // with what our behavior should be there. -nikomatsakis
let InferOk { obligations, .. } = self
.infcx
.at(&obligation.cause, obligation.param_env)
- .eq(target, source_trait) // FIXME -- see below
+ .sup(target, source_trait)
.map_err(|_| Unimplemented)?;
nested.extend(obligations);
use super::{ObligationCause, PredicateObligation, TraitObligation};
use super::{Overflow, SelectionError, Unimplemented};
-use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
+use crate::infer::{InferCtxt, InferOk, TypeFreshener};
use crate::traits::error_reporting::InferCtxtExt;
use crate::traits::project::ProjectionCacheKeyExt;
use rustc_ast::attr;
) -> Result<EvaluationResult, OverflowError> {
self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
let result = op(self)?;
+
+ match self.infcx.leak_check(true, snapshot) {
+ Ok(()) => {}
+ Err(_) => return Ok(EvaluatedToErr),
+ }
+
match self.infcx.region_constraints_added_in_snapshot(snapshot) {
None => Ok(result),
Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)),
fn match_projection_obligation_against_definition_bounds(
&mut self,
obligation: &TraitObligation<'tcx>,
- snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> bool {
let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
- let (placeholder_trait_predicate, placeholder_map) =
+ let (placeholder_trait_predicate, _) =
self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
debug!(
"match_projection_obligation_against_definition_bounds: \
placeholder_trait_predicate,
);
- let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().kind {
- ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs),
- ty::Opaque(def_id, substs) => (def_id, substs),
+ let tcx = self.infcx.tcx;
+ let predicates = match placeholder_trait_predicate.trait_ref.self_ty().kind {
+ ty::Projection(ref data) => {
+ tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs)
+ }
+ ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs),
_ => {
span_bug!(
obligation.cause.span,
);
}
};
- debug!(
- "match_projection_obligation_against_definition_bounds: \
- def_id={:?}, substs={:?}",
- def_id, substs
- );
-
- let predicates_of = self.tcx().predicates_of(def_id);
- let bounds = predicates_of.instantiate(self.tcx(), substs);
- debug!(
- "match_projection_obligation_against_definition_bounds: \
- bounds={:?}",
- bounds
- );
- let elaborated_predicates =
- util::elaborate_predicates(self.tcx(), bounds.predicates.into_iter());
- let matching_bound = elaborated_predicates.filter_to_traits().find(|bound| {
- self.infcx.probe(|_| {
- self.match_projection(
- obligation,
- *bound,
- placeholder_trait_predicate.trait_ref,
- &placeholder_map,
- snapshot,
- )
- })
+ let matching_bound = predicates.iter().find_map(|bound| {
+ if let ty::PredicateKind::Trait(bound, _) = bound.kind() {
+ let bound = bound.to_poly_trait_ref();
+ if self.infcx.probe(|_| {
+ self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref)
+ }) {
+ return Some(bound);
+ }
+ }
+ None
});
debug!(
None => false,
Some(bound) => {
// Repeat the successful match, if any, this time outside of a probe.
- let result = self.match_projection(
- obligation,
- bound,
- placeholder_trait_predicate.trait_ref,
- &placeholder_map,
- snapshot,
- );
+ let result =
+ self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref);
assert!(result);
true
obligation: &TraitObligation<'tcx>,
trait_bound: ty::PolyTraitRef<'tcx>,
placeholder_trait_ref: ty::TraitRef<'tcx>,
- placeholder_map: &PlaceholderMap<'tcx>,
- snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> bool {
debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
self.infcx
.at(&obligation.cause, obligation.param_env)
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
.is_ok()
- && self.infcx.leak_check(false, placeholder_map, snapshot).is_ok()
}
fn evaluate_where_clause<'o>(
| ty::Array(..)
| ty::Closure(..)
| ty::Never
- | ty::Error => {
+ | ty::Error(_) => {
// safe for everything
Where(ty::Binder::dummy(Vec::new()))
}
| ty::Infer(ty::FloatVar(_))
| ty::FnDef(..)
| ty::FnPtr(_)
- | ty::Error => Where(ty::Binder::dummy(Vec::new())),
+ | ty::Error(_) => Where(ty::Binder::dummy(Vec::new())),
ty::Uint(_)
| ty::Int(_)
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::Str
- | ty::Error
+ | ty::Error(_)
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Never
| ty::Char => Vec::new(),
) -> Vec<PredicateObligation<'tcx>> {
// Because the types were potentially derived from
// higher-ranked obligations they may reference late-bound
- // regions. For example, `for<'a> Foo<&'a int> : Copy` would
- // yield a type like `for<'a> &'a int`. In general, we
+ // regions. For example, `for<'a> Foo<&'a i32> : Copy` would
+ // yield a type like `for<'a> &'a i32`. In general, we
// maintain the invariant that we never manipulate bound
// regions, so we have to process these bound regions somehow.
//
// The strategy is to:
//
// 1. Instantiate those regions to placeholder regions (e.g.,
- // `for<'a> &'a int` becomes `&0 int`.
- // 2. Produce something like `&'0 int : Copy`
- // 3. Re-bind the regions back to `for<'a> &'a int : Copy`
+ // `for<'a> &'a i32` becomes `&0 i32`.
+ // 2. Produce something like `&'0 i32 : Copy`
+ // 3. Re-bind the regions back to `for<'a> &'a i32 : Copy`
types
- .skip_binder()
+ .skip_binder() // binder moved -\
.iter()
.flat_map(|ty| {
- // binder moved -\
let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/
self.infcx.commit_unconditionally(|_| {
- let (skol_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty);
+ let (placeholder_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty);
let Normalized { value: normalized_ty, mut obligations } =
ensure_sufficient_stack(|| {
project::normalize_with_depth(
param_env,
cause.clone(),
recursion_depth,
- &skol_ty,
+ &placeholder_ty,
)
});
- let skol_obligation = predicate_for_trait_def(
+ let placeholder_obligation = predicate_for_trait_def(
self.tcx(),
param_env,
cause.clone(),
normalized_ty,
&[],
);
- obligations.push(skol_obligation);
+ obligations.push(placeholder_obligation);
obligations
})
})
&mut self,
impl_def_id: DefId,
obligation: &TraitObligation<'tcx>,
- snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> Normalized<'tcx, SubstsRef<'tcx>> {
- match self.match_impl(impl_def_id, obligation, snapshot) {
+ match self.match_impl(impl_def_id, obligation) {
Ok(substs) => substs,
Err(()) => {
bug!(
&mut self,
impl_def_id: DefId,
obligation: &TraitObligation<'tcx>,
- snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> {
let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
return Err(());
}
- let (skol_obligation, placeholder_map) =
+ let (placeholder_obligation, _) =
self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
- let skol_obligation_trait_ref = skol_obligation.trait_ref;
+ let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref;
let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
debug!(
"match_impl(impl_def_id={:?}, obligation={:?}, \
- impl_trait_ref={:?}, skol_obligation_trait_ref={:?})",
- impl_def_id, obligation, impl_trait_ref, skol_obligation_trait_ref
+ impl_trait_ref={:?}, placeholder_obligation_trait_ref={:?})",
+ impl_def_id, obligation, impl_trait_ref, placeholder_obligation_trait_ref
);
let InferOk { obligations, .. } = self
.infcx
.at(&obligation.cause, obligation.param_env)
- .eq(skol_obligation_trait_ref, impl_trait_ref)
+ .eq(placeholder_obligation_trait_ref, impl_trait_ref)
.map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
nested_obligations.extend(obligations);
- if let Err(e) = self.infcx.leak_check(false, &placeholder_map, snapshot) {
- debug!("match_impl: failed leak check due to `{}`", e);
- return Err(());
- }
-
if !self.intercrate
&& self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
{
// We determine whether there's a subset relationship by:
//
- // - skolemizing impl1,
+ // - replacing bound vars with placeholders in impl1,
// - assuming the where clauses for impl1,
// - instantiating impl2 with fresh inference variables,
// - unifying,
ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
bug!("unexpected type during structural-match checking: {:?}", ty);
}
- ty::Error => {
+ ty::Error(_) => {
self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check");
// We still want to check other types after encountering an error,
// as this may still emit relevant errors.
) -> usize {
// Count number of methods preceding the one we are selecting and
// add them to the total offset.
- // Skip over associated types and constants.
+ // Skip over associated types and constants, as those aren't stored in the vtable.
let mut entries = object.vtable_base;
for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()).in_definition_order() {
if trait_item.def_id == method_def_id {
));
}
}
- ty::ConstKind::Error
+ ty::ConstKind::Error(_)
| ty::ConstKind::Param(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(..) => {
| ty::Int(..)
| ty::Uint(..)
| ty::Float(..)
- | ty::Error
+ | ty::Error(_)
| ty::Str
| ty::GeneratorWitness(..)
| ty::Never
rustc_index = { path = "../librustc_index" }
rustc_ast = { path = "../librustc_ast" }
rustc_span = { path = "../librustc_span" }
-chalk-ir = "0.10.0"
-chalk-rust-ir = "0.10.0"
-chalk-solve = "0.10.0"
+chalk-ir = "0.14.0"
+chalk-solve = "0.14.0"
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
rustc_infer = { path = "../librustc_infer" }
rustc_trait_selection = { path = "../librustc_trait_selection" }
//! either the `TyCtxt` (for information about types) or
//! `crate::chalk::lowering` (to lower rustc types into Chalk types).
-use rustc_middle::traits::{ChalkRustDefId as RustDefId, ChalkRustInterner as RustInterner};
+use rustc_middle::traits::ChalkRustInterner as RustInterner;
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::{self, AssocItemContainer, AssocKind, TyCtxt};
fn associated_ty_data(
&self,
assoc_type_id: chalk_ir::AssocTypeId<RustInterner<'tcx>>,
- ) -> Arc<chalk_rust_ir::AssociatedTyDatum<RustInterner<'tcx>>> {
- let def_id = match assoc_type_id.0 {
- RustDefId::AssocTy(def_id) => def_id,
- _ => bug!("Did not use `AssocTy` variant when expecting associated type."),
- };
+ ) -> Arc<chalk_solve::rust_ir::AssociatedTyDatum<RustInterner<'tcx>>> {
+ let def_id = assoc_type_id.0;
let assoc_item = self.tcx.associated_item(def_id);
let trait_def_id = match assoc_item.container {
AssocItemContainer::TraitContainer(def_id) => def_id,
.map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
.filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
- Arc::new(chalk_rust_ir::AssociatedTyDatum {
- trait_id: chalk_ir::TraitId(RustDefId::Trait(trait_def_id)),
+ Arc::new(chalk_solve::rust_ir::AssociatedTyDatum {
+ trait_id: chalk_ir::TraitId(trait_def_id),
id: assoc_type_id,
name: (),
binders: chalk_ir::Binders::new(
binders,
- chalk_rust_ir::AssociatedTyDatumBound { bounds: vec![], where_clauses },
+ chalk_solve::rust_ir::AssociatedTyDatumBound { bounds: vec![], where_clauses },
),
})
}
fn trait_datum(
&self,
trait_id: chalk_ir::TraitId<RustInterner<'tcx>>,
- ) -> Arc<chalk_rust_ir::TraitDatum<RustInterner<'tcx>>> {
- let def_id = match trait_id.0 {
- RustDefId::Trait(def_id) => def_id,
- _ => bug!("Did not use `Trait` variant when expecting trait."),
- };
+ ) -> Arc<chalk_solve::rust_ir::TraitDatum<RustInterner<'tcx>>> {
+ let def_id = trait_id.0;
let trait_def = self.tcx.trait_def(def_id);
let bound_vars = bound_vars_for_item(self.tcx, def_id);
.iter()
.map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
.filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
+ let associated_ty_ids: Vec<_> = self
+ .tcx
+ .associated_items(def_id)
+ .in_definition_order()
+ .filter(|i| i.kind == AssocKind::Type)
+ .map(|i| chalk_ir::AssocTypeId(i.def_id))
+ .collect();
let well_known =
if self.tcx.lang_items().sized_trait().map(|t| def_id == t).unwrap_or(false) {
- Some(chalk_rust_ir::WellKnownTrait::SizedTrait)
+ Some(chalk_solve::rust_ir::WellKnownTrait::Sized)
} else if self.tcx.lang_items().copy_trait().map(|t| def_id == t).unwrap_or(false) {
- Some(chalk_rust_ir::WellKnownTrait::CopyTrait)
+ Some(chalk_solve::rust_ir::WellKnownTrait::Copy)
} else if self.tcx.lang_items().clone_trait().map(|t| def_id == t).unwrap_or(false) {
- Some(chalk_rust_ir::WellKnownTrait::CloneTrait)
+ Some(chalk_solve::rust_ir::WellKnownTrait::Clone)
+ } else if self.tcx.lang_items().drop_trait().map(|t| def_id == t).unwrap_or(false) {
+ Some(chalk_solve::rust_ir::WellKnownTrait::Drop)
+ } else if self.tcx.lang_items().fn_trait().map(|t| def_id == t).unwrap_or(false) {
+ Some(chalk_solve::rust_ir::WellKnownTrait::Fn)
+ } else if self.tcx.lang_items().fn_once_trait().map(|t| def_id == t).unwrap_or(false) {
+ Some(chalk_solve::rust_ir::WellKnownTrait::FnOnce)
+ } else if self.tcx.lang_items().fn_mut_trait().map(|t| def_id == t).unwrap_or(false) {
+ Some(chalk_solve::rust_ir::WellKnownTrait::FnMut)
} else {
None
};
- Arc::new(chalk_rust_ir::TraitDatum {
+ Arc::new(chalk_solve::rust_ir::TraitDatum {
id: trait_id,
binders: chalk_ir::Binders::new(
binders,
- chalk_rust_ir::TraitDatumBound { where_clauses },
+ chalk_solve::rust_ir::TraitDatumBound { where_clauses },
),
- flags: chalk_rust_ir::TraitFlags {
+ flags: chalk_solve::rust_ir::TraitFlags {
auto: trait_def.has_auto_impl,
marker: trait_def.is_marker,
upstream: !def_id.is_local(),
non_enumerable: true,
coinductive: false,
},
- associated_ty_ids: vec![],
+ associated_ty_ids,
well_known,
})
}
- fn struct_datum(
+ fn adt_datum(
&self,
- struct_id: chalk_ir::StructId<RustInterner<'tcx>>,
- ) -> Arc<chalk_rust_ir::StructDatum<RustInterner<'tcx>>> {
- match struct_id.0 {
- RustDefId::Adt(adt_def_id) => {
- let adt_def = self.tcx.adt_def(adt_def_id);
+ adt_id: chalk_ir::AdtId<RustInterner<'tcx>>,
+ ) -> Arc<chalk_solve::rust_ir::AdtDatum<RustInterner<'tcx>>> {
+ let adt_def = adt_id.0;
- let bound_vars = bound_vars_for_item(self.tcx, adt_def_id);
- let binders = binders_for(&self.interner, bound_vars);
+ let bound_vars = bound_vars_for_item(self.tcx, adt_def.did);
+ let binders = binders_for(&self.interner, bound_vars);
- let predicates = self.tcx.predicates_of(adt_def_id).predicates;
- let where_clauses: Vec<_> = predicates
+ let predicates = self.tcx.predicates_of(adt_def.did).predicates;
+ let where_clauses: Vec<_> = predicates
+ .into_iter()
+ .map(|(wc, _)| wc.subst(self.tcx, bound_vars))
+ .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner))
+ .collect();
+ let fields = match adt_def.adt_kind() {
+ ty::AdtKind::Struct | ty::AdtKind::Union => {
+ let variant = adt_def.non_enum_variant();
+ variant
+ .fields
.iter()
- .map(|(wc, _)| wc.subst(self.tcx, bound_vars))
- .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner))
- .collect();
- let fields = match adt_def.adt_kind() {
- ty::AdtKind::Struct | ty::AdtKind::Union => {
- let variant = adt_def.non_enum_variant();
- variant
- .fields
- .iter()
- .map(|field| {
- self.tcx
- .type_of(field.did)
- .subst(self.tcx, bound_vars)
- .lower_into(&self.interner)
- })
- .collect()
- }
- // FIXME(chalk): handle enums; force_impl_for requires this
- ty::AdtKind::Enum => vec![],
- };
- let struct_datum = Arc::new(chalk_rust_ir::StructDatum {
- id: struct_id,
- binders: chalk_ir::Binders::new(
- binders,
- chalk_rust_ir::StructDatumBound { fields, where_clauses },
- ),
- flags: chalk_rust_ir::StructFlags {
- upstream: !adt_def_id.is_local(),
- fundamental: adt_def.is_fundamental(),
- },
- });
- struct_datum
- }
- RustDefId::Ref(_) => Arc::new(chalk_rust_ir::StructDatum {
- id: struct_id,
- binders: chalk_ir::Binders::new(
- chalk_ir::ParameterKinds::from(
- &self.interner,
- vec![
- chalk_ir::ParameterKind::Lifetime(()),
- chalk_ir::ParameterKind::Ty(()),
- ],
- ),
- chalk_rust_ir::StructDatumBound { fields: vec![], where_clauses: vec![] },
- ),
- flags: chalk_rust_ir::StructFlags { upstream: false, fundamental: false },
- }),
- RustDefId::Array | RustDefId::Slice => Arc::new(chalk_rust_ir::StructDatum {
- id: struct_id,
- binders: chalk_ir::Binders::new(
- chalk_ir::ParameterKinds::from(
- &self.interner,
- Some(chalk_ir::ParameterKind::Ty(())),
- ),
- chalk_rust_ir::StructDatumBound { fields: vec![], where_clauses: vec![] },
- ),
- flags: chalk_rust_ir::StructFlags { upstream: false, fundamental: false },
- }),
- RustDefId::Str | RustDefId::Never | RustDefId::FnDef(_) => {
- Arc::new(chalk_rust_ir::StructDatum {
- id: struct_id,
- binders: chalk_ir::Binders::new(
- chalk_ir::ParameterKinds::new(&self.interner),
- chalk_rust_ir::StructDatumBound { fields: vec![], where_clauses: vec![] },
- ),
- flags: chalk_rust_ir::StructFlags { upstream: false, fundamental: false },
- })
+ .map(|field| {
+ self.tcx
+ .type_of(field.did)
+ .subst(self.tcx, bound_vars)
+ .lower_into(&self.interner)
+ })
+ .collect()
}
+ // FIXME(chalk): handle enums; force_impl_for requires this
+ ty::AdtKind::Enum => vec![],
+ };
+ let struct_datum = Arc::new(chalk_solve::rust_ir::AdtDatum {
+ id: adt_id,
+ binders: chalk_ir::Binders::new(
+ binders,
+ chalk_solve::rust_ir::AdtDatumBound { fields, where_clauses },
+ ),
+ flags: chalk_solve::rust_ir::AdtFlags {
+ upstream: !adt_def.did.is_local(),
+ fundamental: adt_def.is_fundamental(),
+ phantom_data: adt_def.is_phantom_data(),
+ },
+ });
+ return struct_datum;
+ }
- _ => bug!("Used not struct variant when expecting struct variant."),
- }
+ fn fn_def_datum(
+ &self,
+ fn_def_id: chalk_ir::FnDefId<RustInterner<'tcx>>,
+ ) -> Arc<chalk_solve::rust_ir::FnDefDatum<RustInterner<'tcx>>> {
+ let def_id = fn_def_id.0;
+ let bound_vars = bound_vars_for_item(self.tcx, def_id);
+ let binders = binders_for(&self.interner, bound_vars);
+
+ let predicates = self.tcx.predicates_defined_on(def_id).predicates;
+ let where_clauses: Vec<_> = predicates
+ .into_iter()
+ .map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
+ .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
+
+ let sig = self.tcx.fn_sig(def_id);
+ let inputs_and_output = sig.inputs_and_output();
+ let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars(
+ &self.interner,
+ self.tcx,
+ &inputs_and_output,
+ );
+
+ let argument_types = inputs_and_output[..inputs_and_output.len() - 1]
+ .iter()
+ .map(|t| t.subst(self.tcx, &bound_vars).lower_into(&self.interner))
+ .collect();
+
+ let return_type = inputs_and_output[inputs_and_output.len() - 1]
+ .subst(self.tcx, &bound_vars)
+ .lower_into(&self.interner);
+
+ let bound = chalk_solve::rust_ir::FnDefDatumBound {
+ inputs_and_output: chalk_ir::Binders::new(
+ iobinders,
+ chalk_solve::rust_ir::FnDefInputsAndOutputDatum { argument_types, return_type },
+ ),
+ where_clauses,
+ };
+ Arc::new(chalk_solve::rust_ir::FnDefDatum {
+ id: fn_def_id,
+ abi: sig.abi(),
+ binders: chalk_ir::Binders::new(binders, bound),
+ })
}
fn impl_datum(
&self,
impl_id: chalk_ir::ImplId<RustInterner<'tcx>>,
- ) -> Arc<chalk_rust_ir::ImplDatum<RustInterner<'tcx>>> {
- let def_id = match impl_id.0 {
- RustDefId::Impl(def_id) => def_id,
- _ => bug!("Did not use `Impl` variant when expecting impl."),
- };
+ ) -> Arc<chalk_solve::rust_ir::ImplDatum<RustInterner<'tcx>>> {
+ let def_id = impl_id.0;
let bound_vars = bound_vars_for_item(self.tcx, def_id);
let binders = binders_for(&self.interner, bound_vars);
.map(|(wc, _)| wc.subst(self.tcx, bound_vars))
.filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
- let value = chalk_rust_ir::ImplDatumBound {
+ let value = chalk_solve::rust_ir::ImplDatumBound {
trait_ref: trait_ref.lower_into(&self.interner),
where_clauses,
};
- Arc::new(chalk_rust_ir::ImplDatum {
- polarity: chalk_rust_ir::Polarity::Positive,
+ Arc::new(chalk_solve::rust_ir::ImplDatum {
+ polarity: chalk_solve::rust_ir::Polarity::Positive,
binders: chalk_ir::Binders::new(binders, value),
- impl_type: chalk_rust_ir::ImplType::Local,
+ impl_type: chalk_solve::rust_ir::ImplType::Local,
associated_ty_value_ids: vec![],
})
}
fn impls_for_trait(
&self,
trait_id: chalk_ir::TraitId<RustInterner<'tcx>>,
- parameters: &[chalk_ir::Parameter<RustInterner<'tcx>>],
+ parameters: &[chalk_ir::GenericArg<RustInterner<'tcx>>],
) -> Vec<chalk_ir::ImplId<RustInterner<'tcx>>> {
- let def_id: DefId = match trait_id.0 {
- RustDefId::Trait(def_id) => def_id,
- _ => bug!("Did not use `Trait` variant when expecting trait."),
- };
+ let def_id = trait_id.0;
// FIXME(chalk): use TraitDef::for_each_relevant_impl, but that will
// require us to be able to interconvert `Ty<'tcx>`, and we're
parameters[0].assert_ty_ref(&self.interner).could_match(&self.interner, &lowered_ty)
});
- let impls = matched_impls
- .map(|matched_impl| chalk_ir::ImplId(RustDefId::Impl(matched_impl)))
- .collect();
+ let impls = matched_impls.map(|matched_impl| chalk_ir::ImplId(matched_impl)).collect();
impls
}
fn impl_provided_for(
&self,
auto_trait_id: chalk_ir::TraitId<RustInterner<'tcx>>,
- struct_id: chalk_ir::StructId<RustInterner<'tcx>>,
+ adt_id: chalk_ir::AdtId<RustInterner<'tcx>>,
) -> bool {
- let trait_def_id: DefId = match auto_trait_id.0 {
- RustDefId::Trait(def_id) => def_id,
- _ => bug!("Did not use `Trait` variant when expecting trait."),
- };
- let adt_def_id: DefId = match struct_id.0 {
- RustDefId::Adt(def_id) => def_id,
- _ => bug!("Did not use `Adt` variant when expecting adt."),
- };
+ let trait_def_id = auto_trait_id.0;
+ let adt_def = adt_id.0;
let all_impls = self.tcx.all_impls(trait_def_id);
for impl_def_id in all_impls {
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
let self_ty = trait_ref.self_ty();
match self_ty.kind {
- ty::Adt(adt_def, _) => {
- if adt_def.did == adt_def_id {
+ ty::Adt(impl_adt_def, _) => {
+ if impl_adt_def == adt_def {
return true;
}
}
fn associated_ty_value(
&self,
- associated_ty_id: chalk_rust_ir::AssociatedTyValueId<RustInterner<'tcx>>,
- ) -> Arc<chalk_rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
- let def_id = match associated_ty_id.0 {
- RustDefId::AssocTy(def_id) => def_id,
- _ => bug!("Did not use `AssocTy` variant when expecting associated type."),
- };
+ associated_ty_id: chalk_solve::rust_ir::AssociatedTyValueId<RustInterner<'tcx>>,
+ ) -> Arc<chalk_solve::rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
+ let def_id = associated_ty_id.0;
let assoc_item = self.tcx.associated_item(def_id);
let impl_id = match assoc_item.container {
AssocItemContainer::TraitContainer(def_id) => def_id,
let binders = binders_for(&self.interner, bound_vars);
let ty = self.tcx.type_of(def_id);
- Arc::new(chalk_rust_ir::AssociatedTyValue {
- impl_id: chalk_ir::ImplId(RustDefId::Impl(impl_id)),
- associated_ty_id: chalk_ir::AssocTypeId(RustDefId::AssocTy(def_id)),
+ Arc::new(chalk_solve::rust_ir::AssociatedTyValue {
+ impl_id: chalk_ir::ImplId(impl_id),
+ associated_ty_id: chalk_ir::AssocTypeId(def_id),
value: chalk_ir::Binders::new(
binders,
- chalk_rust_ir::AssociatedTyValueBound { ty: ty.lower_into(&self.interner) },
+ chalk_solve::rust_ir::AssociatedTyValueBound { ty: ty.lower_into(&self.interner) },
),
})
}
fn opaque_ty_data(
&self,
- _id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>,
- ) -> Arc<chalk_rust_ir::OpaqueTyDatum<RustInterner<'tcx>>> {
- unimplemented!()
+ opaque_ty_id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>,
+ ) -> Arc<chalk_solve::rust_ir::OpaqueTyDatum<RustInterner<'tcx>>> {
+ let bound_vars = bound_vars_for_item(self.tcx, opaque_ty_id.0);
+ let binders = binders_for(&self.interner, bound_vars);
+ let predicates = self.tcx.predicates_defined_on(opaque_ty_id.0).predicates;
+ let where_clauses: Vec<_> = predicates
+ .iter()
+ .map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
+ .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
+
+ let value = chalk_solve::rust_ir::OpaqueTyDatumBound {
+ bounds: chalk_ir::Binders::new(binders, where_clauses),
+ };
+ Arc::new(chalk_solve::rust_ir::OpaqueTyDatum {
+ opaque_ty_id,
+ bound: chalk_ir::Binders::new(chalk_ir::VariableKinds::new(&self.interner), value),
+ })
}
/// Since Chalk can't handle all Rust types currently, we have to handle
/// `None` and eventually this function will be removed.
fn force_impl_for(
&self,
- well_known: chalk_rust_ir::WellKnownTrait,
+ well_known: chalk_solve::rust_ir::WellKnownTrait,
ty: &chalk_ir::TyData<RustInterner<'tcx>>,
) -> Option<bool> {
use chalk_ir::TyData::*;
match well_known {
- chalk_rust_ir::WellKnownTrait::SizedTrait => match ty {
+ chalk_solve::rust_ir::WellKnownTrait::Sized => match ty {
Apply(apply) => match apply.name {
- chalk_ir::TypeName::Struct(chalk_ir::StructId(rust_def_id)) => {
- use rustc_middle::traits::ChalkRustDefId::*;
- match rust_def_id {
- Never | Array | RawPtr | FnDef(_) | Ref(_) => Some(true),
-
- Adt(adt_def_id) => {
- let adt_def = self.tcx.adt_def(adt_def_id);
- match adt_def.adt_kind() {
- ty::AdtKind::Struct | ty::AdtKind::Union => None,
- ty::AdtKind::Enum => {
- let constraint = self.tcx.adt_sized_constraint(adt_def_id);
- if !constraint.0.is_empty() {
- unimplemented!()
- } else {
- Some(true)
- }
- }
- }
- }
-
- Str | Slice => Some(false),
-
- Trait(_) | Impl(_) | AssocTy(_) => panic!(),
+ chalk_ir::TypeName::Adt(chalk_ir::AdtId(adt_def)) => match adt_def.adt_kind() {
+ ty::AdtKind::Struct | ty::AdtKind::Union => None,
+ ty::AdtKind::Enum => {
+ let constraint = self.tcx.adt_sized_constraint(adt_def.did);
+ if constraint.0.len() > 0 { unimplemented!() } else { Some(true) }
}
- }
+ },
_ => None,
},
- Dyn(_) | Alias(_) | Placeholder(_) | Function(_) | InferenceVar(_)
+ Dyn(_)
+ | Alias(_)
+ | Placeholder(_)
+ | Function(_)
+ | InferenceVar(_, _)
| BoundVar(_) => None,
},
- chalk_rust_ir::WellKnownTrait::CopyTrait
- | chalk_rust_ir::WellKnownTrait::CloneTrait => match ty {
+ chalk_solve::rust_ir::WellKnownTrait::Copy
+ | chalk_solve::rust_ir::WellKnownTrait::Clone => match ty {
Apply(apply) => match apply.name {
- chalk_ir::TypeName::Struct(chalk_ir::StructId(rust_def_id)) => {
- use rustc_middle::traits::ChalkRustDefId::*;
- match rust_def_id {
- Never | RawPtr | Ref(_) | Str | Slice => Some(false),
- FnDef(_) | Array => Some(true),
- Adt(adt_def_id) => {
- let adt_def = self.tcx.adt_def(adt_def_id);
- match adt_def.adt_kind() {
- ty::AdtKind::Struct | ty::AdtKind::Union => None,
- ty::AdtKind::Enum => {
- let constraint = self.tcx.adt_sized_constraint(adt_def_id);
- if !constraint.0.is_empty() {
- unimplemented!()
- } else {
- Some(true)
- }
- }
- }
- }
- Trait(_) | Impl(_) | AssocTy(_) => panic!(),
+ chalk_ir::TypeName::Adt(chalk_ir::AdtId(adt_def)) => match adt_def.adt_kind() {
+ ty::AdtKind::Struct | ty::AdtKind::Union => None,
+ ty::AdtKind::Enum => {
+ let constraint = self.tcx.adt_sized_constraint(adt_def.did);
+ if constraint.0.len() > 0 { unimplemented!() } else { Some(true) }
}
- }
+ },
_ => None,
},
- Dyn(_) | Alias(_) | Placeholder(_) | Function(_) | InferenceVar(_)
+ Dyn(_)
+ | Alias(_)
+ | Placeholder(_)
+ | Function(_)
+ | InferenceVar(_, _)
| BoundVar(_) => None,
},
- chalk_rust_ir::WellKnownTrait::DropTrait => None,
+ chalk_solve::rust_ir::WellKnownTrait::Drop => None,
+ chalk_solve::rust_ir::WellKnownTrait::Fn => None,
+ chalk_solve::rust_ir::WellKnownTrait::FnMut => None,
+ chalk_solve::rust_ir::WellKnownTrait::FnOnce => None,
+ chalk_solve::rust_ir::WellKnownTrait::Unsize => None,
}
}
fn well_known_trait_id(
&self,
- well_known_trait: chalk_rust_ir::WellKnownTrait,
+ well_known_trait: chalk_solve::rust_ir::WellKnownTrait,
) -> Option<chalk_ir::TraitId<RustInterner<'tcx>>> {
- use chalk_rust_ir::WellKnownTrait::*;
- let t = match well_known_trait {
- SizedTrait => self
- .tcx
- .lang_items()
- .sized_trait()
- .map(|t| chalk_ir::TraitId(RustDefId::Trait(t)))
- .unwrap(),
- CopyTrait => self
- .tcx
- .lang_items()
- .copy_trait()
- .map(|t| chalk_ir::TraitId(RustDefId::Trait(t)))
- .unwrap(),
- CloneTrait => self
- .tcx
- .lang_items()
- .clone_trait()
- .map(|t| chalk_ir::TraitId(RustDefId::Trait(t)))
- .unwrap(),
- DropTrait => self
- .tcx
- .lang_items()
- .drop_trait()
- .map(|t| chalk_ir::TraitId(RustDefId::Trait(t)))
- .unwrap(),
+ use chalk_solve::rust_ir::WellKnownTrait::*;
+ let def_id = match well_known_trait {
+ Sized => self.tcx.lang_items().sized_trait(),
+ Copy => self.tcx.lang_items().copy_trait(),
+ Clone => self.tcx.lang_items().clone_trait(),
+ Drop => self.tcx.lang_items().drop_trait(),
+ Fn => self.tcx.lang_items().fn_trait(),
+ FnMut => self.tcx.lang_items().fn_mut_trait(),
+ FnOnce => self.tcx.lang_items().fn_once_trait(),
+ Unsize => self.tcx.lang_items().unsize_trait(),
};
- Some(t)
+ def_id.map(|t| chalk_ir::TraitId(t))
+ }
+
+ fn is_object_safe(&self, trait_id: chalk_ir::TraitId<RustInterner<'tcx>>) -> bool {
+ self.tcx.is_object_safe(trait_id.0)
+ }
+
+ fn hidden_opaque_type(
+ &self,
+ _id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>,
+ ) -> chalk_ir::Ty<RustInterner<'tcx>> {
+ // FIXME(chalk): actually get hidden ty
+ self.tcx.mk_ty(ty::Tuple(self.tcx.intern_substs(&[]))).lower_into(&self.interner)
+ }
+
+ fn closure_kind(
+ &self,
+ _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>,
+ substs: &chalk_ir::Substitution<RustInterner<'tcx>>,
+ ) -> chalk_solve::rust_ir::ClosureKind {
+ let kind = &substs.parameters(&self.interner)[substs.len(&self.interner) - 3];
+ match kind.assert_ty_ref(&self.interner).data(&self.interner) {
+ chalk_ir::TyData::Apply(apply) => match apply.name {
+ chalk_ir::TypeName::Scalar(scalar) => match scalar {
+ chalk_ir::Scalar::Int(int_ty) => match int_ty {
+ chalk_ir::IntTy::I8 => chalk_solve::rust_ir::ClosureKind::Fn,
+ chalk_ir::IntTy::I16 => chalk_solve::rust_ir::ClosureKind::FnMut,
+ chalk_ir::IntTy::I32 => chalk_solve::rust_ir::ClosureKind::FnOnce,
+ _ => bug!("bad closure kind"),
+ },
+ _ => bug!("bad closure kind"),
+ },
+ _ => bug!("bad closure kind"),
+ },
+ _ => bug!("bad closure kind"),
+ }
+ }
+
+ fn closure_inputs_and_output(
+ &self,
+ _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>,
+ substs: &chalk_ir::Substitution<RustInterner<'tcx>>,
+ ) -> chalk_ir::Binders<chalk_solve::rust_ir::FnDefInputsAndOutputDatum<RustInterner<'tcx>>>
+ {
+ let sig = &substs.parameters(&self.interner)[substs.len(&self.interner) - 2];
+ match sig.assert_ty_ref(&self.interner).data(&self.interner) {
+ chalk_ir::TyData::Function(f) => {
+ let substitution = f.substitution.parameters(&self.interner);
+ let return_type =
+ substitution.last().unwrap().assert_ty_ref(&self.interner).clone();
+ // Closure arguments are tupled
+ let argument_tuple = substitution[0].assert_ty_ref(&self.interner);
+ let argument_types = match argument_tuple.data(&self.interner) {
+ chalk_ir::TyData::Apply(apply) => match apply.name {
+ chalk_ir::TypeName::Tuple(_) => apply
+ .substitution
+ .iter(&self.interner)
+ .map(|arg| arg.assert_ty_ref(&self.interner))
+ .cloned()
+ .collect(),
+ _ => bug!("Expecting closure FnSig args to be tupled."),
+ },
+ _ => bug!("Expecting closure FnSig args to be tupled."),
+ };
+
+ chalk_ir::Binders::new(
+ chalk_ir::VariableKinds::from(
+ &self.interner,
+ (0..f.num_binders).map(|_| chalk_ir::VariableKind::Lifetime),
+ ),
+ chalk_solve::rust_ir::FnDefInputsAndOutputDatum { argument_types, return_type },
+ )
+ }
+ _ => panic!("Invalid sig."),
+ }
+ }
+
+ fn closure_upvars(
+ &self,
+ _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>,
+ substs: &chalk_ir::Substitution<RustInterner<'tcx>>,
+ ) -> chalk_ir::Binders<chalk_ir::Ty<RustInterner<'tcx>>> {
+ let inputs_and_output = self.closure_inputs_and_output(_closure_id, substs);
+ let tuple = substs.parameters(&self.interner).last().unwrap().assert_ty_ref(&self.interner);
+ inputs_and_output.map_ref(|_| tuple.clone())
+ }
+
+ fn closure_fn_substitution(
+ &self,
+ _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>,
+ substs: &chalk_ir::Substitution<RustInterner<'tcx>>,
+ ) -> chalk_ir::Substitution<RustInterner<'tcx>> {
+ let substitution = &substs.parameters(&self.interner)[0..substs.len(&self.interner) - 3];
+ chalk_ir::Substitution::from(&self.interner, substitution)
}
}
fn binders_for<'tcx>(
interner: &RustInterner<'tcx>,
bound_vars: SubstsRef<'tcx>,
-) -> chalk_ir::ParameterKinds<RustInterner<'tcx>> {
- chalk_ir::ParameterKinds::from(
+) -> chalk_ir::VariableKinds<RustInterner<'tcx>> {
+ chalk_ir::VariableKinds::from(
interner,
bound_vars.iter().map(|arg| match arg.unpack() {
- ty::subst::GenericArgKind::Lifetime(_re) => chalk_ir::ParameterKind::Lifetime(()),
- ty::subst::GenericArgKind::Type(_ty) => chalk_ir::ParameterKind::Ty(()),
- ty::subst::GenericArgKind::Const(_const) => chalk_ir::ParameterKind::Ty(()),
+ ty::subst::GenericArgKind::Lifetime(_re) => chalk_ir::VariableKind::Lifetime,
+ ty::subst::GenericArgKind::Type(_ty) => {
+ chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General)
+ }
+ ty::subst::GenericArgKind::Const(c) => {
+ chalk_ir::VariableKind::Const(c.ty.lower_into(interner))
+ }
}),
)
}
//! variables from the current `Binder`.
use rustc_middle::traits::{
- ChalkEnvironmentAndGoal, ChalkEnvironmentClause, ChalkRustDefId as RustDefId,
- ChalkRustInterner as RustInterner,
+ ChalkEnvironmentAndGoal, ChalkEnvironmentClause, ChalkRustInterner as RustInterner,
};
use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
use std::collections::btree_map::{BTreeMap, Entry};
+use chalk_ir::fold::shift::Shift;
+
/// Essentially an `Into` with a `&RustInterner` parameter
crate trait LowerInto<'tcx, T> {
/// Lower a rustc construct (e.g., `ty::TraitPredicate`) to a chalk type, consuming `self`.
impl<'tcx> LowerInto<'tcx, chalk_ir::AliasTy<RustInterner<'tcx>>> for ty::ProjectionTy<'tcx> {
fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::AliasTy<RustInterner<'tcx>> {
chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
- associated_ty_id: chalk_ir::AssocTypeId(RustDefId::AssocTy(self.item_def_id)),
+ associated_ty_id: chalk_ir::AssocTypeId(self.item_def_id),
substitution: self.substs.lower_into(interner),
})
}
collect_bound_vars(interner, interner.tcx, predicate);
Some(
- chalk_ir::ProgramClauseData::ForAll(chalk_ir::Binders::new(
+ chalk_ir::ProgramClauseData(chalk_ir::Binders::new(
binders,
chalk_ir::ProgramClauseImplication {
consequence: chalk_ir::DomainGoal::FromEnv(
.intern(interner),
)
}
- // FIXME(chalk): need to add RegionOutlives/TypeOutlives
- ty::PredicateKind::RegionOutlives(_) => None,
+ ty::PredicateKind::RegionOutlives(predicate) => {
+ let (predicate, binders, _named_regions) =
+ collect_bound_vars(interner, interner.tcx, predicate);
+
+ Some(
+ chalk_ir::ProgramClauseData(chalk_ir::Binders::new(
+ binders,
+ chalk_ir::ProgramClauseImplication {
+ consequence: chalk_ir::DomainGoal::Holds(
+ chalk_ir::WhereClause::LifetimeOutlives(
+ chalk_ir::LifetimeOutlives {
+ a: predicate.0.lower_into(interner),
+ b: predicate.1.lower_into(interner),
+ },
+ ),
+ ),
+ conditions: chalk_ir::Goals::new(interner),
+ priority: chalk_ir::ClausePriority::High,
+ },
+ ))
+ .intern(interner),
+ )
+ }
+ // FIXME(chalk): need to add TypeOutlives
ty::PredicateKind::TypeOutlives(_) => None,
ty::PredicateKind::Projection(predicate) => {
let (predicate, binders, _named_regions) =
collect_bound_vars(interner, interner.tcx, predicate);
Some(
- chalk_ir::ProgramClauseData::ForAll(chalk_ir::Binders::new(
+ chalk_ir::ProgramClauseData(chalk_ir::Binders::new(
binders,
chalk_ir::ProgramClauseImplication {
consequence: chalk_ir::DomainGoal::Holds(
}
}
ChalkEnvironmentClause::TypeFromEnv(ty) => Some(
- chalk_ir::ProgramClauseData::Implies(chalk_ir::ProgramClauseImplication {
- consequence: chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(
- ty.lower_into(interner),
- )),
- conditions: chalk_ir::Goals::new(interner),
- priority: chalk_ir::ClausePriority::High,
- })
+ chalk_ir::ProgramClauseData(chalk_ir::Binders::new(
+ chalk_ir::VariableKinds::new(interner),
+ chalk_ir::ProgramClauseImplication {
+ consequence: chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(
+ ty.lower_into(interner).shifted_in(interner),
+ )),
+ conditions: chalk_ir::Goals::new(interner),
+ priority: chalk_ir::ClausePriority::High,
+ },
+ ))
.intern(interner),
),
});
fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData<RustInterner<'tcx>> {
match self.kind() {
ty::PredicateKind::Trait(predicate, _) => predicate.lower_into(interner),
- // FIXME(chalk): we need to register constraints.
- ty::PredicateKind::RegionOutlives(_predicate) => {
- chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
+ ty::PredicateKind::RegionOutlives(predicate) => {
+ let (predicate, binders, _named_regions) =
+ collect_bound_vars(interner, interner.tcx, predicate);
+
+ chalk_ir::GoalData::Quantified(
+ chalk_ir::QuantifierKind::ForAll,
+ chalk_ir::Binders::new(
+ binders,
+ chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
+ chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
+ a: predicate.0.lower_into(interner),
+ b: predicate.1.lower_into(interner),
+ }),
+ ))
+ .intern(interner),
+ ),
+ )
}
+ // FIXME(chalk): TypeOutlives
ty::PredicateKind::TypeOutlives(_predicate) => {
chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
}
ty::PredicateKind::Projection(predicate) => predicate.lower_into(interner),
ty::PredicateKind::WellFormed(arg) => match arg.unpack() {
GenericArgKind::Type(ty) => match ty.kind {
- // These types are always WF.
- ty::Str | ty::Placeholder(..) | ty::Error | ty::Never => {
- chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
- }
-
- // FIXME(chalk): Well-formed only if ref lifetime outlives type
- ty::Ref(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)),
+ // FIXME(chalk): In Chalk, a placeholder is WellFormed if it
+ // `FromEnv`. However, when we "lower" Params, we don't update
+ // the environment.
+ ty::Placeholder(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)),
- ty::Param(..) => panic!("No Params expected."),
-
- // FIXME(chalk) -- ultimately I think this is what we
- // want to do, and we just have rules for how to prove
- // `WellFormed` for everything above, instead of
- // inlining a bit the rules of the proof here.
_ => chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed(
chalk_ir::WellFormed::Ty(ty.lower_into(interner)),
)),
GenericArgKind::Lifetime(lt) => bug!("unexpect well formed predicate: {:?}", lt),
},
+ ty::PredicateKind::ObjectSafe(t) => chalk_ir::GoalData::DomainGoal(
+ chalk_ir::DomainGoal::ObjectSafe(chalk_ir::TraitId(*t)),
+ ),
+
// FIXME(chalk): other predicates
//
// We can defer this, but ultimately we'll want to express
// some of these in terms of chalk operations.
- ty::PredicateKind::ObjectSafe(..)
- | ty::PredicateKind::ClosureKind(..)
+ ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => {
{
fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::TraitRef<RustInterner<'tcx>> {
chalk_ir::TraitRef {
- trait_id: chalk_ir::TraitId(RustDefId::Trait(self.def_id)),
+ trait_id: chalk_ir::TraitId(self.def_id),
substitution: self.substs.lower_into(interner),
}
}
use TyKind::*;
let empty = || chalk_ir::Substitution::empty(interner);
- let struct_ty = |def_id| chalk_ir::TypeName::Struct(chalk_ir::StructId(def_id));
+ let struct_ty =
+ |def_id| chalk_ir::TypeName::Adt(chalk_ir::AdtId(interner.tcx.adt_def(def_id)));
let apply = |name, substitution| {
TyData::Apply(chalk_ir::ApplicationTy { name, substitution }).intern(interner)
};
ast::FloatTy::F32 => float(chalk_ir::FloatTy::F32),
ast::FloatTy::F64 => float(chalk_ir::FloatTy::F64),
},
- Adt(def, substs) => {
- apply(struct_ty(RustDefId::Adt(def.did)), substs.lower_into(interner))
- }
+ Adt(def, substs) => apply(struct_ty(def.did), substs.lower_into(interner)),
Foreign(_def_id) => unimplemented!(),
- Str => apply(struct_ty(RustDefId::Str), empty()),
- Array(ty, _) => apply(
- struct_ty(RustDefId::Array),
- chalk_ir::Substitution::from1(
- interner,
- chalk_ir::ParameterKind::Ty(ty.lower_into(interner)).intern(interner),
- ),
- ),
+ Str => apply(chalk_ir::TypeName::Str, empty()),
+ Array(ty, len) => {
+ let value = match len.val {
+ ty::ConstKind::Value(val) => {
+ chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: val })
+ }
+ ty::ConstKind::Bound(db, bound) => {
+ chalk_ir::ConstValue::BoundVar(chalk_ir::BoundVar::new(
+ chalk_ir::DebruijnIndex::new(db.as_u32()),
+ bound.index(),
+ ))
+ }
+ _ => unimplemented!("Const not implemented. {:?}", len.val),
+ };
+ apply(
+ chalk_ir::TypeName::Array,
+ chalk_ir::Substitution::from(
+ interner,
+ &[
+ chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner),
+ chalk_ir::GenericArgData::Const(
+ chalk_ir::ConstData { ty: len.ty.lower_into(interner), value }
+ .intern(interner),
+ )
+ .intern(interner),
+ ],
+ ),
+ )
+ }
Slice(ty) => apply(
- struct_ty(RustDefId::Slice),
+ chalk_ir::TypeName::Slice,
chalk_ir::Substitution::from1(
interner,
- chalk_ir::ParameterKind::Ty(ty.lower_into(interner)).intern(interner),
+ chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner),
),
),
- RawPtr(_) => apply(struct_ty(RustDefId::RawPtr), empty()),
- Ref(region, ty, mutability) => apply(
- struct_ty(RustDefId::Ref(mutability)),
- chalk_ir::Substitution::from(
- interner,
- [
- chalk_ir::ParameterKind::Lifetime(region.lower_into(interner))
- .intern(interner),
- chalk_ir::ParameterKind::Ty(ty.lower_into(interner)).intern(interner),
- ]
- .iter(),
- ),
+ RawPtr(ptr) => {
+ let name = match ptr.mutbl {
+ ast::Mutability::Mut => chalk_ir::TypeName::Raw(chalk_ir::Mutability::Mut),
+ ast::Mutability::Not => chalk_ir::TypeName::Raw(chalk_ir::Mutability::Not),
+ };
+ apply(name, chalk_ir::Substitution::from1(interner, ptr.ty.lower_into(interner)))
+ }
+ Ref(region, ty, mutability) => {
+ let name = match mutability {
+ ast::Mutability::Mut => chalk_ir::TypeName::Ref(chalk_ir::Mutability::Mut),
+ ast::Mutability::Not => chalk_ir::TypeName::Ref(chalk_ir::Mutability::Not),
+ };
+ apply(
+ name,
+ chalk_ir::Substitution::from(
+ interner,
+ &[
+ chalk_ir::GenericArgData::Lifetime(region.lower_into(interner))
+ .intern(interner),
+ chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner),
+ ],
+ ),
+ )
+ }
+ FnDef(def_id, substs) => apply(
+ chalk_ir::TypeName::FnDef(chalk_ir::FnDefId(def_id)),
+ substs.lower_into(interner),
),
- FnDef(def_id, _) => apply(struct_ty(RustDefId::FnDef(def_id)), empty()),
FnPtr(sig) => {
let (inputs_and_outputs, binders, _named_regions) =
collect_bound_vars(interner, interner.tcx, &sig.inputs_and_output());
substitution: chalk_ir::Substitution::from(
interner,
inputs_and_outputs.iter().map(|ty| {
- chalk_ir::ParameterKind::Ty(ty.lower_into(interner)).intern(interner)
+ chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner)
}),
),
})
.intern(interner)
}
- Dynamic(_, _) => unimplemented!(),
- Closure(_def_id, _) => unimplemented!(),
+ Dynamic(predicates, region) => TyData::Dyn(chalk_ir::DynTy {
+ bounds: predicates.lower_into(interner),
+ lifetime: region.lower_into(interner),
+ })
+ .intern(interner),
+ Closure(def_id, substs) => apply(
+ chalk_ir::TypeName::Closure(chalk_ir::ClosureId(def_id)),
+ substs.lower_into(interner),
+ ),
Generator(_def_id, _substs, _) => unimplemented!(),
GeneratorWitness(_) => unimplemented!(),
- Never => apply(struct_ty(RustDefId::Never), empty()),
+ Never => apply(chalk_ir::TypeName::Never, empty()),
Tuple(substs) => {
apply(chalk_ir::TypeName::Tuple(substs.len()), substs.lower_into(interner))
}
Projection(proj) => TyData::Alias(proj.lower_into(interner)).intern(interner),
- Opaque(_def_id, _substs) => unimplemented!(),
+ Opaque(def_id, substs) => {
+ TyData::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
+ opaque_ty_id: chalk_ir::OpaqueTyId(def_id),
+ substitution: substs.lower_into(interner),
+ }))
+ .intern(interner)
+ }
// This should have been done eagerly prior to this, and all Params
// should have been substituted to placeholders
Param(_) => panic!("Lowering Param when not expected."),
})
.intern(interner),
Infer(_infer) => unimplemented!(),
- Error => unimplemented!(),
+ Error(_) => apply(chalk_ir::TypeName::Error, empty()),
}
}
}
ty::BrEnv => unimplemented!(),
},
ReFree(_) => unimplemented!(),
+ // FIXME(chalk): need to handle ReStatic
ReStatic => unimplemented!(),
ReVar(_) => unimplemented!(),
RePlaceholder(placeholder_region) => {
.intern(interner)
}
ReEmpty(_) => unimplemented!(),
+ // FIXME(chalk): need to handle ReErased
ReErased => unimplemented!(),
}
}
}
-impl<'tcx> LowerInto<'tcx, chalk_ir::Parameter<RustInterner<'tcx>>> for GenericArg<'tcx> {
- fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Parameter<RustInterner<'tcx>> {
+impl<'tcx> LowerInto<'tcx, chalk_ir::GenericArg<RustInterner<'tcx>>> for GenericArg<'tcx> {
+ fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GenericArg<RustInterner<'tcx>> {
match self.unpack() {
ty::subst::GenericArgKind::Type(ty) => {
- chalk_ir::ParameterKind::Ty(ty.lower_into(interner))
+ chalk_ir::GenericArgData::Ty(ty.lower_into(interner))
}
ty::subst::GenericArgKind::Lifetime(lifetime) => {
- chalk_ir::ParameterKind::Lifetime(lifetime.lower_into(interner))
+ chalk_ir::GenericArgData::Lifetime(lifetime.lower_into(interner))
}
- ty::subst::GenericArgKind::Const(_) => chalk_ir::ParameterKind::Ty(
+ ty::subst::GenericArgKind::Const(_) => chalk_ir::GenericArgData::Ty(
chalk_ir::TyData::Apply(chalk_ir::ApplicationTy {
name: chalk_ir::TypeName::Tuple(0),
substitution: chalk_ir::Substitution::empty(interner),
chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)),
))
}
- ty::PredicateKind::RegionOutlives(_predicate) => None,
+ ty::PredicateKind::RegionOutlives(predicate) => {
+ let (predicate, binders, _named_regions) =
+ collect_bound_vars(interner, interner.tcx, predicate);
+
+ Some(chalk_ir::Binders::new(
+ binders,
+ chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
+ a: predicate.0.lower_into(interner),
+ b: predicate.1.lower_into(interner),
+ }),
+ ))
+ }
ty::PredicateKind::TypeOutlives(_predicate) => None,
ty::PredicateKind::Projection(_predicate) => None,
ty::PredicateKind::WellFormed(_ty) => None,
}
}
+impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<RustInterner<'tcx>>>>
+ for Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>
+{
+ fn lower_into(
+ self,
+ interner: &RustInterner<'tcx>,
+ ) -> chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<RustInterner<'tcx>>> {
+ let (predicates, binders, _named_regions) =
+ collect_bound_vars(interner, interner.tcx, &self);
+ let where_clauses = predicates.into_iter().map(|predicate| match predicate {
+ ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => {
+ chalk_ir::Binders::new(
+ chalk_ir::VariableKinds::new(interner),
+ chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef {
+ trait_id: chalk_ir::TraitId(def_id),
+ substitution: substs.lower_into(interner),
+ }),
+ )
+ }
+ ty::ExistentialPredicate::Projection(_predicate) => unimplemented!(),
+ ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new(
+ chalk_ir::VariableKinds::new(interner),
+ chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef {
+ trait_id: chalk_ir::TraitId(def_id),
+ substitution: chalk_ir::Substitution::empty(interner),
+ }),
+ ),
+ });
+ let value = chalk_ir::QuantifiedWhereClauses::from(interner, where_clauses);
+ chalk_ir::Binders::new(binders, value)
+ }
+}
+
/// To collect bound vars, we have to do two passes. In the first pass, we
/// collect all `BoundRegion`s and `ty::Bound`s. In the second pass, we then
/// replace `BrNamed` into `BrAnon`. The two separate passes are important,
interner: &RustInterner<'tcx>,
tcx: TyCtxt<'tcx>,
ty: &'a Binder<T>,
-) -> (T, chalk_ir::ParameterKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) {
+) -> (T, chalk_ir::VariableKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) {
let mut bound_vars_collector = BoundVarsCollector::new();
ty.skip_binder().visit_with(&mut bound_vars_collector);
let mut parameters = bound_vars_collector.parameters;
let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor);
for var in named_parameters.values() {
- parameters.insert(*var, chalk_ir::ParameterKind::Lifetime(()));
+ parameters.insert(*var, chalk_ir::VariableKind::Lifetime);
}
(0..parameters.len()).for_each(|i| {
- parameters.get(&(i as u32)).expect("Skipped bound var index.");
+ parameters.get(&(i as u32)).expect(&format!("Skipped bound var index `{:?}`.", i));
});
- let binders = chalk_ir::ParameterKinds::from(interner, parameters.into_iter().map(|(_, v)| v));
+ let binders = chalk_ir::VariableKinds::from(interner, parameters.into_iter().map(|(_, v)| v));
(new_ty, binders, named_parameters)
}
-crate struct BoundVarsCollector {
+crate struct BoundVarsCollector<'tcx> {
binder_index: ty::DebruijnIndex,
- crate parameters: BTreeMap<u32, chalk_ir::ParameterKind<()>>,
+ crate parameters: BTreeMap<u32, chalk_ir::VariableKind<RustInterner<'tcx>>>,
crate named_parameters: Vec<DefId>,
}
-impl BoundVarsCollector {
+impl<'tcx> BoundVarsCollector<'tcx> {
crate fn new() -> Self {
BoundVarsCollector {
binder_index: ty::INNERMOST,
}
}
-impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector {
+impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
self.binder_index.shift_in(1);
let result = t.super_visit_with(self);
ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
match self.parameters.entry(bound_ty.var.as_u32()) {
Entry::Vacant(entry) => {
- entry.insert(chalk_ir::ParameterKind::Ty(()));
- }
- Entry::Occupied(entry) => {
- entry.get().assert_ty_ref();
+ entry.insert(chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General));
}
+ Entry::Occupied(entry) => match entry.get() {
+ chalk_ir::VariableKind::Ty(_) => {}
+ _ => panic!(),
+ },
}
}
ty::BoundRegion::BrAnon(var) => match self.parameters.entry(*var) {
Entry::Vacant(entry) => {
- entry.insert(chalk_ir::ParameterKind::Lifetime(()));
- }
- Entry::Occupied(entry) => {
- entry.get().assert_lifetime_ref();
+ entry.insert(chalk_ir::VariableKind::Lifetime);
}
+ Entry::Occupied(entry) => match entry.get() {
+ chalk_ir::VariableKind::Lifetime => {}
+ _ => panic!(),
+ },
},
ty::BrEnv => unimplemented!(),
use rustc_infer::infer::canonical::{
Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse,
};
-use rustc_infer::traits::{self, ChalkCanonicalGoal, ChalkRustDefId as RustDefId};
+use rustc_infer::traits::{self, ChalkCanonicalGoal};
use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase;
use crate::chalk::lowering::{LowerInto, ParamsSubstitutor};
CanonicalVarKind::PlaceholderTy(_ty) => unimplemented!(),
CanonicalVarKind::PlaceholderRegion(_ui) => unimplemented!(),
CanonicalVarKind::Ty(ty) => match ty {
- CanonicalTyVarKind::General(ui) => {
- chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex {
- counter: ui.index(),
- })
- }
- CanonicalTyVarKind::Int | CanonicalTyVarKind::Float => {
- // FIXME(chalk) - this is actually really important
- // These variable kinds put some limits on the
- // types that can be substituted (floats or ints).
- // While it's unclear exactly the design here, we
- // probably want some way to "register" these.
- chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::root())
- }
+ CanonicalTyVarKind::General(ui) => chalk_ir::WithKind::new(
+ chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General),
+ chalk_ir::UniverseIndex { counter: ui.index() },
+ ),
+ CanonicalTyVarKind::Int => chalk_ir::WithKind::new(
+ chalk_ir::VariableKind::Ty(chalk_ir::TyKind::Integer),
+ chalk_ir::UniverseIndex::root(),
+ ),
+ CanonicalTyVarKind::Float => chalk_ir::WithKind::new(
+ chalk_ir::VariableKind::Ty(chalk_ir::TyKind::Float),
+ chalk_ir::UniverseIndex::root(),
+ ),
},
- CanonicalVarKind::Region(ui) => {
- chalk_ir::ParameterKind::Lifetime(chalk_ir::UniverseIndex {
- counter: ui.index(),
- })
- }
+ CanonicalVarKind::Region(ui) => chalk_ir::WithKind::new(
+ chalk_ir::VariableKind::Lifetime,
+ chalk_ir::UniverseIndex { counter: ui.index() },
+ ),
CanonicalVarKind::Const(_ui) => unimplemented!(),
CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(),
}),
// essentially inverse of lowering a `GenericArg`.
let _data = p.data(&interner);
match _data {
- chalk_ir::ParameterKind::Ty(_t) => {
+ chalk_ir::GenericArgData::Ty(_t) => {
use chalk_ir::TyData;
use rustc_ast::ast;
let _data = _t.data(&interner);
let kind = match _data {
TyData::Apply(_application_ty) => match _application_ty.name {
- chalk_ir::TypeName::Struct(_struct_id) => match _struct_id.0 {
- RustDefId::Array => unimplemented!(),
- RustDefId::Slice => unimplemented!(),
- _ => unimplemented!(),
- },
+ chalk_ir::TypeName::Adt(_struct_id) => unimplemented!(),
chalk_ir::TypeName::Scalar(scalar) => match scalar {
chalk_ir::Scalar::Bool => ty::Bool,
chalk_ir::Scalar::Char => ty::Char,
chalk_ir::FloatTy::F64 => ty::Float(ast::FloatTy::F64),
},
},
+ chalk_ir::TypeName::Array => unimplemented!(),
+ chalk_ir::TypeName::FnDef(_) => unimplemented!(),
+ chalk_ir::TypeName::Closure(_) => unimplemented!(),
+ chalk_ir::TypeName::Never => unimplemented!(),
chalk_ir::TypeName::Tuple(_size) => unimplemented!(),
+ chalk_ir::TypeName::Slice => unimplemented!(),
+ chalk_ir::TypeName::Raw(_) => unimplemented!(),
+ chalk_ir::TypeName::Ref(_) => unimplemented!(),
+ chalk_ir::TypeName::Str => unimplemented!(),
chalk_ir::TypeName::OpaqueType(_ty) => unimplemented!(),
chalk_ir::TypeName::AssociatedType(_assoc_ty) => unimplemented!(),
chalk_ir::TypeName::Error => unimplemented!(),
kind: ty::BoundTyKind::Anon,
},
),
- TyData::InferenceVar(_) => unimplemented!(),
+ TyData::InferenceVar(_, _) => unimplemented!(),
TyData::Dyn(_) => unimplemented!(),
};
let _ty: Ty<'_> = tcx.mk_ty(kind);
let _arg: GenericArg<'_> = _ty.into();
var_values.push(_arg);
}
- chalk_ir::ParameterKind::Lifetime(_l) => {
+ chalk_ir::GenericArgData::Lifetime(_l) => {
let _data = _l.data(&interner);
let _lifetime: Region<'_> = match _data {
chalk_ir::LifetimeData::BoundVar(_var) => {
let _arg: GenericArg<'_> = _lifetime.into();
var_values.push(_arg);
}
+ chalk_ir::GenericArgData::Const(_) => unimplemented!(),
}
});
let sol = Canonical {
.map(|s| match s {
Solution::Unique(_subst) => {
// FIXME(chalk): handle constraints
- assert!(_subst.value.constraints.is_empty());
make_solution(_subst.value.subst)
}
Solution::Ambig(_guidance) => {
constraints.dtorck_types.push(ty);
}
- ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => {
+ ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => {
// By the time this code runs, all type variables ought to
// be fully resolved.
return Err(NoSolution);
for component in components {
match component.kind {
- _ if component.is_copy_modulo_regions(tcx, self.param_env, DUMMY_SP) => (),
+ _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (),
ty::Closure(_, substs) => {
for upvar_ty in substs.as_closure().upvar_tys() {
use rustc_data_structures::svh::Svh;
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use rustc_infer::traits::util;
use rustc_middle::hir::map as hir_map;
-use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::{InternalSubsts, Subst};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
use rustc_session::CrateDisambiguator;
use rustc_span::symbol::Symbol;
Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
| FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![],
- Str | Dynamic(..) | Slice(_) | Foreign(..) | Error | GeneratorWitness(..) => {
+ Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | GeneratorWitness(..) => {
// these are never sized - return the target type
vec![ty]
}
fn_like.asyncness()
}
+/// For associated types we allow bounds written on the associated type
+/// (`type X: Trait`) to be used as candidates. We also allow the same bounds
+/// when desugared as bounds on the trait `where Self::X: Trait`.
+///
+/// Note that this filtering is done with the items identity substs to
+/// simplify checking that these bounds are met in impls. This means that
+/// a bound such as `for<'b> <Self as X<'b>>::U: Clone` can't be used, as in
+/// `hr-associated-type-bound-1.rs`.
+fn associated_type_projection_predicates(
+ tcx: TyCtxt<'_>,
+ assoc_item_def_id: DefId,
+) -> &'_ ty::List<ty::Predicate<'_>> {
+ let generic_trait_bounds = tcx.predicates_of(assoc_item_def_id);
+ // We include predicates from the trait as well to handle
+ // `where Self::X: Trait`.
+ let item_bounds = generic_trait_bounds.instantiate_identity(tcx);
+ let item_predicates = util::elaborate_predicates(tcx, item_bounds.predicates.into_iter());
+
+ let assoc_item_ty = ty::ProjectionTy {
+ item_def_id: assoc_item_def_id,
+ substs: InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
+ };
+
+ let predicates = item_predicates.filter_map(|obligation| {
+ let pred = obligation.predicate;
+ match pred.kind() {
+ ty::PredicateKind::Trait(tr, _) => {
+ if let ty::Projection(p) = tr.skip_binder().self_ty().kind {
+ if p == assoc_item_ty {
+ return Some(pred);
+ }
+ }
+ }
+ ty::PredicateKind::Projection(proj) => {
+ if let ty::Projection(p) = proj.skip_binder().projection_ty.self_ty().kind {
+ if p == assoc_item_ty {
+ return Some(pred);
+ }
+ }
+ }
+ ty::PredicateKind::TypeOutlives(outlives) => {
+ if let ty::Projection(p) = outlives.skip_binder().0.kind {
+ if p == assoc_item_ty {
+ return Some(pred);
+ }
+ }
+ }
+ _ => {}
+ }
+ None
+ });
+
+ let result = tcx.mk_predicates(predicates);
+ debug!(
+ "associated_type_projection_predicates({}) = {:?}",
+ tcx.def_path_str(assoc_item_def_id),
+ result
+ );
+ result
+}
+
+/// Opaque types don't have the same issues as associated types: the only
+/// predicates on an opaque type (excluding those it inherits from its parent
+/// item) should be of the form we're expecting.
+fn opaque_type_projection_predicates(
+ tcx: TyCtxt<'_>,
+ def_id: DefId,
+) -> &'_ ty::List<ty::Predicate<'_>> {
+ let substs = InternalSubsts::identity_for_item(tcx, def_id);
+
+ let bounds = tcx.predicates_of(def_id);
+ let predicates =
+ util::elaborate_predicates(tcx, bounds.predicates.into_iter().map(|&(pred, _)| pred));
+
+ let filtered_predicates = predicates.filter_map(|obligation| {
+ let pred = obligation.predicate;
+ match pred.kind() {
+ ty::PredicateKind::Trait(tr, _) => {
+ if let ty::Opaque(opaque_def_id, opaque_substs) = tr.skip_binder().self_ty().kind {
+ if opaque_def_id == def_id && opaque_substs == substs {
+ return Some(pred);
+ }
+ }
+ }
+ ty::PredicateKind::Projection(proj) => {
+ if let ty::Opaque(opaque_def_id, opaque_substs) =
+ proj.skip_binder().projection_ty.self_ty().kind
+ {
+ if opaque_def_id == def_id && opaque_substs == substs {
+ return Some(pred);
+ }
+ }
+ }
+ ty::PredicateKind::TypeOutlives(outlives) => {
+ if let ty::Opaque(opaque_def_id, opaque_substs) = outlives.skip_binder().0.kind {
+ if opaque_def_id == def_id && opaque_substs == substs {
+ return Some(pred);
+ }
+ } else {
+ // These can come from elaborating other predicates
+ return None;
+ }
+ }
+ // These can come from elaborating other predicates
+ ty::PredicateKind::RegionOutlives(_) => return None,
+ _ => {}
+ }
+ tcx.sess.delay_span_bug(
+ obligation.cause.span(tcx),
+ &format!("unexpected predicate {:?} on opaque type", pred),
+ );
+ None
+ });
+
+ let result = tcx.mk_predicates(filtered_predicates);
+ debug!("opaque_type_projection_predicates({}) = {:?}", tcx.def_path_str(def_id), result);
+ result
+}
+
+fn projection_predicates(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List<ty::Predicate<'_>> {
+ match tcx.def_kind(def_id) {
+ DefKind::AssocTy => associated_type_projection_predicates(tcx, def_id),
+ DefKind::OpaqueTy => opaque_type_projection_predicates(tcx, def_id),
+ k => bug!("projection_predicates called on {}", k.descr(def_id)),
+ }
+}
+
pub fn provide(providers: &mut ty::query::Providers<'_>) {
*providers = ty::query::Providers {
asyncness,
instance_def_size_estimate,
issue33140_self_ty,
impl_defaultness,
+ projection_predicates,
..*providers
};
}
use crate::collect::PlaceholderHirTyCollector;
use crate::middle::resolve_lifetime as rl;
use crate::require_c_abi_if_c_variadic;
-use rustc_ast::ast::ParamKindOrd;
-use rustc_ast::util::lev_distance::find_best_match_for_name;
+use rustc_ast::{ast::ParamKindOrd, util::lev_distance::find_best_match_for_name};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::ErrorReported;
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, FatalError};
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, LATE_BOUND_LIFETIME_ARGUMENTS};
use rustc_session::parse::feature_err;
use rustc_session::Session;
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use rustc_target::spec::abi;
use rustc_trait_selection::traits;
/// Report an error that a generic argument did not match the generic parameter that was
/// expected.
- fn generic_arg_mismatch_err(sess: &Session, arg: &GenericArg<'_>, kind: &'static str) {
+ fn generic_arg_mismatch_err(
+ sess: &Session,
+ arg: &GenericArg<'_>,
+ kind: &'static str,
+ help: Option<&str>,
+ ) {
let mut err = struct_span_err!(
sess,
arg.span(),
let (first, last) =
if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
err.note(&format!("{} arguments must be provided before {} arguments", first, last));
+
+ if let Some(help) = help {
+ err.help(help);
+ }
err.emit();
}
if arg_count.correct.is_ok()
&& arg_count.explicit_late_bound == ExplicitLateBound::No
{
- Self::generic_arg_mismatch_err(tcx.sess, arg, kind.descr());
+ // We're going to iterate over the parameters to sort them out, and
+ // show that order to the user as a possible order for the parameters
+ let mut param_types_present = defs
+ .params
+ .clone()
+ .into_iter()
+ .map(|param| {
+ (
+ match param.kind {
+ GenericParamDefKind::Lifetime => {
+ ParamKindOrd::Lifetime
+ }
+ GenericParamDefKind::Type { .. } => {
+ ParamKindOrd::Type
+ }
+ GenericParamDefKind::Const => {
+ ParamKindOrd::Const
+ }
+ },
+ param,
+ )
+ })
+ .collect::<Vec<(ParamKindOrd, GenericParamDef)>>();
+ param_types_present.sort_by_key(|(ord, _)| *ord);
+ let (mut param_types_present, ordered_params): (
+ Vec<ParamKindOrd>,
+ Vec<GenericParamDef>,
+ ) = param_types_present.into_iter().unzip();
+ param_types_present.dedup();
+
+ Self::generic_arg_mismatch_err(
+ tcx.sess,
+ arg,
+ kind.descr(),
+ Some(&format!(
+ "reorder the arguments: {}: `<{}>`",
+ param_types_present
+ .into_iter()
+ .map(|ord| format!("{}s", ord.to_string()))
+ .collect::<Vec<String>>()
+ .join(", then "),
+ ordered_params
+ .into_iter()
+ .filter_map(|param| {
+ if param.name == kw::SelfUpper {
+ None
+ } else {
+ Some(param.name.to_string())
+ }
+ })
+ .collect::<Vec<String>>()
+ .join(", ")
+ )),
+ );
}
// We've reported the error, but we want to make sure that this
assert_eq!(kind, "lifetime");
let provided =
force_infer_lt.expect("lifetimes ought to have been inferred");
- Self::generic_arg_mismatch_err(tcx.sess, provided, kind);
+ Self::generic_arg_mismatch_err(tcx.sess, provided, kind, None);
}
break;
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) {
inferred_params.push(ty.span);
- tcx.types.err.into()
+ tcx.ty_error().into()
} else {
self.ast_ty_to_ty(&ty).into()
}
// careful!
if default_needs_object_self(param) {
missing_type_params.push(param.name.to_string());
- tcx.types.err.into()
+ tcx.ty_error().into()
} else {
// This is a default type parameter.
self.normalize_ty(
self.ty_infer(param, span).into()
} else {
// We've already errored above about the mismatch.
- tcx.types.err.into()
+ tcx.ty_error().into()
}
}
GenericParamDefKind::Const => {
self.ct_infer(ty, Some(param), span).into()
} else {
// We've already errored above about the mismatch.
- tcx.mk_const(ty::Const { val: ty::ConstKind::Error, ty }).into()
+ tcx.const_error(ty).into()
}
}
}
// That is, consider this case:
//
// ```
- // trait SubTrait: SuperTrait<int> { }
+ // trait SubTrait: SuperTrait<i32> { }
// trait SuperTrait<A> { type T; }
//
// ... B: SubTrait<T = foo> ...
// ```
//
- // We want to produce `<B as SuperTrait<int>>::T == foo`.
+ // We want to produce `<B as SuperTrait<i32>>::T == foo`.
// Find any late-bound regions declared in `ty` that are not
// declared in the trait-ref. These are not well-formed.
"at least one trait is required for an object type"
)
.emit();
- return tcx.types.err;
+ return tcx.ty_error();
}
// Check that there are no gross object safety violations;
&object_safety_violations[..],
)
.emit();
- return tcx.types.err;
+ return tcx.ty_error();
}
}
&path_str,
item_segment.ident.name,
);
- return tcx.types.err;
+ return tcx.ty_error();
};
debug!("qpath_to_ty: self_type={:?}", self_ty);
hir::PrimTy::Int(it) => tcx.mk_mach_int(it),
hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(uit),
hir::PrimTy::Float(ft) => tcx.mk_mach_float(ft),
- hir::PrimTy::Str => tcx.mk_str(),
+ hir::PrimTy::Str => tcx.types.str_,
}
}
Res::Err => {
self.set_tainted_by_errors();
- self.tcx().types.err
+ self.tcx().ty_error()
}
_ => span_bug!(span, "unexpected resolution: {:?}", path.res),
}
};
self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, res, segment, false)
.map(|(ty, _, _)| ty)
- .unwrap_or(tcx.types.err)
+ .unwrap_or_else(|_| tcx.ty_error())
}
hir::TyKind::Array(ref ty, ref length) => {
let length_def_id = tcx.hir().local_def_id(length.hir_id);
.span_label(ast_ty.span, "reserved keyword")
.emit();
- tcx.types.err
+ tcx.ty_error()
}
hir::TyKind::Infer => {
// Infer also appears as the type of arguments or return
// handled specially and will not descend into this routine.
self.ty_infer(None, ast_ty.span)
}
- hir::TyKind::Err => tcx.types.err,
+ hir::TyKind::Err => tcx.ty_error(),
};
debug!("ast_ty_to_ty: result_ty={:?}", result_ty);
&& i != 0
&& self.if_fallback_coercion(expr.span, &arms[0].body, &mut coercion)
{
- tcx.types.err
+ tcx.ty_error()
} else {
// Only call this if this is not an `if` expr with an expected type and no `else`
// clause to avoid duplicated type errors. (#60254)
+//! Some helper functions for `AutoDeref`
use super::method::MethodCallee;
-use super::{FnCtxt, Needs, PlaceOp};
+use super::{FnCtxt, PlaceOp};
-use rustc_errors::struct_span_err;
-use rustc_hir as hir;
-use rustc_infer::infer::{InferCtxt, InferOk};
+use rustc_infer::infer::InferOk;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
-use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
-use rustc_middle::ty::{ToPredicate, TypeFoldable};
-use rustc_session::DiagnosticMessageId;
-use rustc_span::symbol::Ident;
+use rustc_middle::ty::{self, Ty};
use rustc_span::Span;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-use rustc_trait_selection::traits::{self, TraitEngine};
+use rustc_trait_selection::autoderef::{Autoderef, AutoderefKind};
use std::iter;
-#[derive(Copy, Clone, Debug)]
-enum AutoderefKind {
- Builtin,
- Overloaded,
-}
-
-pub struct Autoderef<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
- body_id: hir::HirId,
- param_env: ty::ParamEnv<'tcx>,
- steps: Vec<(Ty<'tcx>, AutoderefKind)>,
- cur_ty: Ty<'tcx>,
- obligations: Vec<traits::PredicateObligation<'tcx>>,
- at_start: bool,
- include_raw_pointers: bool,
- span: Span,
- silence_errors: bool,
- reached_recursion_limit: bool,
-}
-
-impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
- type Item = (Ty<'tcx>, usize);
-
- fn next(&mut self) -> Option<Self::Item> {
- let tcx = self.infcx.tcx;
-
- debug!("autoderef: steps={:?}, cur_ty={:?}", self.steps, self.cur_ty);
- if self.at_start {
- self.at_start = false;
- debug!("autoderef stage #0 is {:?}", self.cur_ty);
- return Some((self.cur_ty, 0));
- }
-
- if !tcx.sess.recursion_limit().value_within_limit(self.steps.len()) {
- if !self.silence_errors {
- report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty);
- }
- self.reached_recursion_limit = true;
- return None;
- }
-
- if self.cur_ty.is_ty_var() {
- return None;
- }
-
- // Otherwise, deref if type is derefable:
- let (kind, new_ty) = if let Some(mt) = self.cur_ty.builtin_deref(self.include_raw_pointers)
- {
- (AutoderefKind::Builtin, mt.ty)
- } else {
- let ty = self.overloaded_deref_ty(self.cur_ty)?;
- (AutoderefKind::Overloaded, ty)
- };
-
- if new_ty.references_error() {
- return None;
- }
-
- self.steps.push((self.cur_ty, kind));
- debug!(
- "autoderef stage #{:?} is {:?} from {:?}",
- self.steps.len(),
- new_ty,
- (self.cur_ty, kind)
- );
- self.cur_ty = new_ty;
-
- Some((self.cur_ty, self.steps.len()))
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+ pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
+ Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
}
-}
-impl<'a, 'tcx> Autoderef<'a, 'tcx> {
- pub fn new(
- infcx: &'a InferCtxt<'a, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- body_id: hir::HirId,
+ pub fn try_overloaded_deref(
+ &self,
span: Span,
base_ty: Ty<'tcx>,
- ) -> Autoderef<'a, 'tcx> {
- Autoderef {
- infcx,
- body_id,
- param_env,
- steps: vec![],
- cur_ty: infcx.resolve_vars_if_possible(&base_ty),
- obligations: vec![],
- at_start: true,
- include_raw_pointers: false,
- silence_errors: false,
- reached_recursion_limit: false,
- span,
- }
- }
-
- fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
- debug!("overloaded_deref_ty({:?})", ty);
-
- let tcx = self.infcx.tcx;
-
- // <ty as Deref>
- let trait_ref = TraitRef {
- def_id: tcx.lang_items().deref_trait()?,
- substs: tcx.mk_substs_trait(ty, &[]),
- };
-
- let cause = traits::ObligationCause::misc(self.span, self.body_id);
-
- let obligation = traits::Obligation::new(
- cause.clone(),
- self.param_env,
- trait_ref.without_const().to_predicate(tcx),
- );
- if !self.infcx.predicate_may_hold(&obligation) {
- debug!("overloaded_deref_ty: cannot match obligation");
- return None;
- }
-
- let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
- let normalized_ty = fulfillcx.normalize_projection_type(
- &self.infcx,
- self.param_env,
- ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, Ident::from_str("Target")),
- cause,
- );
- if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
- // This shouldn't happen, except for evaluate/fulfill mismatches,
- // but that's not a reason for an ICE (`predicate_may_hold` is conservative
- // by design).
- debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e);
- return None;
- }
- let obligations = fulfillcx.pending_obligations();
- debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
- self.obligations.extend(obligations);
-
- Some(self.infcx.resolve_vars_if_possible(&normalized_ty))
- }
-
- /// Returns the final type, generating an error if it is an
- /// unresolved inference variable.
- pub fn unambiguous_final_ty(&self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> {
- fcx.structurally_resolved_type(self.span, self.cur_ty)
- }
-
- /// Returns the final type we ended up with, which may well be an
- /// inference variable (we will resolve it first, if possible).
- pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> {
- self.infcx.resolve_vars_if_possible(&self.cur_ty)
- }
-
- pub fn step_count(&self) -> usize {
- self.steps.len()
+ ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
+ self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref)
}
/// Returns the adjustment steps.
- pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'tcx>, needs: Needs) -> Vec<Adjustment<'tcx>> {
- fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx, needs))
+ pub fn adjust_steps(&self, autoderef: &Autoderef<'a, 'tcx>) -> Vec<Adjustment<'tcx>> {
+ self.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(autoderef))
}
pub fn adjust_steps_as_infer_ok(
&self,
- fcx: &FnCtxt<'a, 'tcx>,
- needs: Needs,
+ autoderef: &Autoderef<'a, 'tcx>,
) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
let mut obligations = vec![];
- let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(self.cur_ty));
- let steps: Vec<_> = self
- .steps
+ let steps = autoderef.steps();
+ let targets =
+ steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(autoderef.final_ty(false)));
+ let steps: Vec<_> = steps
.iter()
.map(|&(source, kind)| {
if let AutoderefKind::Overloaded = kind {
- fcx.try_overloaded_deref(self.span, source, needs).and_then(
+ self.try_overloaded_deref(autoderef.span(), source).and_then(
|InferOk { value: method, obligations: o }| {
obligations.extend(o);
if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
InferOk { obligations, value: steps }
}
-
- /// also dereference through raw pointer types
- /// e.g., assuming ptr_to_Foo is the type `*const Foo`
- /// fcx.autoderef(span, ptr_to_Foo) => [*const Foo]
- /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo]
- pub fn include_raw_pointers(mut self) -> Self {
- self.include_raw_pointers = true;
- self
- }
-
- pub fn silence_errors(mut self) -> Self {
- self.silence_errors = true;
- self
- }
-
- pub fn reached_recursion_limit(&self) -> bool {
- self.reached_recursion_limit
- }
-
- pub fn finalize(self, fcx: &FnCtxt<'a, 'tcx>) {
- fcx.register_predicates(self.into_obligations());
- }
-
- pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
- self.obligations
- }
-}
-
-pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
- // We've reached the recursion limit, error gracefully.
- let suggested_limit = tcx.sess.recursion_limit() * 2;
- let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty);
- let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
- let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
- if fresh {
- struct_span_err!(
- tcx.sess,
- span,
- E0055,
- "reached the recursion limit while auto-dereferencing `{:?}`",
- ty
- )
- .span_label(span, "deref recursion limit reached")
- .help(&format!(
- "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
- suggested_limit, tcx.crate_name,
- ))
- .emit();
- }
-}
-
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
- pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
- Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
- }
-
- pub fn try_overloaded_deref(
- &self,
- span: Span,
- base_ty: Ty<'tcx>,
- needs: Needs,
- ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
- self.try_overloaded_place_op(span, base_ty, &[], needs, PlaceOp::Deref)
- }
}
-use super::autoderef::Autoderef;
use super::method::MethodCallee;
-use super::{Expectation, FnCtxt, Needs, TupleArgumentsFlag};
+use super::{Expectation, FnCtxt, TupleArgumentsFlag};
use crate::type_error_struct;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_span::symbol::Ident;
use rustc_span::Span;
use rustc_target::spec::abi;
+use rustc_trait_selection::autoderef::Autoderef;
/// Checks that it is legal to call methods of the trait corresponding
/// to `trait_id` (this only cares about the trait, not the specific
while result.is_none() && autoderef.next().is_some() {
result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef);
}
- autoderef.finalize(self);
+ self.register_predicates(autoderef.into_obligations());
let output = match result {
None => {
arg_exprs: &'tcx [hir::Expr<'tcx>],
autoderef: &Autoderef<'a, 'tcx>,
) -> Option<CallStep<'tcx>> {
- let adjusted_ty = autoderef.unambiguous_final_ty(self);
+ let adjusted_ty =
+ self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
debug!(
"try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})",
call_expr, adjusted_ty
// If the callee is a bare function or a closure, then we're all set.
match adjusted_ty.kind {
ty::FnDef(..) | ty::FnPtr(_) => {
- let adjustments = autoderef.adjust_steps(self, Needs::None);
+ let adjustments = self.adjust_steps(autoderef);
self.apply_adjustments(callee_expr, adjustments);
return Some(CallStep::Builtin(adjusted_ty));
}
&closure_sig,
)
.0;
- let adjustments = autoderef.adjust_steps(self, Needs::None);
+ let adjustments = self.adjust_steps(autoderef);
self.record_deferred_call_resolution(
def_id,
DeferredCallResolution {
self.try_overloaded_call_traits(call_expr, adjusted_ty, Some(arg_exprs))
.or_else(|| self.try_overloaded_call_traits(call_expr, adjusted_ty, None))
.map(|(autoref, method)| {
- let mut adjustments = autoderef.adjust_steps(self, Needs::None);
+ let mut adjustments = self.adjust_steps(autoderef);
adjustments.extend(autoref);
self.apply_adjustments(callee_expr, adjustments);
CallStep::Overloaded(method)
let method = self.register_infer_ok_obligations(ok);
let mut autoref = None;
if borrow {
- if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind {
- let mutbl = match mutbl {
- hir::Mutability::Not => AutoBorrowMutability::Not,
- hir::Mutability::Mut => AutoBorrowMutability::Mut {
- // For initial two-phase borrow
- // deployment, conservatively omit
- // overloaded function call ops.
- allow_two_phase_borrow: AllowTwoPhase::No,
- },
- };
- autoref = Some(Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
- target: method.sig.inputs()[0],
- });
- }
+ // Check for &self vs &mut self in the method signature. Since this is either
+ // the Fn or FnMut trait, it should be one of those.
+ let (region, mutbl) = if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind
+ {
+ (r, mutbl)
+ } else {
+ span_bug!(call_expr.span, "input to call/call_mut is not a ref?");
+ };
+
+ let mutbl = match mutbl {
+ hir::Mutability::Not => AutoBorrowMutability::Not,
+ hir::Mutability::Mut => AutoBorrowMutability::Mut {
+ // For initial two-phase borrow
+ // deployment, conservatively omit
+ // overloaded function call ops.
+ allow_two_phase_borrow: AllowTwoPhase::No,
+ },
+ };
+ autoref = Some(Adjustment {
+ kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
+ target: method.sig.inputs()[0],
+ });
}
return Some((autoref, method));
}
(
ty::Binder::bind(self.tcx.mk_fn_sig(
self.err_args(arg_exprs.len()).into_iter(),
- self.tcx.types.err,
+ self.tcx.ty_error(),
false,
hir::Unsafety::Normal,
abi::Abi::Rust,
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable};
use rustc_session::lint;
use rustc_session::Session;
+use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
| ty::Generator(..)
| ty::Adt(..)
| ty::Never
- | ty::Error => {
+ | ty::Error(_) => {
self.tcx
.sess
.delay_span_bug(span, &format!("`{:?}` should be sized but is not?", t));
"only `u8` can be cast as `char`, not `{}`",
self.expr_ty
)
+ .span_label(self.span, "invalid cast")
.emit();
}
CastError::NonScalar => {
- type_error_struct!(
+ let mut err = type_error_struct!(
fcx.tcx.sess,
self.span,
self.expr_ty,
"non-primitive cast: `{}` as `{}`",
self.expr_ty,
fcx.ty_to_string(self.cast_ty)
- )
- .note(
- "an `as` expression can only be used to convert between \
- primitive types. Consider using the `From` trait",
- )
- .emit();
+ );
+ let mut sugg = None;
+ if let ty::Ref(reg, _, mutbl) = self.cast_ty.kind {
+ if fcx
+ .try_coerce(
+ self.expr,
+ fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
+ self.cast_ty,
+ AllowTwoPhase::No,
+ )
+ .is_ok()
+ {
+ sugg = Some(format!("&{}", mutbl.prefix_str()));
+ }
+ }
+ if let Some(sugg) = sugg {
+ err.span_label(self.span, "invalid cast");
+ err.span_suggestion_verbose(
+ self.expr.span.shrink_to_lo(),
+ "borrow the value for the cast to be valid",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ } else if !matches!(
+ self.cast_ty.kind,
+ ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..)
+ ) {
+ let mut label = true;
+ // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion:
+ if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+ if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::from_trait) {
+ let ty = fcx.resolve_vars_if_possible(&self.cast_ty);
+ // Erase regions to avoid panic in `prove_value` when calling
+ // `type_implements_trait`.
+ let ty = fcx.tcx.erase_regions(&ty);
+ let expr_ty = fcx.resolve_vars_if_possible(&self.expr_ty);
+ let expr_ty = fcx.tcx.erase_regions(&expr_ty);
+ let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]);
+ // Check for infer types because cases like `Option<{integer}>` would
+ // panic otherwise.
+ if !expr_ty.has_infer_types()
+ && fcx.tcx.type_implements_trait((
+ from_trait,
+ ty,
+ ty_params,
+ fcx.param_env,
+ ))
+ {
+ label = false;
+ err.span_suggestion(
+ self.span,
+ "consider using the `From` trait instead",
+ format!("{}::from({})", self.cast_ty, snippet),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ let msg = "an `as` expression can only be used to convert between primitive \
+ types or to coerce to a specific trait object";
+ if label {
+ err.span_label(self.span, msg);
+ } else {
+ err.note(msg);
+ }
+ } else {
+ err.span_label(self.span, "invalid cast");
+ }
+ err.emit();
}
CastError::SizedUnsizedCast => {
use crate::structured_errors::{SizedUnsizedCastError, StructuredDiagnostic};
};
let mut err = struct_span_err!(
fcx.tcx.sess,
- self.span,
+ if unknown_cast_to { self.cast_span } else { self.span },
E0641,
"cannot cast {} a pointer of an unknown kind",
if unknown_cast_to { "to" } else { "from" }
);
- err.note(
- "the type information given here is insufficient to check whether \
- the pointer cast is valid",
- );
if unknown_cast_to {
- err.span_suggestion_short(
- self.cast_span,
- "consider giving more type information",
- String::new(),
- Applicability::Unspecified,
+ err.span_label(self.cast_span, "needs more type information");
+ err.note(
+ "the type information given here is insufficient to check whether \
+ the pointer cast is valid",
+ );
+ } else {
+ err.span_label(
+ self.span,
+ "the type information given here is insufficient to check whether \
+ the pointer cast is valid",
);
}
err.emit();
Ok(s) => {
err.span_suggestion(
self.cast_span,
- "try casting to a `Box` instead",
+ "you can cast to a `Box` instead",
format!("Box<{}>", s),
Applicability::MachineApplicable,
);
}
Err(_) => {
- err.span_help(self.cast_span, &format!("did you mean `Box<{}>`?", tstr));
+ err.span_help(
+ self.cast_span,
+ &format!("you might have meant `Box<{}>`", tstr),
+ );
}
}
}
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
// prim -> prim
- (Int(CEnum), Int(_)) => Ok(CastKind::EnumCast),
+ (Int(CEnum), Int(_)) => {
+ self.cenum_impl_drop_lint(fcx);
+ Ok(CastKind::EnumCast)
+ }
(Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
(Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
// Coerce to a raw pointer so that we generate AddressOf in MIR.
let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No)
- .unwrap_or_else(|_| bug!(
+ .unwrap_or_else(|_| {
+ bug!(
"could not cast from reference to array to pointer to array ({:?} to {:?})",
self.expr_ty,
array_ptr_type,
- ));
+ )
+ });
// this will report a type mismatch if needed
fcx.demand_eqtype(self.span, ety, m_cast.ty);
Err(err) => Err(err),
}
}
+
+ fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
+ if let ty::Adt(d, _) = self.expr_ty.kind {
+ if d.has_dtor(fcx.tcx) {
+ fcx.tcx.struct_span_lint_hir(
+ lint::builtin::CENUM_IMPL_DROP_CAST,
+ self.expr.hir_id,
+ self.span,
+ |err| {
+ err.build(&format!(
+ "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
+ self.expr_ty, self.cast_ty
+ ))
+ .emit();
+ },
+ );
+ }
+ }
+ }
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let supplied_arguments = decl.inputs.iter().map(|a| {
// Convert the types that the user supplied (if any), but ignore them.
astconv.ast_ty_to_ty(a);
- self.tcx.types.err
+ self.tcx.ty_error()
});
if let hir::FnRetTy::Return(ref output) = decl.output {
let result = ty::Binder::bind(self.tcx.mk_fn_sig(
supplied_arguments,
- self.tcx.types.err,
+ self.tcx.ty_error(),
decl.c_variadic,
hir::Unsafety::Normal,
Abi::RustCall,
//!
//! Note that if we are expecting a reference, we will *reborrow*
//! even if the argument provided was already a reference. This is
-//! useful for freezing mut/const things (that is, when the expected is &T
-//! but you have &const T or &mut T) and also for avoiding the linearity
+//! useful for freezing mut things (that is, when the expected type is &T
+//! but you have &mut T) and also for avoiding the linearity
//! of mut things (when the expected is &mut T and you have &mut T). See
-//! the various `src/test/ui/coerce-reborrow-*.rs` tests for
+//! the various `src/test/ui/coerce/*.rs` tests for
//! examples of where this is useful.
//!
//! ## Subtle note
//!
-//! When deciding what type coercions to consider, we do not attempt to
-//! resolve any type variables we may encounter. This is because `b`
-//! represents the expected type "as the user wrote it", meaning that if
-//! the user defined a generic function like
+//! When infering the generic arguments of functions, the argument
+//! order is relevant, which can lead to the following edge case:
//!
-//! fn foo<A>(a: A, b: A) { ... }
+//! ```rust
+//! fn foo<T>(a: T, b: T) {
+//! // ...
+//! }
//!
-//! and then we wrote `foo(&1, @2)`, we will not auto-borrow
-//! either argument. In older code we went to some lengths to
-//! resolve the `b` variable, which could mean that we'd
-//! auto-borrow later arguments but not earlier ones, which
-//! seems very confusing.
+//! foo(&7i32, &mut 7i32);
+//! // This compiles, as we first infer `T` to be `&i32`,
+//! // and then coerce `&mut 7i32` to `&7i32`.
//!
-//! ## Subtler note
-//!
-//! However, right now, if the user manually specifies the
-//! values for the type variables, as so:
-//!
-//! foo::<&int>(@1, @2)
-//!
-//! then we *will* auto-borrow, because we can't distinguish this from a
-//! function that declared `&int`. This is inconsistent but it's easiest
-//! at the moment. The right thing to do, I think, is to consider the
-//! *unsubstituted* type when deciding whether to auto-borrow, but the
-//! *substituted* type when considering the bounds and so forth. But most
-//! of our methods don't give access to the unsubstituted type, and
-//! rightly so because they'd be error-prone. So maybe the thing to do is
-//! to actually determine the kind of coercions that should occur
-//! separately and pass them in. Or maybe it's ok as is. Anyway, it's
-//! sort of a minor point so I've opted to leave it for later -- after all,
-//! we may want to adjust precisely when coercions occur.
+//! foo(&mut 7i32, &7i32);
+//! // This does not compile, as we first infer `T` to be `&mut i32`
+//! // and are then unable to coerce `&7i32` to `&mut i32`.
+//! ```
use crate::astconv::AstConv;
-use crate::check::{FnCtxt, Needs};
+use crate::check::FnCtxt;
use rustc_errors::{struct_span_err, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>;
+/// Coercing a mutable reference to an immutable works, while
+/// coercing `&T` to `&mut T` should be forbidden.
fn coerce_mutbls<'tcx>(
from_mutbl: hir::Mutability,
to_mutbl: hir::Mutability,
// Just ignore error types.
if a.references_error() || b.references_error() {
- return success(vec![], self.fcx.tcx.types.err, vec![]);
+ return success(vec![], self.fcx.tcx.ty_error(), vec![]);
}
if a.is_never() {
return success(vec![], ty, obligations);
}
- let needs = Needs::maybe_mut_place(mutbl_b);
let InferOk { value: mut adjustments, obligations: o } =
- autoderef.adjust_steps_as_infer_ok(self, needs);
+ self.adjust_steps_as_infer_ok(&autoderef);
obligations.extend(o);
obligations.extend(autoderef.into_obligations());
let (adjustments, _) = self.register_infer_ok_obligations(ok);
self.apply_adjustments(expr, adjustments);
- Ok(if expr_ty.references_error() { self.tcx.types.err } else { target })
+ Ok(if expr_ty.references_error() { self.tcx.ty_error() } else { target })
}
/// Same as `try_coerce()`, but without side-effects.
{
let prev_ty = self.resolve_vars_with_obligations(prev_ty);
let new_ty = self.resolve_vars_with_obligations(new_ty);
- debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty);
+ debug!(
+ "coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)",
+ prev_ty,
+ new_ty,
+ exprs.len()
+ );
// Special-case that coercion alone cannot handle:
// Function items or non-capturing closures of differing IDs or InternalSubsts.
Ok(ok) => {
let (adjustments, target) = self.register_infer_ok_obligations(ok);
self.apply_adjustments(new, adjustments);
+ debug!(
+ "coercion::try_find_coercion_lub: was able to coerce from previous type {:?} to new type {:?}",
+ prev_ty, new_ty,
+ );
return Ok(target);
}
Err(e) => first_error = Some(e),
};
if !noop {
+ debug!(
+ "coercion::try_find_coercion_lub: older expression {:?} had adjustments, requiring LUB",
+ expr,
+ );
+
return self
.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
.map(|ok| self.register_infer_ok_obligations(ok));
}
}
Ok(ok) => {
+ debug!(
+ "coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?}",
+ prev_ty, new_ty,
+ );
let (adjustments, target) = self.register_infer_ok_obligations(ok);
for expr in exprs {
let expr = expr.as_coercion_site();
// If we see any error types, just propagate that error
// upwards.
if expression_ty.references_error() || self.merged_ty().references_error() {
- self.final_ty = Some(fcx.tcx.types.err);
+ self.final_ty = Some(fcx.tcx.ty_error());
return;
}
err.emit_unless(assign_to_bool || unsized_return);
- self.final_ty = Some(fcx.tcx.types.err);
+ self.final_ty = Some(fcx.tcx.ty_error());
}
}
}
use rustc_hir::intravisit;
use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
+use rustc_middle::ty;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
+use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt, WithConstness};
use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
use super::{potentially_plural_count, FnCtxt, Inherited};
+use std::iter;
/// Checks that a method from an impl conforms to the signature of
/// the same method as declared in the trait.
// This code is best explained by example. Consider a trait:
//
- // trait Trait<'t,T> {
- // fn method<'a,M>(t: &'t T, m: &'a M) -> Self;
+ // trait Trait<'t, T> {
+ // fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
// }
//
// And an impl:
//
// impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
- // fn method<'b,N>(t: &'j &'i U, m: &'b N) -> Foo;
+ // fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo;
// }
//
// We wish to decide if those two method types are compatible.
// regions (Note: but only early-bound regions, i.e., those
// declared on the impl or used in type parameter bounds).
//
- // impl_to_skol_substs = {'i => 'i0, U => U0, N => N0 }
+ // impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
//
- // Now we can apply skol_substs to the type of the impl method
+ // Now we can apply placeholder_substs to the type of the impl method
// to yield a new function type in terms of our fresh, placeholder
// types:
//
// We now want to extract and substitute the type of the *trait*
// method and compare it. To do so, we must create a compound
// substitution by combining trait_to_impl_substs and
- // impl_to_skol_substs, and also adding a mapping for the method
+ // impl_to_placeholder_substs, and also adding a mapping for the method
// type parameters. We extend the mapping to also include
// the method parameters.
//
- // trait_to_skol_substs = { T => &'i0 U0, Self => Foo, M => N0 }
+ // trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
//
// Applying this to the trait method type yields:
//
// satisfied by the implementation's method.
//
// We do this by creating a parameter environment which contains a
- // substitution corresponding to impl_to_skol_substs. We then build
- // trait_to_skol_substs and use it to convert the predicates contained
+ // substitution corresponding to impl_to_placeholder_substs. We then build
+ // trait_to_placeholder_substs and use it to convert the predicates contained
// in the trait_m.generics to the placeholder form.
//
// Finally we register each of these predicates as an obligation in
// a fresh FulfillmentCtxt, and invoke select_all_or_error.
// Create mapping from impl to placeholder.
- let impl_to_skol_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
+ let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
// Create mapping from trait to placeholder.
- let trait_to_skol_substs =
- impl_to_skol_substs.rebase_onto(tcx, impl_m.container.id(), trait_to_impl_substs);
- debug!("compare_impl_method: trait_to_skol_substs={:?}", trait_to_skol_substs);
+ let trait_to_placeholder_substs =
+ impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container.id(), trait_to_impl_substs);
+ debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs);
let impl_m_generics = tcx.generics_of(impl_m.def_id);
let trait_m_generics = tcx.generics_of(trait_m.def_id);
// if all constraints hold.
hybrid_preds
.predicates
- .extend(trait_m_predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
+ .extend(trait_m_predicates.instantiate_own(tcx, trait_to_placeholder_substs).predicates);
// Construct trait parameter environment and then shift it into the placeholder viewpoint.
// The key step here is to update the caller_bounds's predicates to be
let mut selcx = traits::SelectionContext::new(&infcx);
- let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_skol_substs);
+ let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
let (impl_m_own_bounds, _) = infcx.replace_bound_vars_with_fresh_vars(
impl_m_span,
infer::HigherRankedType,
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, &tcx.fn_sig(trait_m.def_id));
- let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs);
+ let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs);
let trait_sig =
inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, &trait_sig);
let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig));
let _: Result<(), ErrorReported> = (|| {
compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?;
- compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)
+ compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)?;
+
+ compare_projection_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
})();
}
/// The equivalent of [compare_predicate_entailment], but for associated types
/// instead of associated functions.
-fn compare_type_predicate_entailment(
+fn compare_type_predicate_entailment<'tcx>(
tcx: TyCtxt<'tcx>,
impl_ty: &ty::AssocItem,
impl_ty_span: Span,
})
}
+/// Validate that `ProjectionCandidate`s created for this associated type will
+/// be valid.
+///
+/// Usually given
+///
+/// trait X { type Y: Copy } impl X for T { type Y = S; }
+///
+/// We are able to normalize `<T as X>::U` to `S`, and so when we check the
+/// impl is well-formed we have to prove `S: Copy`.
+///
+/// For default associated types the normalization is not possible (the value
+/// from the impl could be overridden). We also can't normalize generic
+/// associated types (yet) because they contain bound parameters.
+fn compare_projection_bounds<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ty: &ty::AssocItem,
+ impl_ty: &ty::AssocItem,
+ impl_ty_span: Span,
+ impl_trait_ref: ty::TraitRef<'tcx>,
+) -> Result<(), ErrorReported> {
+ let have_gats = tcx.features().generic_associated_types;
+ if impl_ty.defaultness.is_final() && !have_gats {
+ // For "final", non-generic associate type implementations, we
+ // don't need this as described above.
+ return Ok(());
+ }
+
+ let param_env = tcx.param_env(impl_ty.def_id);
+
+ // Given
+ //
+ // impl<A, B> Foo<u32> for (A, B) {
+ // type Bar<C> =...
+ // }
+ //
+ // - `impl_substs` would be `[A, B, C]`
+ // - `rebased_substs` would be `[(A, B), u32, C]`, combining the substs from
+ // the *trait* with the generic associated type parameters.
+ let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
+ let rebased_substs =
+ impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
+ let impl_ty_value = tcx.type_of(impl_ty.def_id);
+
+ // Map the predicate from the trait to the corresponding one for the impl.
+ // For example:
+ //
+ // trait X<A> { type Y<'a>: PartialEq<A> } impl X for T { type Y<'a> = &'a S; }
+ // impl<'x> X<&'x u32> for () { type Y<'c> = &'c u32; }
+ //
+ // For the `for<'a> <<Self as X<A>>::Y<'a>: PartialEq<A>` bound, this
+ // function would translate and partially normalize
+ // `[<Self as X<A>>::Y<'a>, A]` to `[&'a u32, &'x u32]`.
+ let translate_predicate_substs = move |predicate_substs: SubstsRef<'tcx>| {
+ tcx.mk_substs(
+ iter::once(impl_ty_value.into())
+ .chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, rebased_substs))),
+ )
+ };
+
+ tcx.infer_ctxt().enter(move |infcx| {
+ let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
+ let infcx = &inh.infcx;
+ let mut selcx = traits::SelectionContext::new(&infcx);
+
+ let impl_ty_hir_id = tcx.hir().as_local_hir_id(impl_ty.def_id.expect_local());
+ let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
+ let cause = ObligationCause::new(
+ impl_ty_span,
+ impl_ty_hir_id,
+ ObligationCauseCode::ItemObligation(trait_ty.def_id),
+ );
+
+ let predicates = tcx.projection_predicates(trait_ty.def_id);
+
+ debug!("compare_projection_bounds: projection_predicates={:?}", predicates);
+
+ for predicate in predicates {
+ let concrete_ty_predicate = match predicate.kind() {
+ ty::PredicateKind::Trait(poly_tr, c) => poly_tr
+ .map_bound(|tr| {
+ let trait_substs = translate_predicate_substs(tr.trait_ref.substs);
+ ty::TraitRef { def_id: tr.def_id(), substs: trait_substs }
+ })
+ .with_constness(*c)
+ .to_predicate(tcx),
+ ty::PredicateKind::Projection(poly_projection) => poly_projection
+ .map_bound(|projection| {
+ let projection_substs =
+ translate_predicate_substs(projection.projection_ty.substs);
+ ty::ProjectionPredicate {
+ projection_ty: ty::ProjectionTy {
+ substs: projection_substs,
+ item_def_id: projection.projection_ty.item_def_id,
+ },
+ ty: projection.ty.subst(tcx, rebased_substs),
+ }
+ })
+ .to_predicate(tcx),
+ ty::PredicateKind::TypeOutlives(poly_outlives) => poly_outlives
+ .map_bound(|outlives| {
+ ty::OutlivesPredicate(impl_ty_value, outlives.1.subst(tcx, rebased_substs))
+ })
+ .to_predicate(tcx),
+ _ => bug!("unexepected projection predicate kind: `{:?}`", predicate),
+ };
+
+ let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
+ &mut selcx,
+ param_env,
+ normalize_cause.clone(),
+ &concrete_ty_predicate,
+ );
+
+ debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
+
+ inh.register_predicates(obligations);
+ inh.register_predicate(traits::Obligation::new(
+ cause.clone(),
+ param_env,
+ normalized_predicate,
+ ));
+ }
+
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
+ infcx.report_fulfillment_errors(errors, None, false);
+ return Err(ErrorReported);
+ }
+
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id);
+ fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &[]);
+
+ Ok(())
+ })
+}
+
fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
match impl_item.kind {
ty::AssocKind::Const => "const",
}
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
self.suggest_missing_await(err, expr, expected, expr_ty);
+ self.note_need_for_fn_pointer(err, expected, expr_ty);
}
// Requires that the two types unify, and prints an error message if
let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| {
if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false }
};
+ let is_negative_int =
+ |expr: &hir::Expr<'_>| matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::UnNeg, ..));
+ let is_uint = |ty: Ty<'_>| matches!(ty.kind, ty::Uint(..));
let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id);
"you can convert `{}` from `{}` to `{}`, matching the type of `{}`",
lhs_src, expected_ty, checked_ty, src
);
- let suggestion = format!("{}::from({})", checked_ty, lhs_src,);
+ let suggestion = format!("{}::from({})", checked_ty, lhs_src);
(lhs_expr.span, msg, suggestion)
} else {
let msg = format!("{} and panic if the converted value wouldn't fit", msg);
|err: &mut DiagnosticBuilder<'_>,
found_to_exp_is_fallible: bool,
exp_to_found_is_fallible: bool| {
+ let always_fallible = found_to_exp_is_fallible
+ && (exp_to_found_is_fallible || expected_ty_expr.is_none());
let msg = if literal_is_ty_suffixed(expr) {
&lit_msg
+ } else if always_fallible && (is_negative_int(expr) && is_uint(expected_ty)) {
+ // We now know that converting either the lhs or rhs is fallible. Before we
+ // suggest a fallible conversion, check if the value can never fit in the
+ // expected type.
+ let msg = format!("`{}` cannot fit into type `{}`", src, expected_ty);
+ err.note(&msg);
+ return;
} else if in_const_context {
// Do not recommend `into` or `try_into` in const contexts.
return;
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty;
-use rustc_middle::ty::adjustment::{
- Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
-};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
use rustc_middle::ty::Ty;
use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{AdtKind, Visibility};
self.check_expr_with_expectation(expr, ExpectHasType(expected))
}
- pub(super) fn check_expr_with_expectation(
+ fn check_expr_with_expectation_and_needs(
&self,
expr: &'tcx hir::Expr<'tcx>,
expected: Expectation<'tcx>,
+ needs: Needs,
) -> Ty<'tcx> {
- self.check_expr_with_expectation_and_needs(expr, expected, Needs::None)
+ let ty = self.check_expr_with_expectation(expr, expected);
+
+ // If the expression is used in a place whether mutable place is required
+ // e.g. LHS of assignment, perform the conversion.
+ if let Needs::MutPlace = needs {
+ self.convert_place_derefs_to_mutable(expr);
+ }
+
+ ty
}
pub(super) fn check_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
/// Note that inspecting a type's structure *directly* may expose the fact
/// that there are actually multiple representations for `Error`, so avoid
/// that when err needs to be handled differently.
- fn check_expr_with_expectation_and_needs(
+ pub(super) fn check_expr_with_expectation(
&self,
expr: &'tcx hir::Expr<'tcx>,
expected: Expectation<'tcx>,
- needs: Needs,
) -> Ty<'tcx> {
debug!(">> type-checking: expr={:?} expected={:?}", expr, expected);
let old_diverges = self.diverges.replace(Diverges::Maybe);
let old_has_errors = self.has_errors.replace(false);
- let ty = self.check_expr_kind(expr, expected, needs);
+ let ty = self.check_expr_kind(expr, expected);
// Warn for non-block expressions with diverging children.
match expr.kind {
&self,
expr: &'tcx hir::Expr<'tcx>,
expected: Expectation<'tcx>,
- needs: Needs,
) -> Ty<'tcx> {
- debug!("check_expr_kind(expr={:?}, expected={:?}, needs={:?})", expr, expected, needs,);
+ debug!("check_expr_kind(expr={:?}, expected={:?})", expr, expected);
let tcx = self.tcx;
match expr.kind {
self.check_expr_assign(expr, expected, lhs, rhs, span)
}
ExprKind::AssignOp(op, ref lhs, ref rhs) => self.check_binop_assign(expr, op, lhs, rhs),
- ExprKind::Unary(unop, ref oprnd) => {
- self.check_expr_unary(unop, oprnd, expected, needs, expr)
- }
+ ExprKind::Unary(unop, ref oprnd) => self.check_expr_unary(unop, oprnd, expected, expr),
ExprKind::AddrOf(kind, mutbl, ref oprnd) => {
self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
}
tcx.types.never
} else {
// There was an error; make type-check fail.
- tcx.types.err
+ tcx.ty_error()
}
}
ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
ExprKind::Block(ref body, _) => self.check_block_with_expected(&body, expected),
ExprKind::Call(ref callee, ref args) => self.check_call(expr, &callee, args, expected),
ExprKind::MethodCall(ref segment, span, ref args, _) => {
- self.check_method_call(expr, segment, span, args, expected, needs)
+ self.check_method_call(expr, segment, span, args, expected)
}
ExprKind::Cast(ref e, ref t) => self.check_expr_cast(e, t, expr),
ExprKind::Type(ref e, ref t) => {
ExprKind::Struct(ref qpath, fields, ref base_expr) => {
self.check_expr_struct(expr, expected, qpath, fields, base_expr)
}
- ExprKind::Field(ref base, field) => self.check_field(expr, needs, &base, field),
- ExprKind::Index(ref base, ref idx) => self.check_expr_index(base, idx, needs, expr),
+ ExprKind::Field(ref base, field) => self.check_field(expr, &base, field),
+ ExprKind::Index(ref base, ref idx) => self.check_expr_index(base, idx, expr),
ExprKind::Yield(ref value, ref src) => self.check_expr_yield(value, expr, src),
- hir::ExprKind::Err => tcx.types.err,
+ hir::ExprKind::Err => tcx.ty_error(),
}
}
unop: hir::UnOp,
oprnd: &'tcx hir::Expr<'tcx>,
expected: Expectation<'tcx>,
- needs: Needs,
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
let tcx = self.tcx;
hir::UnOp::UnNot | hir::UnOp::UnNeg => expected,
hir::UnOp::UnDeref => NoExpectation,
};
- let needs = match unop {
- hir::UnOp::UnDeref => needs,
- _ => Needs::None,
- };
- let mut oprnd_t = self.check_expr_with_expectation_and_needs(&oprnd, expected_inner, needs);
+ let mut oprnd_t = self.check_expr_with_expectation(&oprnd, expected_inner);
if !oprnd_t.references_error() {
oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
match unop {
hir::UnOp::UnDeref => {
- if let Some(mt) = oprnd_t.builtin_deref(true) {
- oprnd_t = mt.ty;
- } else if let Some(ok) = self.try_overloaded_deref(expr.span, oprnd_t, needs) {
- let method = self.register_infer_ok_obligations(ok);
- if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind {
- let mutbl = match mutbl {
- hir::Mutability::Not => AutoBorrowMutability::Not,
- hir::Mutability::Mut => AutoBorrowMutability::Mut {
- // (It shouldn't actually matter for unary ops whether
- // we enable two-phase borrows or not, since a unary
- // op has no additional operands.)
- allow_two_phase_borrow: AllowTwoPhase::No,
- },
- };
- self.apply_adjustments(
- oprnd,
- vec![Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
- target: method.sig.inputs()[0],
- }],
- );
- }
- oprnd_t = self.make_overloaded_place_return_type(method).ty;
- self.write_method_call(expr.hir_id, method);
+ if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) {
+ oprnd_t = ty;
} else {
let mut err = type_error_struct!(
tcx.sess,
tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp, None);
}
err.emit();
- oprnd_t = tcx.types.err;
+ oprnd_t = tcx.ty_error();
}
}
hir::UnOp::UnNot => {
_ => NoExpectation,
}
});
- let needs = Needs::maybe_mut_place(mutbl);
- let ty = self.check_expr_with_expectation_and_needs(&oprnd, hint, needs);
+ let ty =
+ self.check_expr_with_expectation_and_needs(&oprnd, hint, Needs::maybe_mut_place(mutbl));
let tm = ty::TypeAndMut { ty, mutbl };
match kind {
- _ if tm.ty.references_error() => self.tcx.types.err,
+ _ if tm.ty.references_error() => self.tcx.ty_error(),
hir::BorrowKind::Raw => {
self.check_named_place_expr(oprnd);
self.tcx.mk_ptr(tm)
let ty = match res {
Res::Err => {
self.set_tainted_by_errors();
- tcx.types.err
+ tcx.ty_error()
}
Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) => {
report_unexpected_variant_res(tcx, res, expr.span);
- tcx.types.err
+ tcx.ty_error()
}
_ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0,
};
Some(ctxt) => ctxt.coerce.as_ref().map(|coerce| coerce.expected_ty()),
None => {
// Avoid ICE when `break` is inside a closure (#65383).
- self.tcx.sess.delay_span_bug(
+ return tcx.ty_error_with_message(
expr.span,
"break was outside loop, but no error was emitted",
);
- return tcx.types.err;
}
}
};
// If the loop context is not a `loop { }`, then break with
// a value is illegal, and `opt_coerce_to` will be `None`.
// Just set expectation to error in that case.
- let coerce_to = opt_coerce_to.unwrap_or(tcx.types.err);
+ let coerce_to = opt_coerce_to.unwrap_or_else(|| tcx.ty_error());
// Recurse without `enclosing_breakables` borrowed.
e_ty = self.check_expr_with_hint(e, coerce_to);
Some(ctxt) => ctxt,
None => {
// Avoid ICE when `break` is inside a closure (#65383).
- self.tcx.sess.delay_span_bug(
+ return tcx.ty_error_with_message(
expr.span,
"break was outside loop, but no error was emitted",
);
- return tcx.types.err;
}
};
// this can only happen if the `break` was not
// inside a loop at all, which is caught by the
// loop-checking pass.
- self.tcx
- .sess
- .delay_span_bug(expr.span, "break was outside loop, but no error was emitted");
+ let err = self.tcx.ty_error_with_message(
+ expr.span,
+ "break was outside loop, but no error was emitted",
+ );
// We still need to assign a type to the inner expression to
// prevent the ICE in #43162.
if let Some(ref e) = expr_opt {
- self.check_expr_with_hint(e, tcx.types.err);
+ self.check_expr_with_hint(e, err);
// ... except when we try to 'break rust;'.
// ICE this expression in particular (see #43162).
}
}
}
+
// There was an error; make type-check fail.
- tcx.types.err
+ err
}
}
self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
if lhs_ty.references_error() || rhs_ty.references_error() {
- self.tcx.types.err
+ self.tcx.ty_error()
} else {
self.tcx.mk_unit()
}
span: Span,
args: &'tcx [hir::Expr<'tcx>],
expected: Expectation<'tcx>,
- needs: Needs,
) -> Ty<'tcx> {
let rcvr = &args[0];
- let rcvr_t = self.check_expr_with_needs(&rcvr, needs);
+ let rcvr_t = self.check_expr(&rcvr);
// no need to check for bot/err -- callee does that
let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);
rcvr,
probe::ProbeScope::AllTraits,
) {
- err.span_label(
- pick.item.ident.span,
- &format!("the method is available for `{}` here", new_rcvr_t),
- );
+ debug!("try_alt_rcvr: pick candidate {:?}", pick);
+ // Make sure the method is defined for the *actual* receiver:
+ // we don't want to treat `Box<Self>` as a receiver if
+ // it only works because of an autoderef to `&self`
+ if pick.autoderefs == 0 {
+ err.span_label(
+ pick.item.ident.span,
+ &format!("the method is available for `{}` here", new_rcvr_t),
+ );
+ }
}
}
};
// Eagerly check for some obvious errors.
if t_expr.references_error() || t_cast.references_error() {
- self.tcx.types.err
+ self.tcx.ty_error()
} else {
// Defer other checks until we're done type checking.
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
deferred_cast_checks.push(cast_check);
t_cast
}
- Err(ErrorReported) => self.tcx.types.err,
+ Err(ErrorReported) => self.tcx.ty_error(),
}
}
}
};
if element_ty.references_error() {
- return tcx.types.err;
+ return tcx.ty_error();
}
tcx.mk_ty(ty::Array(t, count))
});
let tuple = self.tcx.mk_tup(elt_ts_iter);
if tuple.references_error() {
- self.tcx.types.err
+ self.tcx.ty_error()
} else {
self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized);
tuple
variant_ty
} else {
self.check_struct_fields_on_error(fields, base_expr);
- return self.tcx.types.err;
+ return self.tcx.ty_error();
};
let path_span = match *qpath {
self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name, span);
}
- tcx.types.err
+ tcx.ty_error()
};
// Make sure to give a type to the field even if there's
fn check_field(
&self,
expr: &'tcx hir::Expr<'tcx>,
- needs: Needs,
base: &'tcx hir::Expr<'tcx>,
field: Ident,
) -> Ty<'tcx> {
- let expr_t = self.check_expr_with_needs(base, needs);
+ let expr_t = self.check_expr(base);
let expr_t = self.structurally_resolved_type(base.span, expr_t);
let mut private_candidate = None;
let mut autoderef = self.autoderef(expr.span, expr_t);
// of error recovery.
self.write_field_index(expr.hir_id, index);
if field.vis.is_accessible_from(def_scope, self.tcx) {
- let adjustments = autoderef.adjust_steps(self, needs);
+ let adjustments = self.adjust_steps(&autoderef);
self.apply_adjustments(base, adjustments);
- autoderef.finalize(self);
+ self.register_predicates(autoderef.into_obligations());
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span);
return field_ty;
if let Ok(index) = fstr.parse::<usize>() {
if fstr == index.to_string() {
if let Some(field_ty) = tys.get(index) {
- let adjustments = autoderef.adjust_steps(self, needs);
+ let adjustments = self.adjust_steps(&autoderef);
self.apply_adjustments(base, adjustments);
- autoderef.finalize(self);
+ self.register_predicates(autoderef.into_obligations());
self.write_field_index(expr.hir_id, index);
return field_ty.expect_ty();
_ => {}
}
}
- autoderef.unambiguous_final_ty(self);
+ self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
if let Some((did, field_ty)) = private_candidate {
self.ban_private_field_access(expr, expr_t, field, did);
.emit();
}
- self.tcx().types.err
+ self.tcx().ty_error()
}
fn ban_nonexisting_field(
&self,
base: &'tcx hir::Expr<'tcx>,
idx: &'tcx hir::Expr<'tcx>,
- needs: Needs,
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
- let base_t = self.check_expr_with_needs(&base, needs);
+ let base_t = self.check_expr(&base);
let idx_t = self.check_expr(&idx);
if base_t.references_error() {
idx_t
} else {
let base_t = self.structurally_resolved_type(base.span, base_t);
- match self.lookup_indexing(expr, base, base_t, idx_t, needs) {
+ match self.lookup_indexing(expr, base, base_t, idx_t) {
Some((index_ty, element_ty)) => {
// two-phase not needed because index_ty is never mutable
self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No);
}
}
err.emit();
- self.tcx.types.err
+ self.tcx.ty_error()
}
}
}
ty::Char => "'a'",
ty::Int(_) | ty::Uint(_) => "42",
ty::Float(_) => "3.14159",
- ty::Error | ty::Never => return None,
+ ty::Error(_) | ty::Never => return None,
_ => "value",
})
}
| "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add"
| "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz"
| "bswap" | "bitreverse" | "discriminant_value" | "type_id" | "likely" | "unlikely"
- | "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" | "type_name" => {
- hir::Unsafety::Normal
- }
+ | "ptr_guaranteed_eq" | "ptr_guaranteed_ne" | "minnumf32" | "minnumf64" | "maxnumf32"
+ | "maxnumf64" | "type_name" | "variant_count" => hir::Unsafety::Normal,
_ => hir::Unsafety::Unsafe,
}
}
let unsafety = intrinsic_operation_unsafety(&name[..]);
let (n_tps, inputs, output) = match &name[..] {
"breakpoint" => (0, Vec::new(), tcx.mk_unit()),
- "size_of" | "pref_align_of" | "min_align_of" => (1, Vec::new(), tcx.types.usize),
+ "size_of" | "pref_align_of" | "min_align_of" | "variant_count" => {
+ (1, Vec::new(), tcx.types.usize)
+ }
"size_of_val" | "min_align_of_val" => {
(1, vec![tcx.mk_imm_ptr(param(0))], tcx.types.usize)
}
(1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool]))
}
+ "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
+ (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool)
+ }
+
"ptr_offset_from" => {
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
}
return;
}
+ "count_code_region" => (0, vec![tcx.types.u32], tcx.mk_unit()),
+
ref other => {
struct_span_err!(
tcx.sess,
use super::{probe, MethodCallee};
use crate::astconv::AstConv;
-use crate::check::{callee, FnCtxt, Needs, PlaceOp};
+use crate::check::{callee, FnCtxt};
use crate::hir::def_id::DefId;
use crate::hir::GenericArg;
use rustc_hir as hir;
use rustc_infer::infer::{self, InferOk};
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{Subst, SubstsRef};
// Create the final `MethodCallee`.
let callee = MethodCallee { def_id: pick.item.def_id, substs: all_substs, sig: method_sig };
-
- if let Some(hir::Mutability::Mut) = pick.autoref {
- self.convert_place_derefs_to_mutable();
- }
-
ConfirmResult { callee, illegal_sized_bound }
}
let (_, n) = match autoderef.nth(pick.autoderefs) {
Some(n) => n,
None => {
- self.tcx.sess.delay_span_bug(
+ return self.tcx.ty_error_with_message(
rustc_span::DUMMY_SP,
&format!("failed autoderef {}", pick.autoderefs),
);
- return self.tcx.types.err;
}
};
assert_eq!(n, pick.autoderefs);
- let mut adjustments = autoderef.adjust_steps(self, Needs::None);
+ let mut adjustments = self.adjust_steps(&autoderef);
- let mut target = autoderef.unambiguous_final_ty(self);
+ let mut target =
+ self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
if let Some(mutbl) = pick.autoref {
let region = self.next_region_var(infer::Autoref(self.span));
assert!(pick.unsize.is_none());
}
- autoderef.finalize(self);
+ self.register_predicates(autoderef.into_obligations());
// Write out the final adjustments.
self.apply_adjustments(self.self_expr, adjustments);
self.register_wf_obligation(fty.into(), self.span, traits::MiscObligation);
}
- ///////////////////////////////////////////////////////////////////////////
- // RECONCILIATION
-
- /// When we select a method with a mutable autoref, we have to go convert any
- /// auto-derefs, indices, etc from `Deref` and `Index` into `DerefMut` and `IndexMut`
- /// respectively.
- fn convert_place_derefs_to_mutable(&self) {
- // Gather up expressions we want to munge.
- let mut exprs = vec![self.self_expr];
-
- loop {
- match exprs.last().unwrap().kind {
- hir::ExprKind::Field(ref expr, _)
- | hir::ExprKind::Index(ref expr, _)
- | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) => exprs.push(&expr),
- _ => break,
- }
- }
-
- debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
-
- // Fix up autoderefs and derefs.
- for (i, &expr) in exprs.iter().rev().enumerate() {
- debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr);
-
- // Fix up the autoderefs. Autorefs can only occur immediately preceding
- // overloaded place ops, and will be fixed by them in order to get
- // the correct region.
- let mut source = self.node_ty(expr.hir_id);
- // Do not mutate adjustments in place, but rather take them,
- // and replace them after mutating them, to avoid having the
- // tables borrowed during (`deref_mut`) method resolution.
- let previous_adjustments =
- self.tables.borrow_mut().adjustments_mut().remove(expr.hir_id);
- if let Some(mut adjustments) = previous_adjustments {
- let needs = Needs::MutPlace;
- for adjustment in &mut adjustments {
- if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind {
- if let Some(ok) = self.try_overloaded_deref(expr.span, source, needs) {
- let method = self.register_infer_ok_obligations(ok);
- if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
- *deref = OverloadedDeref { region, mutbl };
- }
- }
- }
- source = adjustment.target;
- }
- self.tables.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments);
- }
-
- match expr.kind {
- hir::ExprKind::Index(ref base_expr, ref index_expr) => {
- // We need to get the final type in case dereferences were needed for the trait
- // to apply (#72002).
- let index_expr_ty = self.tables.borrow().expr_ty_adjusted(index_expr);
- self.convert_place_op_to_mutable(
- PlaceOp::Index,
- expr,
- base_expr,
- &[index_expr_ty],
- );
- }
- hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base_expr) => {
- self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr, &[]);
- }
- _ => {}
- }
- }
- }
-
- fn convert_place_op_to_mutable(
- &self,
- op: PlaceOp,
- expr: &hir::Expr<'_>,
- base_expr: &hir::Expr<'_>,
- arg_tys: &[Ty<'tcx>],
- ) {
- debug!("convert_place_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys);
- if !self.tables.borrow().is_method_call(expr) {
- debug!("convert_place_op_to_mutable - builtin, nothing to do");
- return;
- }
-
- let base_ty = self
- .tables
- .borrow()
- .expr_adjustments(base_expr)
- .last()
- .map_or_else(|| self.node_ty(expr.hir_id), |adj| adj.target);
- let base_ty = self.resolve_vars_if_possible(&base_ty);
-
- // Need to deref because overloaded place ops take self by-reference.
- let base_ty =
- base_ty.builtin_deref(false).expect("place op takes something that is not a ref").ty;
-
- let method = self.try_overloaded_place_op(expr.span, base_ty, arg_tys, Needs::MutPlace, op);
- let method = match method {
- Some(ok) => self.register_infer_ok_obligations(ok),
- None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed"),
- };
- debug!("convert_place_op_to_mutable: method={:?}", method);
- self.write_method_call(expr.hir_id, method);
-
- let (region, mutbl) = if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind {
- (r, mutbl)
- } else {
- span_bug!(expr.span, "input to place op is not a ref?");
- };
-
- // Convert the autoref in the base expr to mutable with the correct
- // region and mutability.
- let base_expr_ty = self.node_ty(base_expr.hir_id);
- if let Some(adjustments) =
- self.tables.borrow_mut().adjustments_mut().get_mut(base_expr.hir_id)
- {
- let mut source = base_expr_ty;
- for adjustment in &mut adjustments[..] {
- if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
- debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment);
- let mutbl = match mutbl {
- hir::Mutability::Not => AutoBorrowMutability::Not,
- hir::Mutability::Mut => AutoBorrowMutability::Mut {
- // For initial two-phase borrow
- // deployment, conservatively omit
- // overloaded operators.
- allow_two_phase_borrow: AllowTwoPhase::No,
- },
- };
- adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
- adjustment.target =
- self.tcx.mk_ref(region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() });
- }
- source = adjustment.target;
- }
-
- // If we have an autoref followed by unsizing at the end, fix the unsize target.
-
- if let [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }] =
- adjustments[..]
- {
- *target = method.sig.inputs()[0];
- }
- }
- }
-
///////////////////////////////////////////////////////////////////////////
// MISCELLANY
self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
for import_id in &pick.import_ids {
- let import_def_id = self.tcx.hir().local_def_id(*import_id);
- debug!("used_trait_import: {:?}", import_def_id);
+ debug!("used_trait_import: {:?}", import_id);
Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports)
.unwrap()
- .insert(import_def_id.to_def_id());
+ .insert(*import_id);
}
self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span);
opt_input_types: Option<&[Ty<'tcx>]>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!(
- "lookup_in_trait_adjusted(self_ty={:?}, \
- m_name={}, trait_def_id={:?})",
+ "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?})",
self_ty, m_name, trait_def_id
);
let mut tables = self.tables.borrow_mut();
let used_trait_imports = Lrc::get_mut(&mut tables.used_trait_imports).unwrap();
for import_id in pick.import_ids {
- let import_def_id = tcx.hir().local_def_id(import_id);
- debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id);
- used_trait_imports.insert(import_def_id.to_def_id());
+ debug!("resolve_ufcs: used_trait_import: {:?}", import_id);
+ used_trait_imports.insert(import_id);
}
}
use super::NoMatchData;
use super::{CandidateSource, ImplSource, TraitSource};
-use crate::check::autoderef::{self, Autoderef};
use crate::check::FnCtxt;
use crate::hir::def::DefKind;
use crate::hir::def_id::DefId;
};
use rustc_session::config::nightly_options;
use rustc_session::lint;
+use rustc_span::def_id::LocalDefId;
use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
+use rustc_trait_selection::autoderef::{self, Autoderef};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy;
use rustc_trait_selection::traits::query::method_autoderef::{
xform_ret_ty: Option<Ty<'tcx>>,
item: ty::AssocItem,
kind: CandidateKind<'tcx>,
- import_ids: SmallVec<[hir::HirId; 1]>,
+ import_ids: SmallVec<[LocalDefId; 1]>,
}
#[derive(Debug)]
pub struct Pick<'tcx> {
pub item: ty::AssocItem,
pub kind: PickKind<'tcx>,
- pub import_ids: SmallVec<[hir::HirId; 1]>,
+ pub import_ids: SmallVec<[LocalDefId; 1]>,
// Indicates that the source expression should be autoderef'd N times
//
self.tcx.sess,
span,
E0699,
- "the type of this value must be known \
- to call a method on a raw pointer on it"
+ "the type of this value must be known to call a method on a raw pointer on \
+ it"
)
.emit();
} else {
.probe_instantiate_query_response(span, &orig_values, ty)
.unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
let ty = self.structurally_resolved_type(span, ty.value);
- assert_eq!(ty, self.tcx.types.err);
+ assert!(matches!(ty.kind, ty::Error(_)));
return Err(MethodError::NoMatch(NoMatchData::new(
Vec::new(),
Vec::new(),
})
.collect();
- let final_ty = autoderef.maybe_ambiguous_final_ty();
+ let final_ty = autoderef.final_ty(true);
let opt_bad_ty = match final_ty.kind {
- ty::Infer(ty::TyVar(_)) | ty::Error => Some(MethodAutoderefBadTy {
+ ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
reached_raw_pointer,
ty: infcx
.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
fn assemble_extension_candidates_for_trait(
&mut self,
- import_ids: &SmallVec<[hir::HirId; 1]>,
+ import_ids: &SmallVec<[LocalDefId; 1]>,
trait_def_id: DefId,
) -> Result<(), MethodError<'tcx>> {
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
///
/// ```
/// trait Foo { ... }
- /// impl Foo for Vec<int> { ... }
+ /// impl Foo for Vec<i32> { ... }
/// impl Foo for Vec<usize> { ... }
/// ```
///
pub mod method;
mod op;
mod pat;
+mod place_op;
mod regionck;
mod upvar;
mod wfcheck;
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::lang_items::{
use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::adjustment::{
- Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
+ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::query::Providers;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::opaque_types::{InferCtxtExt as _, OpaqueTypeDecl};
use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
+use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
use crate::require_c_abi_if_c_variadic;
use crate::util::common::indenter;
-use self::autoderef::Autoderef;
use self::callee::DeferredCallResolution;
use self::coercion::{CoerceMany, DynamicCoerceMany};
use self::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
tcx.hir().krate().par_visit_all_item_likes(&visit);
}
-fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx });
}
}
}
-fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &DefIdSet {
+fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
&*tcx.typeck_tables_of(def_id).used_trait_imports
}
) -> &ty::TypeckTables<'tcx> {
let fallback = move || {
let span = tcx.hir().span(tcx.hir().as_local_hir_id(def_id));
- tcx.sess.delay_span_bug(span, "diagnostic only typeck table used");
- tcx.types.err
+ tcx.ty_error_with_message(span, "diagnostic only typeck table used")
};
typeck_tables_of_with_fallback(tcx, def_id, fallback)
}
}
}
+/// Given a `DefId` for an opaque type in return position, find its parent item's return
+/// expressions.
+fn get_owner_return_paths(
+ tcx: TyCtxt<'tcx>,
+ def_id: LocalDefId,
+) -> Option<(hir::HirId, ReturnsVisitor<'tcx>)> {
+ let hir_id = tcx.hir().as_local_hir_id(def_id);
+ let id = tcx.hir().get_parent_item(hir_id);
+ tcx.hir()
+ .find(id)
+ .map(|n| (id, n))
+ .and_then(|(hir_id, node)| node.body_id().map(|b| (hir_id, b)))
+ .map(|(hir_id, body_id)| {
+ let body = tcx.hir().body(body_id);
+ let mut visitor = ReturnsVisitor::default();
+ visitor.visit_body(body);
+ (hir_id, visitor)
+ })
+}
+
+/// Emit an error for recursive opaque types.
+///
+/// If this is a return `impl Trait`, find the item's return expressions and point at them. For
+/// direct recursion this is enough, but for indirect recursion also point at the last intermediary
+/// `impl Trait`.
+///
+/// If all the return expressions evaluate to `!`, then we explain that the error will go away
+/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
+fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
+ let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
+
+ let mut label = false;
+ if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) {
+ let tables = tcx.typeck_tables_of(tcx.hir().local_def_id(hir_id));
+ if visitor
+ .returns
+ .iter()
+ .filter_map(|expr| tables.node_type_opt(expr.hir_id))
+ .all(|ty| matches!(ty.kind, ty::Never))
+ {
+ let spans = visitor
+ .returns
+ .iter()
+ .filter(|expr| tables.node_type_opt(expr.hir_id).is_some())
+ .map(|expr| expr.span)
+ .collect::<Vec<Span>>();
+ let span_len = spans.len();
+ if span_len == 1 {
+ err.span_label(spans[0], "this returned value is of `!` type");
+ } else {
+ let mut multispan: MultiSpan = spans.clone().into();
+ for span in spans {
+ multispan
+ .push_span_label(span, "this returned value is of `!` type".to_string());
+ }
+ err.span_note(multispan, "these returned values have a concrete \"never\" type");
+ }
+ err.help("this error will resolve once the item's body returns a concrete type");
+ } else {
+ let mut seen = FxHashSet::default();
+ seen.insert(span);
+ err.span_label(span, "recursive opaque type");
+ label = true;
+ for (sp, ty) in visitor
+ .returns
+ .iter()
+ .filter_map(|e| tables.node_type_opt(e.hir_id).map(|t| (e.span, t)))
+ .filter(|(_, ty)| !matches!(ty.kind, ty::Never))
+ {
+ struct VisitTypes(Vec<DefId>);
+ impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes {
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+ match t.kind {
+ ty::Opaque(def, _) => {
+ self.0.push(def);
+ false
+ }
+ _ => t.super_visit_with(self),
+ }
+ }
+ }
+ let mut visitor = VisitTypes(vec![]);
+ ty.visit_with(&mut visitor);
+ for def_id in visitor.0 {
+ let ty_span = tcx.def_span(def_id);
+ if !seen.contains(&ty_span) {
+ err.span_label(ty_span, &format!("returning this opaque type `{}`", ty));
+ seen.insert(ty_span);
+ }
+ err.span_label(sp, &format!("returning here with type `{}`", ty));
+ }
+ }
+ }
+ }
+ if !label {
+ err.span_label(span, "cannot resolve opaque type");
+ }
+ err.emit();
+}
+
+/// Emit an error for recursive opaque types in a `let` binding.
+fn binding_opaque_type_cycle_error(
+ tcx: TyCtxt<'tcx>,
+ def_id: LocalDefId,
+ span: Span,
+ partially_expanded_type: Ty<'tcx>,
+) {
+ let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
+ err.span_label(span, "cannot resolve opaque type");
+ // Find the the owner that declared this `impl Trait` type.
+ let hir_id = tcx.hir().as_local_hir_id(def_id);
+ let mut prev_hir_id = hir_id;
+ let mut hir_id = tcx.hir().get_parent_node(hir_id);
+ while let Some(node) = tcx.hir().find(hir_id) {
+ match node {
+ hir::Node::Local(hir::Local {
+ pat,
+ init: None,
+ ty: Some(ty),
+ source: hir::LocalSource::Normal,
+ ..
+ }) => {
+ err.span_label(pat.span, "this binding might not have a concrete type");
+ err.span_suggestion_verbose(
+ ty.span.shrink_to_hi(),
+ "set the binding to a value for a concrete type to be resolved",
+ " = /* value */".to_string(),
+ Applicability::HasPlaceholders,
+ );
+ }
+ hir::Node::Local(hir::Local {
+ init: Some(expr),
+ source: hir::LocalSource::Normal,
+ ..
+ }) => {
+ let hir_id = tcx.hir().as_local_hir_id(def_id);
+ let tables =
+ tcx.typeck_tables_of(tcx.hir().local_def_id(tcx.hir().get_parent_item(hir_id)));
+ if let Some(ty) = tables.node_type_opt(expr.hir_id) {
+ err.span_label(
+ expr.span,
+ &format!(
+ "this is of type `{}`, which doesn't constrain \
+ `{}` enough to arrive to a concrete type",
+ ty, partially_expanded_type
+ ),
+ );
+ }
+ }
+ _ => {}
+ }
+ if prev_hir_id == hir_id {
+ break;
+ }
+ prev_hir_id = hir_id;
+ hir_id = tcx.hir().get_parent_node(hir_id);
+ }
+ err.emit();
+}
+
+fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) {
+ struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
+ .span_label(span, "recursive `async fn`")
+ .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
+ .emit();
+}
+
/// Checks that an opaque type does not contain cycles.
fn check_opaque_for_cycles<'tcx>(
tcx: TyCtxt<'tcx>,
) {
if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs)
{
- if let hir::OpaqueTyOrigin::AsyncFn = origin {
- struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing",)
- .span_label(span, "recursive `async fn`")
- .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
- .emit();
- } else {
- let mut err =
- struct_span_err!(tcx.sess, span, E0720, "opaque type expands to a recursive type",);
- err.span_label(span, "expands to a recursive type");
- if let ty::Opaque(..) = partially_expanded_type.kind {
- err.note("type resolves to itself");
- } else {
- err.note(&format!("expanded type is `{}`", partially_expanded_type));
+ match origin {
+ hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span),
+ hir::OpaqueTyOrigin::Binding => {
+ binding_opaque_type_cycle_error(tcx, def_id, span, partially_expanded_type)
}
- err.emit();
+ _ => opaque_type_cycle_error(tcx, def_id, span),
}
}
}
&ty_trait_item,
impl_trait_ref,
opt_trait_span,
- )
+ );
} else {
let mut err = struct_span_err!(
tcx.sess,
return;
}
+ let autoborrow_mut = adj.iter().any(|adj| {
+ matches!(adj, &Adjustment {
+ kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })),
+ ..
+ })
+ });
+
match self.tables.borrow_mut().adjustments_mut().entry(expr.hir_id) {
Entry::Vacant(entry) => {
entry.insert(adj);
*entry.get_mut() = adj;
}
}
+
+ // If there is an mutable auto-borrow, it is equivalent to `&mut <expr>`.
+ // In this case implicit use of `Deref` and `Index` within `<expr>` should
+ // instead be `DerefMut` and `IndexMut`, so fix those up.
+ if autoborrow_mut {
+ self.convert_place_derefs_to_mutable(expr);
+ }
}
/// Basically whenever we are converting from a type scheme into
pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
match self.tables.borrow().node_types().get(id) {
Some(&t) => t,
- None if self.is_tainted_by_errors() => self.tcx.types.err,
+ None if self.is_tainted_by_errors() => self.tcx.ty_error(),
None => {
bug!(
"no type for node {}: {} in fcx {}",
assert!(ty.is_ty_infer());
let fallback = match self.type_is_unconstrained_numeric(ty) {
- _ if self.is_tainted_by_errors() => self.tcx().types.err,
+ _ if self.is_tainted_by_errors() => self.tcx().ty_error(),
UnconstrainedInt => self.tcx.types.i32,
UnconstrainedFloat => self.tcx.types.f64,
Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
ret_ty.builtin_deref(true).unwrap()
}
- fn lookup_indexing(
- &self,
- expr: &hir::Expr<'_>,
- base_expr: &'tcx hir::Expr<'tcx>,
- base_ty: Ty<'tcx>,
- idx_ty: Ty<'tcx>,
- needs: Needs,
- ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
- // FIXME(#18741) -- this is almost but not quite the same as the
- // autoderef that normal method probing does. They could likely be
- // consolidated.
-
- let mut autoderef = self.autoderef(base_expr.span, base_ty);
- let mut result = None;
- while result.is_none() && autoderef.next().is_some() {
- result = self.try_index_step(expr, base_expr, &autoderef, needs, idx_ty);
- }
- autoderef.finalize(self);
- result
- }
-
- /// To type-check `base_expr[index_expr]`, we progressively autoderef
- /// (and otherwise adjust) `base_expr`, looking for a type which either
- /// supports builtin indexing or overloaded indexing.
- /// This loop implements one step in that search; the autoderef loop
- /// is implemented by `lookup_indexing`.
- fn try_index_step(
- &self,
- expr: &hir::Expr<'_>,
- base_expr: &hir::Expr<'_>,
- autoderef: &Autoderef<'a, 'tcx>,
- needs: Needs,
- index_ty: Ty<'tcx>,
- ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
- let adjusted_ty = autoderef.unambiguous_final_ty(self);
- debug!(
- "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
- index_ty={:?})",
- expr, base_expr, adjusted_ty, index_ty
- );
-
- for &unsize in &[false, true] {
- let mut self_ty = adjusted_ty;
- if unsize {
- // We only unsize arrays here.
- if let ty::Array(element_ty, _) = adjusted_ty.kind {
- self_ty = self.tcx.mk_slice(element_ty);
- } else {
- continue;
- }
- }
-
- // If some lookup succeeds, write callee into table and extract index/element
- // type from the method signature.
- // If some lookup succeeded, install method in table
- let input_ty = self.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::AutoDeref,
- span: base_expr.span,
- });
- let method = self.try_overloaded_place_op(
- expr.span,
- self_ty,
- &[input_ty],
- needs,
- PlaceOp::Index,
- );
-
- let result = method.map(|ok| {
- debug!("try_index_step: success, using overloaded indexing");
- let method = self.register_infer_ok_obligations(ok);
-
- let mut adjustments = autoderef.adjust_steps(self, needs);
- if let ty::Ref(region, _, r_mutbl) = method.sig.inputs()[0].kind {
- let mutbl = match r_mutbl {
- hir::Mutability::Not => AutoBorrowMutability::Not,
- hir::Mutability::Mut => AutoBorrowMutability::Mut {
- // Indexing can be desugared to a method call,
- // so maybe we could use two-phase here.
- // See the documentation of AllowTwoPhase for why that's
- // not the case today.
- allow_two_phase_borrow: AllowTwoPhase::No,
- },
- };
- adjustments.push(Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
- target: self
- .tcx
- .mk_ref(region, ty::TypeAndMut { mutbl: r_mutbl, ty: adjusted_ty }),
- });
- }
- if unsize {
- adjustments.push(Adjustment {
- kind: Adjust::Pointer(PointerCast::Unsize),
- target: method.sig.inputs()[0],
- });
- }
- self.apply_adjustments(base_expr, adjustments);
-
- self.write_method_call(expr.hir_id, method);
- (input_ty, self.make_overloaded_place_return_type(method).ty)
- });
- if result.is_some() {
- return result;
- }
- }
-
- None
- }
-
- fn resolve_place_op(&self, op: PlaceOp, is_mut: bool) -> (Option<DefId>, Ident) {
- let (tr, name) = match (op, is_mut) {
- (PlaceOp::Deref, false) => (self.tcx.lang_items().deref_trait(), sym::deref),
- (PlaceOp::Deref, true) => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut),
- (PlaceOp::Index, false) => (self.tcx.lang_items().index_trait(), sym::index),
- (PlaceOp::Index, true) => (self.tcx.lang_items().index_mut_trait(), sym::index_mut),
- };
- (tr, Ident::with_dummy_span(name))
- }
-
- fn try_overloaded_place_op(
- &self,
- span: Span,
- base_ty: Ty<'tcx>,
- arg_tys: &[Ty<'tcx>],
- needs: Needs,
- op: PlaceOp,
- ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
- debug!("try_overloaded_place_op({:?},{:?},{:?},{:?})", span, base_ty, needs, op);
-
- // Try Mut first, if needed.
- let (mut_tr, mut_op) = self.resolve_place_op(op, true);
- let method = match (needs, mut_tr) {
- (Needs::MutPlace, Some(trait_did)) => {
- self.lookup_method_in_trait(span, mut_op, trait_did, base_ty, Some(arg_tys))
- }
- _ => None,
- };
-
- // Otherwise, fall back to the immutable version.
- let (imm_tr, imm_op) = self.resolve_place_op(op, false);
- match (method, imm_tr) {
- (None, Some(trait_did)) => {
- self.lookup_method_in_trait(span, imm_op, trait_did, base_ty, Some(arg_tys))
- }
- (method, _) => method,
- }
- }
-
fn check_method_argument_types(
&self,
sp: Span,
tuple_arguments,
None,
);
- return self.tcx.types.err;
+ return self.tcx.ty_error();
}
let method = method.unwrap();
}
fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
- vec![self.tcx.types.err; len]
+ vec![self.tcx.ty_error(); len]
}
/// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk
opt_ty.unwrap_or_else(|| self.next_float_var())
}
ast::LitKind::Bool(_) => tcx.types.bool,
- ast::LitKind::Err(_) => tcx.types.err,
+ ast::LitKind::Err(_) => tcx.ty_error(),
}
}
};
let result =
AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true);
- let ty = result.map(|(ty, _, _)| ty).unwrap_or(self.tcx().types.err);
+ let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
let result = result.map(|(_, kind, def_id)| (kind, def_id));
// Write back the new resolution.
ty: Ty<'tcx>,
) {
if ty.references_error() {
- // Override the types everywhere with `types.err` to avoid knock on errors.
+ // Override the types everywhere with `err()` to avoid knock on errors.
self.write_ty(local.hir_id, ty);
self.write_ty(local.pat.hir_id, ty);
let local_ty = LocalTy { decl_ty, revealed_ty: ty };
let mut ty = ctxt.coerce.unwrap().complete(self);
if self.has_errors.get() || ty.references_error() {
- ty = self.tcx.types.err
+ ty = self.tcx.ty_error()
}
self.write_ty(blk.hir_id, ty);
}
}
+ fn note_need_for_fn_pointer(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ expected: Ty<'tcx>,
+ found: Ty<'tcx>,
+ ) {
+ let (sig, did, substs) = match (&expected.kind, &found.kind) {
+ (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
+ let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
+ let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
+ if sig1 != sig2 {
+ return;
+ }
+ err.note(
+ "different `fn` items always have unique types, even if their signatures are \
+ the same",
+ );
+ (sig1, *did1, substs1)
+ }
+ (ty::FnDef(did, substs), ty::FnPtr(sig2)) => {
+ let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs);
+ if sig1 != *sig2 {
+ return;
+ }
+ (sig1, *did, substs)
+ }
+ _ => return,
+ };
+ err.help(&format!("change the expected type to be function pointer `{}`", sig));
+ err.help(&format!(
+ "if the expected type is due to type inference, cast the expected `fn` to a function \
+ pointer: `{} as {}`",
+ self.tcx.def_path_str_with_substs(did, substs),
+ sig
+ ));
+ }
+
/// A common error is to add an extra semicolon:
///
/// ```
_ => return None,
};
let last_expr_ty = self.node_ty(last_expr.hir_id);
- if matches!(last_expr_ty.kind, ty::Error)
+ if matches!(last_expr_ty.kind, ty::Error(_))
|| self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err()
{
return None;
}
err.emit();
- return (tcx.types.err, res);
+ return (tcx.ty_error(), res);
}
}
} else {
.note("type must be known at this point")
.emit();
}
- self.demand_suptype(sp, self.tcx.types.err, ty);
- self.tcx.types.err
+ let err = self.tcx.ty_error();
+ self.demand_suptype(sp, err, ty);
+ err
}
}
//! Code related to processing overloaded binary and unary operators.
use super::method::MethodCallee;
-use super::{FnCtxt, Needs};
+use super::FnCtxt;
use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
};
+use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, Uint};
-use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{
+ self, suggest_constraining_type_param, Ty, TyCtxt, TypeFoldable, TypeVisitor,
+};
use rustc_span::symbol::Ident;
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
// trait matching creating lifetime constraints that are too strict.
// e.g., adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result
// in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`.
- let lhs_ty = self.check_expr_with_needs(lhs_expr, Needs::None);
+ let lhs_ty = self.check_expr(lhs_expr);
let fresh_var = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span: lhs_expr.span,
// equivalence on the LHS of an assign-op like `+=`;
// overwritten or mutably-borrowed places cannot be
// coerced to a supertype.
- self.check_expr_with_needs(lhs_expr, Needs::MutPlace)
+ self.check_expr(lhs_expr)
}
};
let lhs_ty = self.resolve_vars_with_obligations(lhs_ty);
method.sig.output()
}
+ // error types are considered "builtin"
+ Err(()) if lhs_ty.references_error() || rhs_ty.references_error() => {
+ self.tcx.ty_error()
+ }
Err(()) => {
- // error types are considered "builtin"
- if !lhs_ty.references_error() && !rhs_ty.references_error() {
- let source_map = self.tcx.sess.source_map();
-
- match is_assign {
- IsAssign::Yes => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- expr.span,
- E0368,
- "binary assignment operation `{}=` cannot be applied to type `{}`",
- op.node.as_str(),
+ let source_map = self.tcx.sess.source_map();
+ let (mut err, missing_trait, use_output, involves_fn) = match is_assign {
+ IsAssign::Yes => {
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ expr.span,
+ E0368,
+ "binary assignment operation `{}=` cannot be applied to type `{}`",
+ op.node.as_str(),
+ lhs_ty,
+ );
+ err.span_label(
+ lhs_expr.span,
+ format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty),
+ );
+ let missing_trait = match op.node {
+ hir::BinOpKind::Add => Some("std::ops::AddAssign"),
+ hir::BinOpKind::Sub => Some("std::ops::SubAssign"),
+ hir::BinOpKind::Mul => Some("std::ops::MulAssign"),
+ hir::BinOpKind::Div => Some("std::ops::DivAssign"),
+ hir::BinOpKind::Rem => Some("std::ops::RemAssign"),
+ hir::BinOpKind::BitAnd => Some("std::ops::BitAndAssign"),
+ hir::BinOpKind::BitXor => Some("std::ops::BitXorAssign"),
+ hir::BinOpKind::BitOr => Some("std::ops::BitOrAssign"),
+ hir::BinOpKind::Shl => Some("std::ops::ShlAssign"),
+ hir::BinOpKind::Shr => Some("std::ops::ShrAssign"),
+ _ => None,
+ };
+ (err, missing_trait, false, false)
+ }
+ IsAssign::No => {
+ let (message, missing_trait, use_output) = match op.node {
+ hir::BinOpKind::Add => (
+ format!("cannot add `{}` to `{}`", rhs_ty, lhs_ty),
+ Some("std::ops::Add"),
+ true,
+ ),
+ hir::BinOpKind::Sub => (
+ format!("cannot subtract `{}` from `{}`", rhs_ty, lhs_ty),
+ Some("std::ops::Sub"),
+ true,
+ ),
+ hir::BinOpKind::Mul => (
+ format!("cannot multiply `{}` to `{}`", rhs_ty, lhs_ty),
+ Some("std::ops::Mul"),
+ true,
+ ),
+ hir::BinOpKind::Div => (
+ format!("cannot divide `{}` by `{}`", lhs_ty, rhs_ty),
+ Some("std::ops::Div"),
+ true,
+ ),
+ hir::BinOpKind::Rem => (
+ format!("cannot mod `{}` by `{}`", lhs_ty, rhs_ty),
+ Some("std::ops::Rem"),
+ true,
+ ),
+ hir::BinOpKind::BitAnd => (
+ format!("no implementation for `{} & {}`", lhs_ty, rhs_ty),
+ Some("std::ops::BitAnd"),
+ true,
+ ),
+ hir::BinOpKind::BitXor => (
+ format!("no implementation for `{} ^ {}`", lhs_ty, rhs_ty),
+ Some("std::ops::BitXor"),
+ true,
+ ),
+ hir::BinOpKind::BitOr => (
+ format!("no implementation for `{} | {}`", lhs_ty, rhs_ty),
+ Some("std::ops::BitOr"),
+ true,
+ ),
+ hir::BinOpKind::Shl => (
+ format!("no implementation for `{} << {}`", lhs_ty, rhs_ty),
+ Some("std::ops::Shl"),
+ true,
+ ),
+ hir::BinOpKind::Shr => (
+ format!("no implementation for `{} >> {}`", lhs_ty, rhs_ty),
+ Some("std::ops::Shr"),
+ true,
+ ),
+ hir::BinOpKind::Eq | hir::BinOpKind::Ne => (
+ format!(
+ "binary operation `{}` cannot be applied to type `{}`",
+ op.node.as_str(),
+ lhs_ty
+ ),
+ Some("std::cmp::PartialEq"),
+ false,
+ ),
+ hir::BinOpKind::Lt
+ | hir::BinOpKind::Le
+ | hir::BinOpKind::Gt
+ | hir::BinOpKind::Ge => (
+ format!(
+ "binary operation `{}` cannot be applied to type `{}`",
+ op.node.as_str(),
+ lhs_ty
+ ),
+ Some("std::cmp::PartialOrd"),
+ false,
+ ),
+ _ => (
+ format!(
+ "binary operation `{}` cannot be applied to type `{}`",
+ op.node.as_str(),
+ lhs_ty
+ ),
+ None,
+ false,
+ ),
+ };
+ let mut err =
+ struct_span_err!(self.tcx.sess, op.span, E0369, "{}", message.as_str());
+ let mut involves_fn = false;
+ if !lhs_expr.span.eq(&rhs_expr.span) {
+ involves_fn |= self.add_type_neq_err_label(
+ &mut err,
+ lhs_expr.span,
lhs_ty,
+ rhs_ty,
+ op,
+ is_assign,
);
- err.span_label(
- lhs_expr.span,
- format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty),
+ involves_fn |= self.add_type_neq_err_label(
+ &mut err,
+ rhs_expr.span,
+ rhs_ty,
+ lhs_ty,
+ op,
+ is_assign,
);
- let mut suggested_deref = false;
- if let Ref(_, rty, _) = lhs_ty.kind {
- if {
- self.infcx.type_is_copy_modulo_regions(
- self.param_env,
- rty,
- lhs_expr.span,
- ) && self
- .lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign))
- .is_ok()
- } {
- if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
- let msg = &format!(
- "`{}=` can be used on '{}', you can dereference `{}`",
- op.node.as_str(),
- rty.peel_refs(),
- lstring,
- );
- err.span_suggestion(
- lhs_expr.span,
- msg,
- format!("*{}", lstring),
- rustc_errors::Applicability::MachineApplicable,
- );
- suggested_deref = true;
- }
- }
- }
- let missing_trait = match op.node {
- hir::BinOpKind::Add => Some("std::ops::AddAssign"),
- hir::BinOpKind::Sub => Some("std::ops::SubAssign"),
- hir::BinOpKind::Mul => Some("std::ops::MulAssign"),
- hir::BinOpKind::Div => Some("std::ops::DivAssign"),
- hir::BinOpKind::Rem => Some("std::ops::RemAssign"),
- hir::BinOpKind::BitAnd => Some("std::ops::BitAndAssign"),
- hir::BinOpKind::BitXor => Some("std::ops::BitXorAssign"),
- hir::BinOpKind::BitOr => Some("std::ops::BitOrAssign"),
- hir::BinOpKind::Shl => Some("std::ops::ShlAssign"),
- hir::BinOpKind::Shr => Some("std::ops::ShrAssign"),
- _ => None,
- };
- if let Some(missing_trait) = missing_trait {
- if op.node == hir::BinOpKind::Add
- && self.check_str_addition(
- lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, true, op,
- )
- {
- // This has nothing here because it means we did string
- // concatenation (e.g., "Hello " += "World!"). This means
- // we don't want the note in the else clause to be emitted
- } else if let ty::Param(p) = lhs_ty.kind {
- suggest_constraining_param(
- self.tcx,
- self.body_id,
- &mut err,
- lhs_ty,
- rhs_ty,
- missing_trait,
- p,
- false,
- );
- } else if !suggested_deref {
- suggest_impl_missing(&mut err, lhs_ty, &missing_trait);
- }
- }
- err.emit();
}
- IsAssign::No => {
- let (message, missing_trait, use_output) = match op.node {
- hir::BinOpKind::Add => (
- format!("cannot add `{}` to `{}`", rhs_ty, lhs_ty),
- Some("std::ops::Add"),
- true,
- ),
- hir::BinOpKind::Sub => (
- format!("cannot subtract `{}` from `{}`", rhs_ty, lhs_ty),
- Some("std::ops::Sub"),
- true,
- ),
- hir::BinOpKind::Mul => (
- format!("cannot multiply `{}` to `{}`", rhs_ty, lhs_ty),
- Some("std::ops::Mul"),
- true,
- ),
- hir::BinOpKind::Div => (
- format!("cannot divide `{}` by `{}`", lhs_ty, rhs_ty),
- Some("std::ops::Div"),
- true,
- ),
- hir::BinOpKind::Rem => (
- format!("cannot mod `{}` by `{}`", lhs_ty, rhs_ty),
- Some("std::ops::Rem"),
- true,
- ),
- hir::BinOpKind::BitAnd => (
- format!("no implementation for `{} & {}`", lhs_ty, rhs_ty),
- Some("std::ops::BitAnd"),
- true,
- ),
- hir::BinOpKind::BitXor => (
- format!("no implementation for `{} ^ {}`", lhs_ty, rhs_ty),
- Some("std::ops::BitXor"),
- true,
- ),
- hir::BinOpKind::BitOr => (
- format!("no implementation for `{} | {}`", lhs_ty, rhs_ty),
- Some("std::ops::BitOr"),
- true,
- ),
- hir::BinOpKind::Shl => (
- format!("no implementation for `{} << {}`", lhs_ty, rhs_ty),
- Some("std::ops::Shl"),
- true,
- ),
- hir::BinOpKind::Shr => (
- format!("no implementation for `{} >> {}`", lhs_ty, rhs_ty),
- Some("std::ops::Shr"),
- true,
- ),
- hir::BinOpKind::Eq | hir::BinOpKind::Ne => (
- format!(
- "binary operation `{}` cannot be applied to type `{}`",
- op.node.as_str(),
- lhs_ty
- ),
- Some("std::cmp::PartialEq"),
- false,
- ),
- hir::BinOpKind::Lt
- | hir::BinOpKind::Le
- | hir::BinOpKind::Gt
- | hir::BinOpKind::Ge => (
- format!(
- "binary operation `{}` cannot be applied to type `{}`",
- op.node.as_str(),
- lhs_ty
- ),
- Some("std::cmp::PartialOrd"),
- false,
- ),
- _ => (
- format!(
- "binary operation `{}` cannot be applied to type `{}`",
- op.node.as_str(),
- lhs_ty
- ),
- None,
- false,
- ),
- };
- let mut err = struct_span_err!(
- self.tcx.sess,
- op.span,
- E0369,
- "{}",
- message.as_str()
+ (err, missing_trait, use_output, involves_fn)
+ }
+ };
+ let mut suggested_deref = false;
+ if let Ref(_, rty, _) = lhs_ty.kind {
+ if {
+ self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span)
+ && self
+ .lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign))
+ .is_ok()
+ } {
+ if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
+ let msg = &format!(
+ "`{}{}` can be used on `{}`, you can dereference `{}`",
+ op.node.as_str(),
+ match is_assign {
+ IsAssign::Yes => "=",
+ IsAssign::No => "",
+ },
+ rty.peel_refs(),
+ lstring,
);
-
- let mut involves_fn = false;
- if !lhs_expr.span.eq(&rhs_expr.span) {
- involves_fn |= self.add_type_neq_err_label(
- &mut err,
- lhs_expr.span,
- lhs_ty,
- rhs_ty,
- op,
- is_assign,
- );
- involves_fn |= self.add_type_neq_err_label(
+ err.span_suggestion_verbose(
+ lhs_expr.span.shrink_to_lo(),
+ msg,
+ "*".to_string(),
+ rustc_errors::Applicability::MachineApplicable,
+ );
+ suggested_deref = true;
+ }
+ }
+ }
+ if let Some(missing_trait) = missing_trait {
+ let mut visitor = TypeParamVisitor(vec![]);
+ visitor.visit_ty(lhs_ty);
+
+ if op.node == hir::BinOpKind::Add
+ && self.check_str_addition(
+ lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, is_assign, op,
+ )
+ {
+ // This has nothing here because it means we did string
+ // concatenation (e.g., "Hello " + "World!"). This means
+ // we don't want the note in the else clause to be emitted
+ } else if let [ty] = &visitor.0[..] {
+ if let ty::Param(p) = ty.kind {
+ // Check if the method would be found if the type param wasn't
+ // involved. If so, it means that adding a trait bound to the param is
+ // enough. Otherwise we do not give the suggestion.
+ let mut eraser = TypeParamEraser(&self, expr.span);
+ let needs_bound = self
+ .lookup_op_method(
+ eraser.fold_ty(lhs_ty),
+ &[eraser.fold_ty(rhs_ty)],
+ Op::Binary(op, is_assign),
+ )
+ .is_ok();
+ if needs_bound {
+ suggest_constraining_param(
+ self.tcx,
+ self.body_id,
&mut err,
- rhs_expr.span,
+ ty,
rhs_ty,
- lhs_ty,
- op,
- is_assign,
+ missing_trait,
+ p,
+ use_output,
);
+ } else if *ty != lhs_ty {
+ // When we know that a missing bound is responsible, we don't show
+ // this note as it is redundant.
+ err.note(&format!(
+ "the trait `{}` is not implemented for `{}`",
+ missing_trait, lhs_ty
+ ));
}
-
- let mut suggested_deref = false;
- if let Ref(_, rty, _) = lhs_ty.kind {
- if {
- self.infcx.type_is_copy_modulo_regions(
- self.param_env,
- rty,
- lhs_expr.span,
- ) && self
- .lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign))
- .is_ok()
- } {
- if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
- err.help(&format!(
- "`{}` can be used on '{}', you can \
- dereference `{2}`: `*{2}`",
- op.node.as_str(),
- rty.peel_refs(),
- lstring
- ));
- suggested_deref = true;
- }
- }
- }
- if let Some(missing_trait) = missing_trait {
- if op.node == hir::BinOpKind::Add
- && self.check_str_addition(
- lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, false, op,
- )
- {
- // This has nothing here because it means we did string
- // concatenation (e.g., "Hello " + "World!"). This means
- // we don't want the note in the else clause to be emitted
- } else if let ty::Param(p) = lhs_ty.kind {
- suggest_constraining_param(
- self.tcx,
- self.body_id,
- &mut err,
- lhs_ty,
- rhs_ty,
- missing_trait,
- p,
- use_output,
- );
- } else if !suggested_deref && !involves_fn {
- suggest_impl_missing(&mut err, lhs_ty, &missing_trait);
- }
- }
- err.emit();
+ } else {
+ bug!("type param visitor stored a non type param: {:?}", ty.kind);
}
+ } else if !suggested_deref && !involves_fn {
+ suggest_impl_missing(&mut err, lhs_ty, &missing_trait);
}
}
- self.tcx.types.err
+ err.emit();
+ self.tcx.ty_error()
}
};
lhs_ty: Ty<'tcx>,
rhs_ty: Ty<'tcx>,
err: &mut rustc_errors::DiagnosticBuilder<'_>,
- is_assign: bool,
+ is_assign: IsAssign,
op: hir::BinOp,
) -> bool {
let source_map = self.tcx.sess.source_map();
&format!("{:?}", rhs_ty) == "&&str"
) =>
{
- if !is_assign { // Do not supply this message if `&str += &str`
+ if let IsAssign::No = is_assign { // Do not supply this message if `&str += &str`
err.span_label(
op.span,
"`+` cannot be used to concatenate two `&str` strings",
source_map.span_to_snippet(rhs_expr.span),
is_assign,
) {
- (Ok(l), Ok(r), false) => {
+ (Ok(l), Ok(r), IsAssign::No) => {
let to_string = if l.starts_with('&') {
// let a = String::new(); let b = String::new();
// let _ = &a + b;
);
err.span_label(
ex.span,
- format!(
- "cannot apply unary \
- operator `{}`",
- op.as_str()
- ),
+ format!("cannot apply unary operator `{}`", op.as_str()),
);
match actual.kind {
Uint(_) if op == hir::UnOp::UnNeg => {
}
err.emit();
}
- self.tcx.types.err
+ self.tcx.ty_error()
}
}
}
if let Adt(def, _) = ty.peel_refs().kind {
if def.did.is_local() {
err.note(&format!(
- "an implementation of `{}` might \
- be missing for `{}`",
+ "an implementation of `{}` might be missing for `{}`",
missing_trait, ty
));
}
err.span_label(span, msg);
}
}
+
+struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>);
+
+impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
+ if let ty::Param(_) = ty.kind {
+ self.0.push(ty);
+ }
+ ty.super_visit_with(self)
+ }
+}
+
+struct TypeParamEraser<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, Span);
+
+impl TypeFolder<'tcx> for TypeParamEraser<'_, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.0.tcx
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ match ty.kind {
+ ty::Param(_) => self.0.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::MiscVariable,
+ span: self.1,
+ }),
+ _ => ty.super_fold_with(self),
+ }
+ }
+}
// errors in some cases, such as this one:
//
// ```
- // fn foo<'x>(x: &'x int) {
+ // fn foo<'x>(x: &'x i32) {
// let a = 1;
// let mut z = x;
// z = &a;
// ```
//
// The reason we might get an error is that `z` might be
- // assigned a type like `&'x int`, and then we would have
+ // assigned a type like `&'x i32`, and then we would have
// a problem when we try to assign `&a` to `z`, because
// the lifetime of `&a` (i.e., the enclosing block) is
// shorter than `'x`.
// expected type here is whatever type the user wrote, not
// the initializer's type. In this case the user wrote
// nothing, so we are going to create a type variable `Z`.
- // Then we will assign the type of the initializer (`&'x
- // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we
- // will instantiate `Z` as a type `&'0 int` where `'0` is
- // a fresh region variable, with the constraint that `'x :
- // '0`. So basically we're all set.
+ // Then we will assign the type of the initializer (`&'x i32`)
+ // as a subtype of `Z`: `&'x i32 <: Z`. And hence we
+ // will instantiate `Z` as a type `&'0 i32` where `'0` is
+ // a fresh region variable, with the constraint that `'x : '0`.
+ // So basically we're all set.
//
// Note that there are two tests to check that this remains true
// (`regions-reassign-{match,let}-bound-pointer.rs`).
// There exists a side that didn't meet our criteria that the end-point
// be of a numeric or char type, as checked in `calc_side` above.
self.emit_err_pat_range(span, lhs, rhs);
- return self.tcx.types.err;
+ return self.tcx.ty_error();
}
// Now that we know the types can be unified we find the unified type
{
variant_ty
} else {
+ let err = self.tcx.ty_error();
for field in fields {
let ti = TopInfo { parent_pat: Some(&pat), ..ti };
- self.check_pat(&field.pat, self.tcx.types.err, def_bm, ti);
+ self.check_pat(&field.pat, err, def_bm, ti);
}
- return self.tcx.types.err;
+ return err;
};
// Type-check the path.
if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, etc, def_bm, ti) {
pat_ty
} else {
- self.tcx.types.err
+ self.tcx.ty_error()
}
}
match res {
Res::Err => {
self.set_tainted_by_errors();
- return tcx.types.err;
+ return tcx.ty_error();
}
Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fictive | CtorKind::Fn), _) => {
report_unexpected_variant_res(tcx, res, pat.span);
- return tcx.types.err;
+ return tcx.ty_error();
}
Res::SelfCtor(..)
| Res::Def(
let on_error = || {
let parent_pat = Some(pat);
for pat in subpats {
- self.check_pat(&pat, tcx.types.err, def_bm, TopInfo { parent_pat, ..ti });
+ self.check_pat(&pat, tcx.ty_error(), def_bm, TopInfo { parent_pat, ..ti });
}
};
let report_unexpected_res = |res: Res| {
if res == Res::Err {
self.set_tainted_by_errors();
on_error();
- return self.tcx.types.err;
+ return self.tcx.ty_error();
}
// Type-check the path.
self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id);
if !pat_ty.is_fn() {
report_unexpected_res(res);
- return tcx.types.err;
+ return tcx.ty_error();
}
let variant = match res {
Res::Err => {
self.set_tainted_by_errors();
on_error();
- return tcx.types.err;
+ return tcx.ty_error();
}
Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
report_unexpected_res(res);
- return tcx.types.err;
+ return tcx.ty_error();
}
Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
_ => bug!("unexpected pattern resolution: {:?}", res),
// Pattern has wrong number of fields.
self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err);
on_error();
- return tcx.types.err;
+ return tcx.ty_error();
}
pat_ty
}
err.emit();
// Walk subpatterns with an expected type of `err` in this case to silence
// further errors being emitted when using the bindings. #50333
- let element_tys_iter = (0..max_len).map(|_| tcx.types.err);
+ let element_tys_iter = (0..max_len).map(|_| tcx.ty_error());
for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
- self.check_pat(elem, &tcx.types.err, def_bm, ti);
+ self.check_pat(elem, &tcx.ty_error(), def_bm, ti);
}
tcx.mk_tup(element_tys_iter)
} else {
Occupied(occupied) => {
self.error_field_already_bound(span, field.ident, *occupied.get());
no_field_errors = false;
- tcx.types.err
+ tcx.ty_error()
}
Vacant(vacant) => {
vacant.insert(span);
.unwrap_or_else(|| {
inexistent_fields.push(field.ident);
no_field_errors = false;
- tcx.types.err
+ tcx.ty_error()
})
}
};
self.demand_eqtype_pat(span, expected, box_ty, ti);
(box_ty, inner_ty)
} else {
- (tcx.types.err, tcx.types.err)
+ let err = tcx.ty_error();
+ (err, err)
};
self.check_pat(&inner, inner_ty, def_bm, ti);
box_ty
}
}
} else {
- (tcx.types.err, tcx.types.err)
+ let err = tcx.ty_error();
+ (err, err)
};
self.check_pat(&inner, inner_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti });
rptr_ty
if !expected.references_error() {
self.error_expected_array_or_slice(span, expected);
}
- let err = self.tcx.types.err;
+ let err = self.tcx.ty_error();
(err, Some(err), err)
}
};
}
// If we get here, we must have emitted an error.
- (Some(self.tcx.types.err), arr_ty)
+ (Some(self.tcx.ty_error()), arr_ty)
}
fn error_scrutinee_inconsistent_length(&self, span: Span, min_len: u64, size: u64) {
--- /dev/null
+use crate::check::method::MethodCallee;
+use crate::check::{FnCtxt, PlaceOp};
+use rustc_hir as hir;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::InferOk;
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast};
+use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::{self, Ty};
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::Span;
+use rustc_trait_selection::autoderef::Autoderef;
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+ /// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already.
+ pub(super) fn lookup_derefing(
+ &self,
+ expr: &hir::Expr<'_>,
+ oprnd_expr: &'tcx hir::Expr<'tcx>,
+ oprnd_ty: Ty<'tcx>,
+ ) -> Option<Ty<'tcx>> {
+ if let Some(mt) = oprnd_ty.builtin_deref(true) {
+ return Some(mt.ty);
+ }
+
+ let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?;
+ let method = self.register_infer_ok_obligations(ok);
+ if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind {
+ self.apply_adjustments(
+ oprnd_expr,
+ vec![Adjustment {
+ kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)),
+ target: method.sig.inputs()[0],
+ }],
+ );
+ } else {
+ span_bug!(expr.span, "input to deref is not a ref?");
+ }
+ let ty = self.make_overloaded_place_return_type(method).ty;
+ self.write_method_call(expr.hir_id, method);
+ Some(ty)
+ }
+
+ /// Type-check `*base_expr[index_expr]` with `base_expr` and `index_expr` type-checked already.
+ pub(super) fn lookup_indexing(
+ &self,
+ expr: &hir::Expr<'_>,
+ base_expr: &'tcx hir::Expr<'tcx>,
+ base_ty: Ty<'tcx>,
+ idx_ty: Ty<'tcx>,
+ ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
+ // FIXME(#18741) -- this is almost but not quite the same as the
+ // autoderef that normal method probing does. They could likely be
+ // consolidated.
+
+ let mut autoderef = self.autoderef(base_expr.span, base_ty);
+ let mut result = None;
+ while result.is_none() && autoderef.next().is_some() {
+ result = self.try_index_step(expr, base_expr, &autoderef, idx_ty);
+ }
+ self.register_predicates(autoderef.into_obligations());
+ result
+ }
+
+ /// To type-check `base_expr[index_expr]`, we progressively autoderef
+ /// (and otherwise adjust) `base_expr`, looking for a type which either
+ /// supports builtin indexing or overloaded indexing.
+ /// This loop implements one step in that search; the autoderef loop
+ /// is implemented by `lookup_indexing`.
+ fn try_index_step(
+ &self,
+ expr: &hir::Expr<'_>,
+ base_expr: &hir::Expr<'_>,
+ autoderef: &Autoderef<'a, 'tcx>,
+ index_ty: Ty<'tcx>,
+ ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
+ let adjusted_ty =
+ self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
+ debug!(
+ "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
+ index_ty={:?})",
+ expr, base_expr, adjusted_ty, index_ty
+ );
+
+ for &unsize in &[false, true] {
+ let mut self_ty = adjusted_ty;
+ if unsize {
+ // We only unsize arrays here.
+ if let ty::Array(element_ty, _) = adjusted_ty.kind {
+ self_ty = self.tcx.mk_slice(element_ty);
+ } else {
+ continue;
+ }
+ }
+
+ // If some lookup succeeds, write callee into table and extract index/element
+ // type from the method signature.
+ // If some lookup succeeded, install method in table
+ let input_ty = self.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::AutoDeref,
+ span: base_expr.span,
+ });
+ let method =
+ self.try_overloaded_place_op(expr.span, self_ty, &[input_ty], PlaceOp::Index);
+
+ let result = method.map(|ok| {
+ debug!("try_index_step: success, using overloaded indexing");
+ let method = self.register_infer_ok_obligations(ok);
+
+ let mut adjustments = self.adjust_steps(autoderef);
+ if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind {
+ adjustments.push(Adjustment {
+ kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)),
+ target: self.tcx.mk_ref(
+ region,
+ ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: adjusted_ty },
+ ),
+ });
+ } else {
+ span_bug!(expr.span, "input to index is not a ref?");
+ }
+ if unsize {
+ adjustments.push(Adjustment {
+ kind: Adjust::Pointer(PointerCast::Unsize),
+ target: method.sig.inputs()[0],
+ });
+ }
+ self.apply_adjustments(base_expr, adjustments);
+
+ self.write_method_call(expr.hir_id, method);
+ (input_ty, self.make_overloaded_place_return_type(method).ty)
+ });
+ if result.is_some() {
+ return result;
+ }
+ }
+
+ None
+ }
+
+ /// Try to resolve an overloaded place op. We only deal with the immutable
+ /// variant here (Deref/Index). In some contexts we would need the mutable
+ /// variant (DerefMut/IndexMut); those would be later converted by
+ /// `convert_place_derefs_to_mutable`.
+ pub(super) fn try_overloaded_place_op(
+ &self,
+ span: Span,
+ base_ty: Ty<'tcx>,
+ arg_tys: &[Ty<'tcx>],
+ op: PlaceOp,
+ ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
+ debug!("try_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
+
+ let (imm_tr, imm_op) = match op {
+ PlaceOp::Deref => (self.tcx.lang_items().deref_trait(), sym::deref),
+ PlaceOp::Index => (self.tcx.lang_items().index_trait(), sym::index),
+ };
+ imm_tr.and_then(|trait_did| {
+ self.lookup_method_in_trait(
+ span,
+ Ident::with_dummy_span(imm_op),
+ trait_did,
+ base_ty,
+ Some(arg_tys),
+ )
+ })
+ }
+
+ fn try_mutable_overloaded_place_op(
+ &self,
+ span: Span,
+ base_ty: Ty<'tcx>,
+ arg_tys: &[Ty<'tcx>],
+ op: PlaceOp,
+ ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
+ debug!("try_mutable_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
+
+ let (mut_tr, mut_op) = match op {
+ PlaceOp::Deref => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut),
+ PlaceOp::Index => (self.tcx.lang_items().index_mut_trait(), sym::index_mut),
+ };
+ mut_tr.and_then(|trait_did| {
+ self.lookup_method_in_trait(
+ span,
+ Ident::with_dummy_span(mut_op),
+ trait_did,
+ base_ty,
+ Some(arg_tys),
+ )
+ })
+ }
+
+ /// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index`
+ /// into `DerefMut` and `IndexMut` respectively.
+ ///
+ /// This is a second pass of typechecking derefs/indices. We need this we do not
+ /// always know whether a place needs to be mutable or not in the first pass.
+ /// This happens whether there is an implicit mutable reborrow, e.g. when the type
+ /// is used as the receiver of a method call.
+ pub fn convert_place_derefs_to_mutable(&self, expr: &hir::Expr<'_>) {
+ // Gather up expressions we want to munge.
+ let mut exprs = vec![expr];
+
+ loop {
+ match exprs.last().unwrap().kind {
+ hir::ExprKind::Field(ref expr, _)
+ | hir::ExprKind::Index(ref expr, _)
+ | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) => exprs.push(&expr),
+ _ => break,
+ }
+ }
+
+ debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
+
+ // Fix up autoderefs and derefs.
+ for (i, &expr) in exprs.iter().rev().enumerate() {
+ debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr);
+
+ // Fix up the autoderefs. Autorefs can only occur immediately preceding
+ // overloaded place ops, and will be fixed by them in order to get
+ // the correct region.
+ let mut source = self.node_ty(expr.hir_id);
+ // Do not mutate adjustments in place, but rather take them,
+ // and replace them after mutating them, to avoid having the
+ // tables borrowed during (`deref_mut`) method resolution.
+ let previous_adjustments =
+ self.tables.borrow_mut().adjustments_mut().remove(expr.hir_id);
+ if let Some(mut adjustments) = previous_adjustments {
+ for adjustment in &mut adjustments {
+ if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind {
+ if let Some(ok) = self.try_mutable_overloaded_place_op(
+ expr.span,
+ source,
+ &[],
+ PlaceOp::Deref,
+ ) {
+ let method = self.register_infer_ok_obligations(ok);
+ if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
+ *deref = OverloadedDeref { region, mutbl };
+ }
+ }
+ }
+ source = adjustment.target;
+ }
+ self.tables.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments);
+ }
+
+ match expr.kind {
+ hir::ExprKind::Index(ref base_expr, ref index_expr) => {
+ // We need to get the final type in case dereferences were needed for the trait
+ // to apply (#72002).
+ let index_expr_ty = self.tables.borrow().expr_ty_adjusted(index_expr);
+ self.convert_place_op_to_mutable(
+ PlaceOp::Index,
+ expr,
+ base_expr,
+ &[index_expr_ty],
+ );
+ }
+ hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base_expr) => {
+ self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr, &[]);
+ }
+ _ => {}
+ }
+ }
+ }
+
+ fn convert_place_op_to_mutable(
+ &self,
+ op: PlaceOp,
+ expr: &hir::Expr<'_>,
+ base_expr: &hir::Expr<'_>,
+ arg_tys: &[Ty<'tcx>],
+ ) {
+ debug!("convert_place_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys);
+ if !self.tables.borrow().is_method_call(expr) {
+ debug!("convert_place_op_to_mutable - builtin, nothing to do");
+ return;
+ }
+
+ // Need to deref because overloaded place ops take self by-reference.
+ let base_ty = self
+ .tables
+ .borrow()
+ .expr_ty_adjusted(base_expr)
+ .builtin_deref(false)
+ .expect("place op takes something that is not a ref")
+ .ty;
+
+ let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op);
+ let method = match method {
+ Some(ok) => self.register_infer_ok_obligations(ok),
+ // Couldn't find the mutable variant of the place op, keep the
+ // current, immutable version.
+ None => return,
+ };
+ debug!("convert_place_op_to_mutable: method={:?}", method);
+ self.write_method_call(expr.hir_id, method);
+
+ let region = if let ty::Ref(r, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind {
+ r
+ } else {
+ span_bug!(expr.span, "input to mutable place op is not a mut ref?");
+ };
+
+ // Convert the autoref in the base expr to mutable with the correct
+ // region and mutability.
+ let base_expr_ty = self.node_ty(base_expr.hir_id);
+ if let Some(adjustments) =
+ self.tables.borrow_mut().adjustments_mut().get_mut(base_expr.hir_id)
+ {
+ let mut source = base_expr_ty;
+ for adjustment in &mut adjustments[..] {
+ if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
+ debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment);
+ let mutbl = AutoBorrowMutability::Mut {
+ // Deref/indexing can be desugared to a method call,
+ // so maybe we could use two-phase here.
+ // See the documentation of AllowTwoPhase for why that's
+ // not the case today.
+ allow_two_phase_borrow: AllowTwoPhase::No,
+ };
+ adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
+ adjustment.target =
+ self.tcx.mk_ref(region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() });
+ }
+ source = adjustment.target;
+ }
+
+ // If we have an autoref followed by unsizing at the end, fix the unsize target.
+ if let [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }] =
+ adjustments[..]
+ {
+ *target = method.sig.inputs()[0];
+ }
+ }
+ }
+}
/// Invoked on any adjustments that occur. Checks that if this is a region pointer being
/// dereferenced, the lifetime of the pointer includes the deref expr.
- fn constrain_adjustments(&mut self, expr: &hir::Expr<'_>) -> mc::McResult<mc::Place<'tcx>> {
+ fn constrain_adjustments(
+ &mut self,
+ expr: &hir::Expr<'_>,
+ ) -> mc::McResult<mc::PlaceWithHirId<'tcx>> {
debug!("constrain_adjustments(expr={:?})", expr);
let mut place = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?;
fn check_safety_of_rvalue_destructor_if_necessary(
&mut self,
- place: &mc::Place<'tcx>,
+ place_with_id: &mc::PlaceWithHirId<'tcx>,
span: Span,
) {
- if let mc::PlaceBase::Rvalue = place.base {
- if place.projections.is_empty() {
- let typ = self.resolve_type(place.ty);
+ if let mc::PlaceBase::Rvalue = place_with_id.place.base {
+ if place_with_id.place.projections.is_empty() {
+ let typ = self.resolve_type(place_with_id.place.ty);
let body_id = self.body_id;
let _ = dropck::check_drop_obligations(self, typ, span, body_id);
}
/// Link lifetimes of any ref bindings in `root_pat` to the pointers found
/// in the discriminant, if needed.
- fn link_pattern(&self, discr_cmt: mc::Place<'tcx>, root_pat: &hir::Pat<'_>) {
+ fn link_pattern(&self, discr_cmt: mc::PlaceWithHirId<'tcx>, root_pat: &hir::Pat<'_>) {
debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat);
ignore_err!(self.with_mc(|mc| {
mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id }| {
fn link_autoref(
&self,
expr: &hir::Expr<'_>,
- expr_cmt: &mc::Place<'tcx>,
+ expr_cmt: &mc::PlaceWithHirId<'tcx>,
autoref: &adjustment::AutoBorrow<'tcx>,
) {
debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt);
span: Span,
id: hir::HirId,
mutbl: hir::Mutability,
- cmt_borrowed: &mc::Place<'tcx>,
+ cmt_borrowed: &mc::PlaceWithHirId<'tcx>,
) {
debug!(
"link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})",
span: Span,
borrow_region: ty::Region<'tcx>,
borrow_kind: ty::BorrowKind,
- borrow_place: &mc::Place<'tcx>,
+ borrow_place: &mc::PlaceWithHirId<'tcx>,
) {
- let origin = infer::DataBorrowed(borrow_place.ty, span);
- self.type_must_outlive(origin, borrow_place.ty, borrow_region);
+ let origin = infer::DataBorrowed(borrow_place.place.ty, span);
+ self.type_must_outlive(origin, borrow_place.place.ty, borrow_region);
- for pointer_ty in borrow_place.deref_tys() {
+ for pointer_ty in borrow_place.place.deref_tys() {
debug!(
"link_region(borrow_region={:?}, borrow_kind={:?}, pointer_ty={:?})",
borrow_region, borrow_kind, borrow_place
_ => assert!(pointer_ty.is_box(), "unexpected built-in deref type {}", pointer_ty),
}
}
- if let mc::PlaceBase::Upvar(upvar_id) = borrow_place.base {
+ if let mc::PlaceBase::Upvar(upvar_id) = borrow_place.place.base {
self.link_upvar_region(span, borrow_region, upvar_id);
}
}
let (closure_def_id, substs) = match ty.kind {
ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)),
ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)),
- ty::Error => {
+ ty::Error(_) => {
// #51714: skip analysis when we have already encountered type errors
return;
}
impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
fn adjust_upvar_borrow_kind_for_consume(
&mut self,
- place: &mc::Place<'tcx>,
+ place_with_id: &mc::PlaceWithHirId<'tcx>,
mode: euv::ConsumeMode,
) {
- debug!("adjust_upvar_borrow_kind_for_consume(place={:?}, mode={:?})", place, mode);
+ debug!(
+ "adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, mode={:?})",
+ place_with_id, mode
+ );
// we only care about moves
match mode {
}
let tcx = self.fcx.tcx;
- let upvar_id = if let PlaceBase::Upvar(upvar_id) = place.base {
+ let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
upvar_id
} else {
return;
self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnOnce,
- place.span,
+ tcx.hir().span(place_with_id.hir_id),
var_name(tcx, upvar_id.var_path.hir_id),
);
self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue);
}
- /// Indicates that `place` is being directly mutated (e.g., assigned
+ /// Indicates that `place_with_id` is being directly mutated (e.g., assigned
/// to). If the place is based on a by-ref upvar, this implies that
/// the upvar must be borrowed using an `&mut` borrow.
- fn adjust_upvar_borrow_kind_for_mut(&mut self, place: &mc::Place<'tcx>) {
- debug!("adjust_upvar_borrow_kind_for_mut(place={:?})", place);
+ fn adjust_upvar_borrow_kind_for_mut(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>) {
+ debug!("adjust_upvar_borrow_kind_for_mut(place_with_id={:?})", place_with_id);
- if let PlaceBase::Upvar(upvar_id) = place.base {
+ if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
let mut borrow_kind = ty::MutBorrow;
- for pointer_ty in place.deref_tys() {
+ for pointer_ty in place_with_id.place.deref_tys() {
match pointer_ty.kind {
// Raw pointers don't inherit mutability.
ty::RawPtr(_) => return,
_ => (),
}
}
- self.adjust_upvar_deref(upvar_id, place.span, borrow_kind);
+ self.adjust_upvar_deref(
+ upvar_id,
+ self.fcx.tcx.hir().span(place_with_id.hir_id),
+ borrow_kind,
+ );
}
}
- fn adjust_upvar_borrow_kind_for_unique(&mut self, place: &mc::Place<'tcx>) {
- debug!("adjust_upvar_borrow_kind_for_unique(place={:?})", place);
+ fn adjust_upvar_borrow_kind_for_unique(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>) {
+ debug!("adjust_upvar_borrow_kind_for_unique(place_with_id={:?})", place_with_id);
- if let PlaceBase::Upvar(upvar_id) = place.base {
- if place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
+ if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
+ if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
// Raw pointers don't inherit mutability.
return;
}
// for a borrowed pointer to be unique, its base must be unique
- self.adjust_upvar_deref(upvar_id, place.span, ty::UniqueImmBorrow);
+ self.adjust_upvar_deref(
+ upvar_id,
+ self.fcx.tcx.hir().span(place_with_id.hir_id),
+ ty::UniqueImmBorrow,
+ );
}
}
}
impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
- fn consume(&mut self, place: &mc::Place<'tcx>, mode: euv::ConsumeMode) {
- debug!("consume(place={:?},mode={:?})", place, mode);
- self.adjust_upvar_borrow_kind_for_consume(place, mode);
+ fn consume(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, mode: euv::ConsumeMode) {
+ debug!("consume(place_with_id={:?},mode={:?})", place_with_id, mode);
+ self.adjust_upvar_borrow_kind_for_consume(place_with_id, mode);
}
- fn borrow(&mut self, place: &mc::Place<'tcx>, bk: ty::BorrowKind) {
- debug!("borrow(place={:?}, bk={:?})", place, bk);
+ fn borrow(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, bk: ty::BorrowKind) {
+ debug!("borrow(place_with_id={:?}, bk={:?})", place_with_id, bk);
match bk {
ty::ImmBorrow => {}
ty::UniqueImmBorrow => {
- self.adjust_upvar_borrow_kind_for_unique(place);
+ self.adjust_upvar_borrow_kind_for_unique(place_with_id);
}
ty::MutBorrow => {
- self.adjust_upvar_borrow_kind_for_mut(place);
+ self.adjust_upvar_borrow_kind_for_mut(place_with_id);
}
}
}
- fn mutate(&mut self, assignee_place: &mc::Place<'tcx>) {
+ fn mutate(&mut self, assignee_place: &mc::PlaceWithHirId<'tcx>) {
debug!("mutate(assignee_place={:?})", assignee_place);
self.adjust_upvar_borrow_kind_for_mut(assignee_place);
);
if can_eq_self(potential_self_ty) {
- autoderef.finalize(fcx);
+ fcx.register_predicates(autoderef.into_obligations());
if let Some(mut err) =
fcx.demand_eqtype_with_origin(&cause, self_ty, potential_self_ty)
use crate::check::FnCtxt;
-use rustc_data_structures::sync::Lrc;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
-use rustc_hir::def_id::DefIdSet;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc_infer::infer::InferCtxt;
wbcx.visit_user_provided_sigs();
wbcx.visit_generator_interior_types();
- let used_trait_imports = mem::replace(
- &mut self.tables.borrow_mut().used_trait_imports,
- Lrc::new(DefIdSet::default()),
- );
+ let used_trait_imports = mem::take(&mut self.tables.borrow_mut().used_trait_imports);
debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
wbcx.tables.used_trait_imports = used_trait_imports;
// to access an unexistend index. We assume that more relevant errors will
// already have been emitted, so we only gate on this with an ICE if no
// error has been emitted. (#64638)
- self.tcx().sess.delay_span_bug(
+ self.fcx.tcx.ty_error_with_message(
e.span,
&format!("bad index {:?} for base: `{:?}`", index, base),
- );
- self.fcx.tcx.types.err
+ )
});
let index_ty = self.fcx.resolve_vars_if_possible(&index_ty);
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
self.report_type_error(t);
self.replaced_with_error = true;
- self.tcx().types.err
+ self.tcx().ty_error()
}
}
}
debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
self.report_const_error(ct);
self.replaced_with_error = true;
- self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: ct.ty })
+ self.tcx().const_error(ct.ty)
}
}
}
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability;
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint;
use rustc_span::{Span, Symbol};
pub fn check_crate(tcx: TyCtxt<'_>) {
- let mut used_trait_imports = DefIdSet::default();
+ let mut used_trait_imports = FxHashSet::default();
for &body_id in tcx.hir().krate().bodies.keys() {
let item_def_id = tcx.hir().body_owner_def_id(body_id);
let imports = tcx.used_trait_imports(item_def_id);
struct CheckVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
- used_trait_imports: DefIdSet,
+ used_trait_imports: FxHashSet<LocalDefId>,
}
impl CheckVisitor<'tcx> {
return;
}
- if self.used_trait_imports.contains(&def_id.to_def_id()) {
+ if self.used_trait_imports.contains(&def_id) {
return;
}
fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
// Destructors only work on nominal types.
- if let ty::Adt(..) | ty::Error = tcx.type_of(impl_did).kind {
+ if let ty::Adt(..) | ty::Error(_) = tcx.type_of(impl_did).kind {
return;
}
item.span,
);
}
- ty::Error => {}
+ ty::Error(_) => {}
_ => {
struct_span_err!(
self.tcx.sess,
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::mono::Linkage;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::Discr;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
+use rustc_session::config::SanitizerSet;
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
///////////////////////////////////////////////////////////////////////////
// Main entry point
-fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().visit_item_likes_in_module(
module_def_id,
&mut CollectItemTypesVisitor { tcx }.as_deep_visitor(),
}
fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
- self.tcx().sess.delay_span_bug(span, "bad placeholder type");
- self.tcx().types.err
+ self.tcx().ty_error_with_message(span, "bad_placeholder_type")
}
fn ct_infer(
span: Span,
) -> &'tcx Const<'tcx> {
bad_placeholder_type(self.tcx(), vec![span]).emit();
-
- self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty })
+ self.tcx().const_error(ty)
}
fn projected_ty_from_poly_trait_ref(
_ => {}
}
err.emit();
- self.tcx().types.err
+ self.tcx().ty_error()
}
}
visitor.visit_ty(ty);
let mut diag = bad_placeholder_type(tcx, visitor.0);
let ret_ty = fn_sig.output();
- if ret_ty != tcx.types.err {
+ if ret_ty != tcx.ty_error() {
diag.span_suggestion(
ty.span,
"replace with the correct return type",
let mut is_trait = None;
let mut is_default_impl_trait = None;
+ let mut is_trait_associated_type = None;
let icx = ItemCtxt::new(tcx, def_id);
let constness = icx.default_constness_for_trait_bounds();
let mut predicates = UniquePredicates::new();
let ast_generics = match node {
- Node::TraitItem(item) => &item.generics,
+ Node::TraitItem(item) => {
+ if let hir::TraitItemKind::Type(bounds, _) = item.kind {
+ is_trait_associated_type = Some((bounds, item.span));
+ }
+ &item.generics
+ }
Node::ImplItem(item) => &item.generics,
}
}
- // Add predicates from associated type bounds.
- if let Some((self_trait_ref, trait_items)) = is_trait {
+ // Add predicates from associated type bounds (`type X: Bound`)
+ if tcx.features().generic_associated_types {
+ // New behavior: bounds declared on associate type are predicates of that
+ // associated type. Not the default because it needs more testing.
+ if let Some((bounds, span)) = is_trait_associated_type {
+ let projection_ty =
+ tcx.mk_projection(def_id, InternalSubsts::identity_for_item(tcx, def_id));
+
+ predicates.extend(associated_item_bounds(tcx, def_id, bounds, projection_ty, span))
+ }
+ } else if let Some((self_trait_ref, trait_items)) = is_trait {
+ // Current behavior: bounds declared on associate type are predicates
+ // of its parent trait.
predicates.extend(trait_items.iter().flat_map(|trait_item_ref| {
- associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref)
+ trait_associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref)
}))
}
result
}
-fn associated_item_predicates(
+fn trait_associated_item_predicates(
tcx: TyCtxt<'tcx>,
def_id: DefId,
self_trait_ref: ty::TraitRef<'tcx>,
_ => return Vec::new(),
};
- let is_gat = !tcx.generics_of(item_def_id).params.is_empty();
-
- let mut had_error = false;
-
- let mut unimplemented_error = |arg_kind: &str| {
- if !had_error {
- tcx.sess
- .struct_span_err(
- trait_item.span,
- &format!("{}-generic associated types are not yet implemented", arg_kind),
- )
- .note(
- "for more information, see issue #44265 \
- <https://github.com/rust-lang/rust/issues/44265> for more information",
- )
- .emit();
- had_error = true;
- }
- };
-
- let mk_bound_param = |param: &ty::GenericParamDef, _: &_| {
- match param.kind {
- ty::GenericParamDefKind::Lifetime => tcx
- .mk_region(ty::RegionKind::ReLateBound(
- ty::INNERMOST,
- ty::BoundRegion::BrNamed(param.def_id, param.name),
- ))
- .into(),
- // FIXME(generic_associated_types): Use bound types and constants
- // once they are handled by the trait system.
- ty::GenericParamDefKind::Type { .. } => {
- unimplemented_error("type");
- tcx.types.err.into()
- }
- ty::GenericParamDefKind::Const => {
- unimplemented_error("const");
- tcx.mk_const(ty::Const { val: ty::ConstKind::Error, ty: tcx.type_of(param.def_id) })
- .into()
- }
- }
- };
+ if !tcx.generics_of(item_def_id).params.is_empty() {
+ // For GATs the substs provided to the mk_projection call below are
+ // wrong. We should emit a feature gate error if we get here so skip
+ // this type.
+ tcx.sess.delay_span_bug(trait_item.span, "gats used without feature gate");
+ return Vec::new();
+ }
- let bound_substs = if is_gat {
- // Given:
- //
- // trait X<'a, B, const C: usize> {
- // type T<'d, E, const F: usize>: Default;
- // }
- //
- // We need to create predicates on the trait:
- //
- // for<'d, E, const F: usize>
- // <Self as X<'a, B, const C: usize>>::T<'d, E, const F: usize>: Sized + Default
- //
- // We substitute escaping bound parameters for the generic
- // arguments to the associated type which are then bound by
- // the `Binder` around the the predicate.
- //
- // FIXME(generic_associated_types): Currently only lifetimes are handled.
- self_trait_ref.substs.extend_to(tcx, item_def_id.to_def_id(), mk_bound_param)
- } else {
- self_trait_ref.substs
- };
+ let assoc_ty = tcx.mk_projection(
+ tcx.hir().local_def_id(trait_item.hir_id).to_def_id(),
+ self_trait_ref.substs,
+ );
- let assoc_ty =
- tcx.mk_projection(tcx.hir().local_def_id(trait_item.hir_id).to_def_id(), bound_substs);
+ associated_item_bounds(tcx, def_id, bounds, assoc_ty, trait_item.span)
+}
+fn associated_item_bounds(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ bounds: &'tcx [hir::GenericBound<'tcx>],
+ projection_ty: Ty<'tcx>,
+ span: Span,
+) -> Vec<(ty::Predicate<'tcx>, Span)> {
let bounds = AstConv::compute_bounds(
&ItemCtxt::new(tcx, def_id),
- assoc_ty,
+ projection_ty,
bounds,
SizedByDefault::Yes,
- trait_item.span,
+ span,
);
- let predicates = bounds.predicates(tcx, assoc_ty);
+ let predicates = bounds.predicates(tcx, projection_ty);
- if is_gat {
- // We use shifts to get the regions that we're substituting to
- // be bound by the binders in the `Predicate`s rather that
- // escaping.
- let shifted_in = ty::fold::shift_vars(tcx, &predicates, 1);
- let substituted = shifted_in.subst(tcx, bound_substs);
- ty::fold::shift_out_vars(tcx, &substituted, 1)
- } else {
- predicates
- }
+ predicates
}
/// Converts a specific `GenericBound` from the AST into a set of
if let Some(list) = attr.meta_item_list() {
for item in list.iter() {
if item.check_name(sym::address) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_ADDRESS;
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
} else if item.check_name(sym::memory) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_MEMORY;
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
} else if item.check_name(sym::thread) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_THREAD;
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
} else {
tcx.sess
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
}
}
- if codegen_fn_attrs.flags.intersects(CodegenFnAttrFlags::NO_SANITIZE_ANY) {
+ if !codegen_fn_attrs.no_sanitize.is_empty() {
if codegen_fn_attrs.inline == InlineAttr::Always {
if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
let hir_id = tcx.hir().as_local_hir_id(id.expect_local());
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
-use rustc_session::parse::feature_err;
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::traits;
// Some error in the
// owner fn prevented us from populating
// the `concrete_opaque_types` table.
- tcx.types.err
+ tcx.ty_error()
} else {
// We failed to resolve the opaque type or it
// resolves to itself. Return the non-revealed
})
| Node::TraitRef(&TraitRef { path, .. }) => &*path,
_ => {
- tcx.sess.delay_span_bug(
+ return tcx.ty_error_with_message(
DUMMY_SP,
&format!("unexpected const parent path {:?}", parent_node),
);
- return tcx.types.err;
}
};
}
Res::Def(_, def_id) => tcx.generics_of(def_id),
res => {
- tcx.sess.delay_span_bug(
+ return tcx.ty_error_with_message(
DUMMY_SP,
&format!(
"unexpected anon const res {:?} in path: {:?}",
res, path,
),
- );
- return tcx.types.err;
+ );
}
};
} else {
// This is no generic parameter associated with the arg. This is
// probably from an extra arg where one is not needed.
- tcx.sess.delay_span_bug(
+ tcx.ty_error_with_message(
DUMMY_SP,
&format!(
- "missing generic parameter for `AnonConst`, parent: {:?}, res: {:?}",
+ "missing generic parameter for `AnonConst`, \
+ parent: {:?}, res: {:?}",
parent_node, res
),
- );
- tcx.types.err
+ )
}
}
- x => {
- tcx.sess.delay_span_bug(
- DUMMY_SP,
- &format!("unexpected const parent in type_of_def_id(): {:?}", x),
- );
- tcx.types.err
- }
+ x => tcx.ty_error_with_message(
+ DUMMY_SP,
+ &format!("unexpected const parent in type_of_def_id(): {:?}", x),
+ ),
}
}
GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
GenericParamKind::Const { ty: ref hir_ty, .. } => {
let ty = icx.to_ty(hir_ty);
- if !tcx.features().const_compare_raw_pointers {
- let err = match ty.peel_refs().kind {
- ty::FnPtr(_) => Some("function pointers"),
- ty::RawPtr(_) => Some("raw pointers"),
- _ => None,
- };
- if let Some(unsupported_type) = err {
- feature_err(
- &tcx.sess.parse_sess,
- sym::const_compare_raw_pointers,
+ let err = match ty.peel_refs().kind {
+ ty::FnPtr(_) => Some("function pointers"),
+ ty::RawPtr(_) => Some("raw pointers"),
+ _ => None,
+ };
+ if let Some(unsupported_type) = err {
+ tcx.sess
+ .struct_span_err(
hir_ty.span,
&format!(
- "using {} as const generic parameters is unstable",
+ "using {} as const generic parameters is forbidden",
unsupported_type
),
)
.emit();
- };
- }
+ };
if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
.is_some()
{
None => {
let span = tcx.def_span(def_id);
tcx.sess.span_err(span, "could not find defining uses");
- tcx.types.err
+ tcx.ty_error()
}
}
}
if let Some(ErrorReported) = owner_tables.tainted_by_errors {
// Some error in the owner fn prevented us from populating the
// `concrete_opaque_types` table.
- tcx.types.err
+ tcx.ty_error()
} else {
// We failed to resolve the opaque type or it resolves to
// itself. Return the non-revealed type, which should result in
}
None => {
let mut diag = bad_placeholder_type(tcx, vec![span]);
- if ty != tcx.types.err {
+ if !matches!(ty.kind, ty::Error(_)) {
diag.span_suggestion(
span,
"replace `_` with the correct type",
pub use self::ConsumeMode::*;
// Export these here so that Clippy can use them.
-pub use mc::{Place, PlaceBase, Projection};
+pub use mc::{PlaceBase, PlaceWithHirId, Projection};
use rustc_hir as hir;
use rustc_hir::def::Res;
pub trait Delegate<'tcx> {
// The value found at `place` is either copied or moved, depending
// on mode.
- fn consume(&mut self, place: &mc::Place<'tcx>, mode: ConsumeMode);
+ fn consume(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, mode: ConsumeMode);
// The value found at `place` is being borrowed with kind `bk`.
- fn borrow(&mut self, place: &mc::Place<'tcx>, bk: ty::BorrowKind);
+ fn borrow(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, bk: ty::BorrowKind);
- // The path at `place` is being assigned to.
- fn mutate(&mut self, assignee_place: &mc::Place<'tcx>);
+ // The path at `place_with_id` is being assigned to.
+ fn mutate(&mut self, assignee_place: &mc::PlaceWithHirId<'tcx>);
}
#[derive(Copy, Clone, PartialEq, Debug)]
self.mc.tcx()
}
- fn delegate_consume(&mut self, place: &Place<'tcx>) {
- debug!("delegate_consume(place={:?})", place);
+ fn delegate_consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>) {
+ debug!("delegate_consume(place_with_id={:?})", place_with_id);
- let mode = copy_or_move(&self.mc, place);
- self.delegate.consume(place, mode);
+ let mode = copy_or_move(&self.mc, place_with_id);
+ self.delegate.consume(place_with_id, mode);
}
fn consume_exprs(&mut self, exprs: &[hir::Expr<'_>]) {
pub fn consume_expr(&mut self, expr: &hir::Expr<'_>) {
debug!("consume_expr(expr={:?})", expr);
- let place = return_if_err!(self.mc.cat_expr(expr));
- self.delegate_consume(&place);
+ let place_with_id = return_if_err!(self.mc.cat_expr(expr));
+ self.delegate_consume(&place_with_id);
self.walk_expr(expr);
}
fn mutate_expr(&mut self, expr: &hir::Expr<'_>) {
- let place = return_if_err!(self.mc.cat_expr(expr));
- self.delegate.mutate(&place);
+ let place_with_id = return_if_err!(self.mc.cat_expr(expr));
+ self.delegate.mutate(&place_with_id);
self.walk_expr(expr);
}
fn borrow_expr(&mut self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) {
debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk);
- let place = return_if_err!(self.mc.cat_expr(expr));
- self.delegate.borrow(&place, bk);
+ let place_with_id = return_if_err!(self.mc.cat_expr(expr));
+ self.delegate.borrow(&place_with_id, bk);
self.walk_expr(expr)
}
// Select just those fields of the `with`
// expression that will actually be used
- match with_place.ty.kind {
+ match with_place.place.ty.kind {
ty::Adt(adt, substs) if adt.is_struct() => {
// Consume those fields of the with expression that are needed.
for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() {
// process.
fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) {
let adjustments = self.mc.tables.expr_adjustments(expr);
- let mut place = return_if_err!(self.mc.cat_expr_unadjusted(expr));
+ let mut place_with_id = return_if_err!(self.mc.cat_expr_unadjusted(expr));
for adjustment in adjustments {
debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
match adjustment.kind {
adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => {
// Creating a closure/fn-pointer or unsizing consumes
// the input and stores it into the resulting rvalue.
- self.delegate_consume(&place);
+ self.delegate_consume(&place_with_id);
}
adjustment::Adjust::Deref(None) => {}
// this is an autoref of `x`.
adjustment::Adjust::Deref(Some(ref deref)) => {
let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
- self.delegate.borrow(&place, bk);
+ self.delegate.borrow(&place_with_id, bk);
}
adjustment::Adjust::Borrow(ref autoref) => {
- self.walk_autoref(expr, &place, autoref);
+ self.walk_autoref(expr, &place_with_id, autoref);
}
}
- place = return_if_err!(self.mc.cat_expr_adjusted(expr, place, &adjustment));
+ place_with_id =
+ return_if_err!(self.mc.cat_expr_adjusted(expr, place_with_id, &adjustment));
}
}
fn walk_autoref(
&mut self,
expr: &hir::Expr<'_>,
- base_place: &mc::Place<'tcx>,
+ base_place: &mc::PlaceWithHirId<'tcx>,
autoref: &adjustment::AutoBorrow<'tcx>,
) {
debug!(
}
}
- fn walk_arm(&mut self, discr_place: &Place<'tcx>, arm: &hir::Arm<'_>) {
+ fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) {
self.walk_pat(discr_place, &arm.pat);
if let Some(hir::Guard::If(ref e)) = arm.guard {
/// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
/// let binding, and *not* a match arm or nested pat.)
- fn walk_irrefutable_pat(&mut self, discr_place: &Place<'tcx>, pat: &hir::Pat<'_>) {
+ fn walk_irrefutable_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
self.walk_pat(discr_place, pat);
}
/// The core driver for walking a pattern
- fn walk_pat(&mut self, discr_place: &Place<'tcx>, pat: &hir::Pat<'_>) {
+ fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat);
let tcx = self.tcx();
closure_hir_id: hir::HirId,
closure_span: Span,
var_id: hir::HirId,
- ) -> mc::McResult<mc::Place<'tcx>> {
+ ) -> mc::McResult<mc::PlaceWithHirId<'tcx>> {
// Create the place for the variable being borrowed, from the
// perspective of the creator (parent) of the closure.
let var_ty = self.mc.node_ty(var_id)?;
fn copy_or_move<'a, 'tcx>(
mc: &mc::MemCategorizationContext<'a, 'tcx>,
- place: &Place<'tcx>,
+ place_with_id: &PlaceWithHirId<'tcx>,
) -> ConsumeMode {
- if !mc.type_is_copy_modulo_regions(place.ty, place.span) { Move } else { Copy }
+ if !mc.type_is_copy_modulo_regions(
+ place_with_id.place.ty,
+ mc.tcx().hir().span(place_with_id.hir_id),
+ ) {
+ Move
+ } else {
+ Copy
+ }
}
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
// but it's one that we must perform earlier than the rest of
// WfCheck.
for &module in tcx.hir().krate().modules.keys() {
- tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id(module).to_def_id());
+ tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id(module));
}
}
-fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
let min_specialization = tcx.features().min_specialization;
tcx.hir()
.visit_item_likes_in_module(module_def_id, &mut ImplWfCheck { tcx, min_specialization });
}
#[derive(Clone, Debug)]
-pub enum Projection<'tcx> {
+pub enum ProjectionKind<'tcx> {
/// A dereference of a pointer, reference or `Box<T>` of the given type
Deref(Ty<'tcx>),
/// An index or a field
Other,
}
+#[derive(Clone, Debug)]
+pub struct Projection<'tcx> {
+ /// Defines the type of access
+ kind: ProjectionKind<'tcx>,
+}
+
/// A `Place` represents how a value is located in memory.
///
/// This is an HIR version of `mir::Place`
#[derive(Clone, Debug)]
pub struct Place<'tcx> {
- /// `HirId` of the expression or pattern producing this value.
- pub hir_id: hir::HirId,
- /// The `Span` of the expression or pattern producing this value.
- pub span: Span,
/// The type of the `Place`
pub ty: Ty<'tcx>,
/// The "outermost" place that holds this value.
pub projections: Vec<Projection<'tcx>>,
}
+/// A `PlaceWithHirId` represents how a value is located in memory.
+///
+/// This is an HIR version of `mir::Place`
+#[derive(Clone, Debug)]
+pub struct PlaceWithHirId<'tcx> {
+ /// `HirId` of the expression or pattern producing this value.
+ pub hir_id: hir::HirId,
+
+ /// Information about the `Place`
+ pub place: Place<'tcx>,
+}
+
+impl<'tcx> PlaceWithHirId<'tcx> {
+ crate fn new(
+ hir_id: hir::HirId,
+ ty: Ty<'tcx>,
+ base: PlaceBase,
+ projections: Vec<Projection<'tcx>>,
+ ) -> PlaceWithHirId<'tcx> {
+ PlaceWithHirId {
+ hir_id: hir_id,
+ place: Place { ty: ty, base: base, projections: projections },
+ }
+ }
+}
+
impl<'tcx> Place<'tcx> {
/// Returns an iterator of the types that have to be dereferenced to access
/// the `Place`.
///`*const u32` then `&*const u32`.
crate fn deref_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ {
self.projections.iter().rev().filter_map(|proj| {
- if let Projection::Deref(deref_ty) = *proj { Some(deref_ty) } else { None }
+ if let ProjectionKind::Deref(deref_ty) = proj.kind { Some(deref_ty) } else { None }
})
}
}
Ok(ret_ty)
}
- crate fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<Place<'tcx>> {
+ crate fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
// This recursion helper avoids going through *too many*
// adjustments, since *only* non-overloaded deref recurses.
fn helper<'a, 'tcx>(
mc: &MemCategorizationContext<'a, 'tcx>,
expr: &hir::Expr<'_>,
adjustments: &[adjustment::Adjustment<'tcx>],
- ) -> McResult<Place<'tcx>> {
+ ) -> McResult<PlaceWithHirId<'tcx>> {
match adjustments.split_last() {
None => mc.cat_expr_unadjusted(expr),
Some((adjustment, previous)) => {
crate fn cat_expr_adjusted(
&self,
expr: &hir::Expr<'_>,
- previous: Place<'tcx>,
+ previous: PlaceWithHirId<'tcx>,
adjustment: &adjustment::Adjustment<'tcx>,
- ) -> McResult<Place<'tcx>> {
+ ) -> McResult<PlaceWithHirId<'tcx>> {
self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
}
expr: &hir::Expr<'_>,
previous: F,
adjustment: &adjustment::Adjustment<'tcx>,
- ) -> McResult<Place<'tcx>>
+ ) -> McResult<PlaceWithHirId<'tcx>>
where
- F: FnOnce() -> McResult<Place<'tcx>>,
+ F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>,
{
debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr);
let target = self.resolve_vars_if_possible(&adjustment.target);
}
}
- crate fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> McResult<Place<'tcx>> {
+ crate fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
debug!("cat_expr: id={} expr={:?}", expr.hir_id, expr);
let expr_ty = self.expr_ty(expr)?;
span: Span,
expr_ty: Ty<'tcx>,
res: Res,
- ) -> McResult<Place<'tcx>> {
+ ) -> McResult<PlaceWithHirId<'tcx>> {
debug!("cat_res: id={:?} expr={:?} def={:?}", hir_id, expr_ty, res);
match res {
)
| Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, span, expr_ty)),
- Res::Def(DefKind::Static, _) => Ok(Place {
- hir_id,
- span,
- ty: expr_ty,
- base: PlaceBase::StaticItem,
- projections: Vec::new(),
- }),
+ Res::Def(DefKind::Static, _) => {
+ Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new()))
+ }
Res::Local(var_id) => {
if self.upvars.map_or(false, |upvars| upvars.contains_key(&var_id)) {
- self.cat_upvar(hir_id, span, var_id)
+ self.cat_upvar(hir_id, var_id)
} else {
- Ok(Place {
- hir_id,
- span,
- ty: expr_ty,
- base: PlaceBase::Local(var_id),
- projections: Vec::new(),
- })
+ Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Local(var_id), Vec::new()))
}
}
/// Note: the actual upvar access contains invisible derefs of closure
/// environment and upvar reference as appropriate. Only regionck cares
/// about these dereferences, so we let it compute them as needed.
- fn cat_upvar(
- &self,
- hir_id: hir::HirId,
- span: Span,
- var_id: hir::HirId,
- ) -> McResult<Place<'tcx>> {
+ fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult<PlaceWithHirId<'tcx>> {
let closure_expr_def_id = self.body_owner;
let upvar_id = ty::UpvarId {
};
let var_ty = self.node_ty(var_id)?;
- let ret = Place {
- hir_id,
- span,
- ty: var_ty,
- base: PlaceBase::Upvar(upvar_id),
- projections: Vec::new(),
- };
+ let ret = PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new());
debug!("cat_upvar ret={:?}", ret);
Ok(ret)
}
- crate fn cat_rvalue(&self, hir_id: hir::HirId, span: Span, expr_ty: Ty<'tcx>) -> Place<'tcx> {
+ crate fn cat_rvalue(
+ &self,
+ hir_id: hir::HirId,
+ span: Span,
+ expr_ty: Ty<'tcx>,
+ ) -> PlaceWithHirId<'tcx> {
debug!("cat_rvalue hir_id={:?}, expr_ty={:?}, span={:?}", hir_id, expr_ty, span);
- let ret =
- Place { hir_id, span, base: PlaceBase::Rvalue, projections: Vec::new(), ty: expr_ty };
+ let ret = PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new());
debug!("cat_rvalue ret={:?}", ret);
ret
}
crate fn cat_projection<N: HirNode>(
&self,
node: &N,
- base_place: Place<'tcx>,
+ base_place: PlaceWithHirId<'tcx>,
ty: Ty<'tcx>,
- ) -> Place<'tcx> {
- let mut projections = base_place.projections;
- projections.push(Projection::Other);
- let ret = Place {
- hir_id: node.hir_id(),
- span: node.span(),
- ty,
- base: base_place.base,
- projections,
- };
+ ) -> PlaceWithHirId<'tcx> {
+ let mut projections = base_place.place.projections;
+ projections.push(Projection { kind: ProjectionKind::Other });
+ let ret = PlaceWithHirId::new(node.hir_id(), ty, base_place.place.base, projections);
debug!("cat_field ret {:?}", ret);
ret
}
&self,
expr: &hir::Expr<'_>,
base: &hir::Expr<'_>,
- ) -> McResult<Place<'tcx>> {
+ ) -> McResult<PlaceWithHirId<'tcx>> {
debug!("cat_overloaded_place(expr={:?}, base={:?})", expr, base);
// Reconstruct the output assuming it's a reference with the
self.cat_deref(expr, base)
}
- fn cat_deref(&self, node: &impl HirNode, base_place: Place<'tcx>) -> McResult<Place<'tcx>> {
+ fn cat_deref(
+ &self,
+ node: &impl HirNode,
+ base_place: PlaceWithHirId<'tcx>,
+ ) -> McResult<PlaceWithHirId<'tcx>> {
debug!("cat_deref: base_place={:?}", base_place);
- let base_ty = base_place.ty;
+ let base_ty = base_place.place.ty;
let deref_ty = match base_ty.builtin_deref(true) {
Some(mt) => mt.ty,
None => {
return Err(());
}
};
- let mut projections = base_place.projections;
- projections.push(Projection::Deref(base_ty));
-
- let ret = Place {
- hir_id: node.hir_id(),
- span: node.span(),
- ty: deref_ty,
- base: base_place.base,
- projections,
- };
+ let mut projections = base_place.place.projections;
+ projections.push(Projection { kind: ProjectionKind::Deref(base_ty) });
+
+ let ret = PlaceWithHirId::new(node.hir_id(), deref_ty, base_place.place.base, projections);
debug!("cat_deref ret {:?}", ret);
Ok(ret)
}
crate fn cat_pattern<F>(
&self,
- place: Place<'tcx>,
+ place: PlaceWithHirId<'tcx>,
pat: &hir::Pat<'_>,
mut op: F,
) -> McResult<()>
where
- F: FnMut(&Place<'tcx>, &hir::Pat<'_>),
+ F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
{
self.cat_pattern_(place, pat, &mut op)
}
// FIXME(#19596) This is a workaround, but there should be a better way to do this
fn cat_pattern_<F>(
&self,
- mut place: Place<'tcx>,
+ mut place_with_id: PlaceWithHirId<'tcx>,
pat: &hir::Pat<'_>,
op: &mut F,
) -> McResult<()>
where
- F: FnMut(&Place<'tcx>, &hir::Pat<'_>),
+ F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
{
- // Here, `place` is the `Place` being matched and pat is the pattern it
+ // Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
// is being matched against.
//
// In general, the way that this works is that we walk down the pattern,
- // constructing a `Place` that represents the path that will be taken
+ // constructing a `PlaceWithHirId` that represents the path that will be taken
// to reach the value being matched.
- debug!("cat_pattern(pat={:?}, place={:?})", pat, place);
+ debug!("cat_pattern(pat={:?}, place_with_id={:?})", pat, place_with_id);
- // If (pattern) adjustments are active for this pattern, adjust the `Place` correspondingly.
- // `Place`s are constructed differently from patterns. For example, in
+ // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly.
+ // `PlaceWithHirId`s are constructed differently from patterns. For example, in
//
// ```
// match foo {
// ```
//
// the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the
- // corresponding `Place` we start with the `Place` for `foo`, and then, by traversing the
+ // corresponding `PlaceWithHirId` we start with the `PlaceWithHirId` for `foo`, and then, by traversing the
// pattern, try to answer the question: given the address of `foo`, how is `x` reached?
//
// `&&Some(x,)` `place_foo`
// `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
// and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
for _ in 0..self.tables.pat_adjustments().get(pat.hir_id).map(|v| v.len()).unwrap_or(0) {
- debug!("cat_pattern: applying adjustment to place={:?}", place);
- place = self.cat_deref(pat, place)?;
+ debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id);
+ place_with_id = self.cat_deref(pat, place_with_id)?;
}
- let place = place; // lose mutability
- debug!("cat_pattern: applied adjustment derefs to get place={:?}", place);
+ let place_with_id = place_with_id; // lose mutability
+ debug!("cat_pattern: applied adjustment derefs to get place_with_id={:?}", place_with_id);
- // Invoke the callback, but only now, after the `place` has adjusted.
+ // Invoke the callback, but only now, after the `place_with_id` has adjusted.
//
// To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that
- // case, the initial `place` will be that for `&Some(3)` and the pattern is `Some(x)`. We
+ // case, the initial `place_with_id` will be that for `&Some(3)` and the pattern is `Some(x)`. We
// don't want to call `op` with these incompatible values. As written, what happens instead
// is that `op` is called with the adjusted place (that for `*&Some(3)`) and the pattern
// `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)`
// result in the place `Downcast<Some>(*&Some(3)).0` associated to `x` and invoke `op` with
// that (where the `ref` on `x` is implied).
- op(&place, pat);
+ op(&place_with_id, pat);
match pat.kind {
PatKind::TupleStruct(_, ref subpats, _) | PatKind::Tuple(ref subpats, _) => {
// S(p1, ..., pN) or (p1, ..., pN)
for subpat in subpats.iter() {
let subpat_ty = self.pat_ty_adjusted(&subpat)?;
- let sub_place = self.cat_projection(pat, place.clone(), subpat_ty);
+ let sub_place = self.cat_projection(pat, place_with_id.clone(), subpat_ty);
self.cat_pattern_(sub_place, &subpat, op)?;
}
}
// S { f1: p1, ..., fN: pN }
for fp in field_pats {
let field_ty = self.pat_ty_adjusted(&fp.pat)?;
- let field_place = self.cat_projection(pat, place.clone(), field_ty);
+ let field_place = self.cat_projection(pat, place_with_id.clone(), field_ty);
self.cat_pattern_(field_place, &fp.pat, op)?;
}
}
PatKind::Or(pats) => {
for pat in pats {
- self.cat_pattern_(place.clone(), &pat, op)?;
+ self.cat_pattern_(place_with_id.clone(), &pat, op)?;
}
}
PatKind::Binding(.., Some(ref subpat)) => {
- self.cat_pattern_(place, &subpat, op)?;
+ self.cat_pattern_(place_with_id, &subpat, op)?;
}
PatKind::Box(ref subpat) | PatKind::Ref(ref subpat, _) => {
// box p1, &p1, &mut p1. we can ignore the mutability of
// PatKind::Ref since that information is already contained
// in the type.
- let subplace = self.cat_deref(pat, place)?;
+ let subplace = self.cat_deref(pat, place_with_id)?;
self.cat_pattern_(subplace, &subpat, op)?;
}
PatKind::Slice(before, ref slice, after) => {
- let element_ty = match place.ty.builtin_index() {
+ let element_ty = match place_with_id.place.ty.builtin_index() {
Some(ty) => ty,
None => {
- debug!("explicit index of non-indexable type {:?}", place);
+ debug!("explicit index of non-indexable type {:?}", place_with_id);
return Err(());
}
};
- let elt_place = self.cat_projection(pat, place.clone(), element_ty);
+ let elt_place = self.cat_projection(pat, place_with_id.clone(), element_ty);
for before_pat in before {
self.cat_pattern_(elt_place.clone(), &before_pat, op)?;
}
if let Some(ref slice_pat) = *slice {
let slice_pat_ty = self.pat_ty_adjusted(&slice_pat)?;
- let slice_place = self.cat_projection(pat, place, slice_pat_ty);
+ let slice_place = self.cat_projection(pat, place_with_id, slice_pat_ty);
self.cat_pattern_(slice_place, &slice_pat, op)?;
}
for after_pat in after {
self.add_constraints_from_sig(current, sig, variance);
}
- ty::Error => {
+ ty::Error(_) => {
// we encounter this when walking the trait references for object
// types, where we use Error as the Self type
}
type_.def_id().and_then(|did| build_ty(cx, did))
}
-pub fn build_ty(cx: &DocContext, did: DefId) -> Option<clean::Type> {
+pub fn build_ty(cx: &DocContext<'_>, did: DefId) -> Option<clean::Type> {
match cx.tcx.def_kind(did) {
DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Const | DefKind::Static => {
Some(cx.tcx.type_of(did).clean(cx))
ty::Placeholder(..) => panic!("Placeholder"),
ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
ty::Infer(..) => panic!("Infer"),
- ty::Error => panic!("Error"),
+ ty::Error(_) => panic!("Error"),
}
}
}
})
}
+ /// Enforce the format of attributes inside `#[doc(...)]`.
+ pub fn check_doc_attributes(
+ diagnostic: &::rustc_errors::Handler,
+ mi: &ast::MetaItem,
+ ) -> Option<(String, String)> {
+ mi.meta_item_list().and_then(|list| {
+ for meta in list {
+ if meta.check_name(sym::alias) {
+ if !meta.is_value_str()
+ || meta
+ .value_str()
+ .map(|s| s.to_string())
+ .unwrap_or_else(String::new)
+ .is_empty()
+ {
+ diagnostic.span_err(
+ meta.span(),
+ "doc alias attribute expects a string: #[doc(alias = \"0\")]",
+ );
+ }
+ }
+ }
+
+ None
+ })
+ }
+
pub fn has_doc_flag(&self, flag: Symbol) -> bool {
for attr in &self.other_attrs {
if !attr.check_name(sym::doc) {
} else {
if attr.check_name(sym::doc) {
if let Some(mi) = attr.meta() {
+ Attributes::check_doc_attributes(&diagnostic, &mi);
if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
// Extracted #[doc(cfg(...))]
match Cfg::parse(cfg_mi) {
Path { global: path.global, res: path.res, segments }
}
-pub fn qpath_to_string(p: &hir::QPath) -> String {
+pub fn qpath_to_string(p: &hir::QPath<'_>) -> String {
let segments = match *p {
hir::QPath::Resolved(_, ref path) => &path.segments,
hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(),
}
}
-pub fn name_from_pat(p: &hir::Pat) -> String {
+pub fn name_from_pat(p: &hir::Pat<'_>) -> String {
use rustc_hir::*;
debug!("trying to get a name from pattern: {:?}", p);
_ => {
let mut s = n.to_string();
// array lengths are obviously usize
- if s.ends_with("usize") {
- let n = s.len() - "usize".len();
+ if s.ends_with("_usize") {
+ let n = s.len() - "_usize".len();
s.truncate(n);
if s.ends_with(": ") {
let n = s.len() - ": ".len();
///
/// Be aware: This option can come both from the CLI and from crate attributes!
pub default_passes: DefaultPassOption,
- /// Document items that have lower than `pub` visibility.
- pub document_private: bool,
- /// Document items that have `doc(hidden)`.
- pub document_hidden: bool,
/// Any passes manually selected by the user.
///
/// Be aware: This option can come both from the CLI and from crate attributes!
.field("test_args", &self.test_args)
.field("persist_doctests", &self.persist_doctests)
.field("default_passes", &self.default_passes)
- .field("document_private", &self.document_private)
- .field("document_hidden", &self.document_hidden)
.field("manual_passes", &self.manual_passes)
.field("display_warnings", &self.display_warnings)
.field("show_coverage", &self.show_coverage)
pub generate_search_filter: bool,
/// Option (disabled by default) to generate files used by RLS and some other tools.
pub generate_redirect_pages: bool,
+ /// Document items that have lower than `pub` visibility.
+ pub document_private: bool,
+ /// Document items that have `doc(hidden)`.
+ pub document_hidden: bool,
}
impl Options {
should_test,
test_args,
default_passes,
- document_private,
- document_hidden,
manual_passes,
display_warnings,
show_coverage,
markdown_playground_url,
generate_search_filter,
generate_redirect_pages,
+ document_private,
+ document_hidden,
},
output_format,
})
// FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
pub generated_synthetics: RefCell<FxHashSet<(Ty<'tcx>, DefId)>>,
pub auto_traits: Vec<DefId>,
+ /// The options given to rustdoc that could be relevant to a pass.
+ pub render_options: RenderOptions,
}
impl<'tcx> DocContext<'tcx> {
Lrc::new(source_map::SourceMap::new(source_map::FilePathMapping::empty()))
});
Box::new(
- JsonEmitter::stderr(None, source_map, pretty, json_rendered, false)
- .ui_testing(debugging_opts.ui_testing),
+ JsonEmitter::stderr(
+ None,
+ source_map,
+ pretty,
+ json_rendered,
+ debugging_opts.terminal_width,
+ false,
+ )
+ .ui_testing(debugging_opts.ui_testing),
)
}
};
describe_lints,
lint_cap,
mut default_passes,
- mut document_private,
- document_hidden,
mut manual_passes,
display_warnings,
render_options,
.cloned()
.filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id))
.collect(),
+ render_options,
};
debug!("crate: {:?}", tcx.hir().krate());
}
if attr.is_word() && name == sym::document_private_items {
- document_private = true;
+ ctxt.render_options.document_private = true;
}
}
for p in passes {
let run = match p.condition {
Always => true,
- WhenDocumentPrivate => document_private,
- WhenNotDocumentPrivate => !document_private,
- WhenNotDocumentHidden => !document_hidden,
+ WhenDocumentPrivate => ctxt.render_options.document_private,
+ WhenNotDocumentPrivate => !ctxt.render_options.document_private,
+ WhenNotDocumentHidden => !ctxt.render_options.document_hidden,
};
if run {
debug!("running pass {}", p.pass.name);
ctxt.sess().abort_if_errors();
- (krate, ctxt.renderinfo.into_inner(), render_options)
+ (krate, ctxt.renderinfo.into_inner(), ctxt.render_options)
})
})
})
pub whence: Span,
}
-pub fn struct_type_from_def(vdata: &hir::VariantData) -> StructType {
+pub fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType {
match *vdata {
hir::VariantData::Struct(..) => Plain,
hir::VariantData::Tuple(..) => Tuple,
pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
let cache = cache();
- if !did.is_local() && !cache.access_levels.is_public(did) {
+ if !did.is_local() && !cache.access_levels.is_public(did) && !cache.document_private {
return None;
}
fn next(&mut self) -> Option<Self::Item> {
let event = self.inner.next();
let compile_fail;
+ let should_panic;
let ignore;
let edition;
if let Some(Event::Start(Tag::CodeBlock(kind))) = event {
return Some(Event::Start(Tag::CodeBlock(kind)));
}
compile_fail = parse_result.compile_fail;
+ should_panic = parse_result.should_panic;
ignore = parse_result.ignore;
edition = parse_result.edition;
} else {
Some(("This example is not tested".to_owned(), "ignore"))
} else if compile_fail {
Some(("This example deliberately fails to compile".to_owned(), "compile_fail"))
+ } else if should_panic {
+ Some(("This example panics".to_owned(), "should_panic"))
} else if explicit_edition {
Some((format!("This code runs with edition {}", edition), "edition"))
} else {
" ignore"
} else if compile_fail {
" compile_fail"
+ } else if should_panic {
+ " should_panic"
} else if explicit_edition {
" edition "
} else {
" ignore"
} else if compile_fail {
" compile_fail"
+ } else if should_panic {
+ " should_panic"
} else if explicit_edition {
" edition "
} else {
static_root_path,
generate_search_filter,
generate_redirect_pages,
+ document_private,
..
} = options;
scx.ensure_dir(&dst)?;
krate = sources::render(&dst, &mut scx, krate)?;
let (new_crate, index, cache) =
- Cache::from_krate(renderinfo, &extern_html_root_urls, &dst, krate);
+ Cache::from_krate(renderinfo, document_private, &extern_html_root_urls, &dst, krate);
krate = new_crate;
let cache = Arc::new(cache);
let mut cx = Context {
/// The version of the crate being documented, if given from the `--crate-version` flag.
pub crate_version: Option<String>,
+ /// Whether to document private items.
+ /// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
+ pub document_private: bool,
+
// Private fields only used when initially crawling a crate to build a cache
stack: Vec<String>,
parent_stack: Vec<DefId>,
impl Cache {
pub fn from_krate(
renderinfo: RenderInfo,
+ document_private: bool,
extern_html_root_urls: &BTreeMap<String, String>,
dst: &Path,
mut krate: clean::Crate,
stripped_mod: false,
access_levels,
crate_version: krate.version.take(),
+ document_private,
orphan_impl_items: Vec::new(),
orphan_trait_impls: Vec::new(),
traits: krate.external_traits.replace(Default::default()),
// 2 for "In Return Types"
var currentTab = 0;
+ var mouseMovedAfterSearch = true;
+
var titleBeforeSearch = document.title;
function clearInputTimeout() {
}
addClass(main, "hidden");
removeClass(search, "hidden");
+ mouseMovedAfterSearch = false;
}
function hideSearchResults(search) {
document.addEventListener("keypress", handleShortcut);
document.addEventListener("keydown", handleShortcut);
+ function resetMouseMoved(ev) {
+ mouseMovedAfterSearch = true;
+ }
+
+ document.addEventListener("mousemove", resetMouseMoved);
+
var handleSourceHighlight = (function() {
var prev_line_id = 0;
var aliases = [];
var crateAliases = [];
var i;
- if (filterCrates !== undefined &&
- ALIASES[filterCrates] &&
- ALIASES[filterCrates][query.search]) {
- for (i = 0; i < ALIASES[crate][query.search].length; ++i) {
- aliases.push(
- createAliasFromItem(searchIndex[ALIASES[filterCrates][query.search]]));
+ if (filterCrates !== undefined) {
+ if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) {
+ for (i = 0; i < ALIASES[filterCrates][query.search].length; ++i) {
+ aliases.push(
+ createAliasFromItem(
+ searchIndex[ALIASES[filterCrates][query.search][i]]));
+ }
}
} else {
Object.keys(ALIASES).forEach(function(crate) {
}
};
var mouseover_func = function(e) {
- var el = e.target;
- // to retrieve the real "owner" of the event.
- while (el.tagName !== "TR") {
- el = el.parentNode;
- }
- clearTimeout(hoverTimeout);
- hoverTimeout = setTimeout(function() {
- onEachLazy(document.getElementsByClassName("search-results"), function(e) {
- onEachLazy(e.getElementsByClassName("result"), function(i_e) {
- removeClass(i_e, "highlighted");
+ if (mouseMovedAfterSearch) {
+ var el = e.target;
+ // to retrieve the real "owner" of the event.
+ while (el.tagName !== "TR") {
+ el = el.parentNode;
+ }
+ clearTimeout(hoverTimeout);
+ hoverTimeout = setTimeout(function() {
+ onEachLazy(document.getElementsByClassName("search-results"), function(e) {
+ onEachLazy(e.getElementsByClassName("result"), function(i_e) {
+ removeClass(i_e, "highlighted");
+ });
});
- });
- addClass(el, "highlighted");
- }, 20);
+ addClass(el, "highlighted");
+ }, 20);
+ }
};
onEachLazy(document.getElementsByClassName("search-results"), function(e) {
onEachLazy(e.getElementsByClassName("result"), function(i_e) {
addClass(actives[currentTab][0].previousElementSibling, "highlighted");
removeClass(actives[currentTab][0], "highlighted");
+ e.preventDefault();
} else if (e.which === 40) { // down
if (!actives[currentTab].length) {
var results = document.getElementById("results").childNodes;
addClass(actives[currentTab][0].nextElementSibling, "highlighted");
removeClass(actives[currentTab][0], "highlighted");
}
+ e.preventDefault();
} else if (e.which === 13) { // return
if (actives[currentTab].length) {
document.location.href =
border-style: solid;
}
-.tooltip.compile_fail, .tooltip.ignore {
+.tooltip.compile_fail, .tooltip.should_panic, .tooltip.ignore {
font-weight: bold;
font-size: 20px;
}
border-left: 2px solid #f00;
}
+pre.should_panic {
+ border-left: 2px solid rgba(255,0,0,.8);
+}
+
+pre.should_panic:hover, .information:hover + pre.should_panic {
+ border-left: 2px solid #f00;
+}
+
pre.ignore {
border-left: 2px solid rgba(255,142,0,.6);
}
color: #f00;
}
+.tooltip.should_panic {
+ color: rgba(255,0,0,.8);
+}
+
+.information > .should_panic:hover {
+ color: #f00;
+}
+
.tooltip.ignore {
color: rgba(255,142,0,.6);
}
border-left: 2px solid #f00;
}
+pre.should_panic {
+ border-left: 2px solid rgba(255,0,0,.5);
+}
+
+pre.should_panic:hover, .information:hover + pre.should_panic {
+ border-left: 2px solid #f00;
+}
+
pre.ignore {
border-left: 2px solid rgba(255,142,0,.6);
}
color: #f00;
}
+.tooltip.should_panic {
+ color: rgba(255,0,0,.5);
+}
+
+.information > .should_panic:hover {
+ color: #f00;
+}
+
.tooltip.ignore {
color: rgba(255,142,0,.6);
}
#![feature(nll)]
#![feature(or_patterns)]
#![feature(test)]
-#![feature(vec_remove_item)]
#![feature(ptr_offset_from)]
#![feature(crate_visibility_modifier)]
#![feature(never_type)]
o.optmulti(
"",
"passes",
- "list of passes to also run, you might want \
- to pass it multiple times; a value of `list` \
- will print available passes",
+ "list of passes to also run, you might want to pass it multiple times; a value of \
+ `list` will print available passes",
"PASSES",
)
}),
"e",
"extend-css",
"To add some CSS rules with a given file to generate doc with your \
- own theme. However, your theme might break if the rustdoc's generated HTML \
- changes, so be careful!",
+ own theme. However, your theme might break if the rustdoc's generated HTML \
+ changes, so be careful!",
"PATH",
)
}),
"",
"playground-url",
"URL to send code snippets to, may be reset by --markdown-playground-url \
- or `#![doc(html_playground_url=...)]`",
+ or `#![doc(html_playground_url=...)]`",
"URL",
)
}),
o.optflag(
"",
"sort-modules-by-appearance",
- "sort modules by where they appear in the \
- program, rather than alphabetically",
+ "sort modules by where they appear in the program, rather than alphabetically",
)
}),
stable("theme", |o| {
"",
"static-root-path",
"Path string to force loading static files from in output pages. \
- If not set, uses combinations of '../' to reach the documentation root.",
+ If not set, uses combinations of '../' to reach the documentation root.",
"PATH",
)
}),
let result = cx.enter_resolver(|resolver| {
resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
});
+ debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
let result = match result {
Ok((_, Res::Err)) => Err(ErrorKind::ResolutionFailure),
_ => result.map_err(|_| ErrorKind::ResolutionFailure),
}
return Ok((res, Some(path_str.to_owned())));
}
- _ => return Ok((res, extra_fragment.clone())),
+ other => {
+ debug!(
+ "failed to resolve {} in namespace {:?} (got {:?})",
+ path_str, ns, other
+ );
+ return Ok((res, extra_fragment.clone()));
+ }
};
if value != (ns == ValueNS) {
} else {
(parts[0].to_owned(), None)
};
+ let resolved_self;
+ let mut path_str;
let (res, fragment) = {
let mut kind = None;
- let mut path_str = if let Some(prefix) =
- ["struct@", "enum@", "type@", "trait@", "union@"]
- .iter()
- .find(|p| link.starts_with(**p))
+ path_str = if let Some(prefix) = ["struct@", "enum@", "type@", "trait@", "union@"]
+ .iter()
+ .find(|p| link.starts_with(**p))
{
kind = Some(TypeNS);
link.trim_start_matches(prefix)
let base_node =
if item.is_mod() && item.attrs.inner_docs { None } else { parent_node };
- let resolved_self;
// replace `Self` with suitable item's parent name
if path_str.starts_with("Self::") {
if let Some(ref name) = parent_name {
if let Res::PrimTy(_) = res {
item.attrs.links.push((ori_link, None, fragment));
} else {
+ debug!("intra-doc link to {} resolved to {:?}", path_str, res);
+ if let Some(local) = res.opt_def_id().and_then(|def_id| def_id.as_local()) {
+ use rustc_hir::def_id::LOCAL_CRATE;
+
+ let hir_id = self.cx.tcx.hir().as_local_hir_id(local);
+ if !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_id)
+ && !self.cx.render_options.document_private
+ {
+ let item_name = item.name.as_deref().unwrap_or("<unknown>");
+ let err_msg = format!(
+ "public documentation for `{}` links to a private item",
+ item_name
+ );
+ build_diagnostic(
+ cx,
+ &item,
+ path_str,
+ &dox,
+ link_range,
+ &err_msg,
+ "this item is private",
+ None,
+ );
+ continue;
+ }
+ }
let id = register_res(cx, res);
item.attrs.links.push((ori_link, Some(id), fragment));
}
}
// Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade.
-fn scrape_test_config(krate: &::rustc_hir::Crate) -> TestOptions {
+fn scrape_test_config(krate: &::rustc_hir::Crate<'_>) -> TestOptions {
use rustc_ast_pretty::pprust;
let mut opts =
intravisit::NestedVisitorMap::All(self.map)
}
- fn visit_item(&mut self, item: &'hir hir::Item) {
+ fn visit_item(&mut self, item: &'hir hir::Item<'_>) {
let name = if let hir::ItemKind::Impl { ref self_ty, .. } = item.kind {
rustc_hir_pretty::id_to_string(&self.map, self_ty.hir_id)
} else {
});
}
- fn visit_trait_item(&mut self, item: &'hir hir::TraitItem) {
+ fn visit_trait_item(&mut self, item: &'hir hir::TraitItem<'_>) {
self.visit_testable(item.ident.to_string(), &item.attrs, item.hir_id, item.span, |this| {
intravisit::walk_trait_item(this, item);
});
}
- fn visit_impl_item(&mut self, item: &'hir hir::ImplItem) {
+ fn visit_impl_item(&mut self, item: &'hir hir::ImplItem<'_>) {
self.visit_testable(item.ident.to_string(), &item.attrs, item.hir_id, item.span, |this| {
intravisit::walk_impl_item(this, item);
});
}
- fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem) {
+ fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem<'_>) {
self.visit_testable(item.ident.to_string(), &item.attrs, item.hir_id, item.span, |this| {
intravisit::walk_foreign_item(this, item);
});
fn visit_variant(
&mut self,
- v: &'hir hir::Variant,
- g: &'hir hir::Generics,
+ v: &'hir hir::Variant<'_>,
+ g: &'hir hir::Generics<'_>,
item_id: hir::HirId,
) {
self.visit_testable(v.ident.to_string(), &v.attrs, v.id, v.span, |this| {
});
}
- fn visit_struct_field(&mut self, f: &'hir hir::StructField) {
+ fn visit_struct_field(&mut self, f: &'hir hir::StructField<'_>) {
self.visit_testable(f.ident.to_string(), &f.attrs, f.hir_id, f.span, |this| {
intravisit::walk_struct_field(this, f);
});
}
- fn visit_macro_def(&mut self, macro_def: &'hir hir::MacroDef) {
+ fn visit_macro_def(&mut self, macro_def: &'hir hir::MacroDef<'_>) {
self.visit_testable(
macro_def.ident.to_string(),
¯o_def.attrs,
self.exact_paths.entry(did).or_insert_with(|| def_id_to_path(tcx, did));
}
- pub fn visit(mut self, krate: &'tcx hir::Crate) -> Module<'tcx> {
+ pub fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> {
let mut module = self.visit_mod_contents(
krate.item.span,
krate.item.attrs,
fn visit_variant_data(
&mut self,
- item: &'tcx hir::Item,
+ item: &'tcx hir::Item<'_>,
name: Symbol,
- sd: &'tcx hir::VariantData,
- generics: &'tcx hir::Generics,
+ sd: &'tcx hir::VariantData<'_>,
+ generics: &'tcx hir::Generics<'_>,
) -> Struct<'tcx> {
debug!("visiting struct");
let struct_type = struct_type_from_def(&*sd);
fn visit_union_data(
&mut self,
- item: &'tcx hir::Item,
+ item: &'tcx hir::Item<'_>,
name: Symbol,
- sd: &'tcx hir::VariantData,
- generics: &'tcx hir::Generics,
+ sd: &'tcx hir::VariantData<'_>,
+ generics: &'tcx hir::Generics<'_>,
) -> Union<'tcx> {
debug!("visiting union");
let struct_type = struct_type_from_def(&*sd);
fn visit_enum_def(
&mut self,
- it: &'tcx hir::Item,
+ it: &'tcx hir::Item<'_>,
name: Symbol,
- def: &'tcx hir::EnumDef,
- generics: &'tcx hir::Generics,
+ def: &'tcx hir::EnumDef<'_>,
+ generics: &'tcx hir::Generics<'_>,
) -> Enum<'tcx> {
debug!("visiting enum");
Enum {
fn visit_fn(
&mut self,
om: &mut Module<'tcx>,
- item: &'tcx hir::Item,
+ item: &'tcx hir::Item<'_>,
name: Symbol,
- decl: &'tcx hir::FnDecl,
+ decl: &'tcx hir::FnDecl<'_>,
header: hir::FnHeader,
- generics: &'tcx hir::Generics,
+ generics: &'tcx hir::Generics<'_>,
body: hir::BodyId,
) {
debug!("visiting fn");
&mut self,
span: Span,
attrs: &'tcx [ast::Attribute],
- vis: &'tcx hir::Visibility,
+ vis: &'tcx hir::Visibility<'_>,
id: hir::HirId,
m: &'tcx hir::Mod<'tcx>,
name: Option<Symbol>,
ret
}
- fn visit_item(&mut self, item: &'tcx hir::Item, renamed: Option<Ident>, om: &mut Module<'tcx>) {
+ fn visit_item(
+ &mut self,
+ item: &'tcx hir::Item<'_>,
+ renamed: Option<Ident>,
+ om: &mut Module<'tcx>,
+ ) {
debug!("visiting item {:?}", item);
let ident = renamed.unwrap_or(item.ident);
fn visit_foreign_item(
&mut self,
- item: &'tcx hir::ForeignItem,
+ item: &'tcx hir::ForeignItem<'_>,
renamed: Option<Ident>,
om: &mut Module<'tcx>,
) {
}
// Convert each `exported_macro` into a doc item.
- fn visit_local_macro(&self, def: &'tcx hir::MacroDef, renamed: Option<Symbol>) -> Macro<'tcx> {
+ fn visit_local_macro(
+ &self,
+ def: &'tcx hir::MacroDef<'_>,
+ renamed: Option<Symbol>,
+ ) -> Macro<'tcx> {
debug!("visit_local_macro: {}", def.ident);
let tts = def.ast.body.inner_tokens().trees().collect::<Vec<_>>();
// Extract the spans of all matchers. They represent the "interface" of the macro.
threads = 125
# Maximum heap size
heap_size = 0x8000000
+
+[[bench]]
+name = "stdbenches"
+path = "benches/lib.rs"
+test = true
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn asinh(self) -> f32 {
- if self == Self::NEG_INFINITY {
- Self::NEG_INFINITY
- } else {
- (self + ((self * self) + 1.0).sqrt()).ln().copysign(self)
- }
+ (self.abs() + ((self * self) + 1.0).sqrt()).ln().copysign(self)
}
/// Inverse hyperbolic cosine function.
assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271
assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
+ // regression test for the catastrophic cancellation fixed in 72486
+ assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32);
}
#[test]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn asinh(self) -> f64 {
- if self == Self::NEG_INFINITY {
- Self::NEG_INFINITY
- } else {
- (self + ((self * self) + 1.0).sqrt()).ln().copysign(self)
- }
+ (self.abs() + ((self * self) + 1.0).sqrt()).ln().copysign(self)
}
/// Inverse hyperbolic cosine function.
// issue 63271
assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64);
assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64);
+ // regression test for the catastrophic cancellation fixed in 72486
+ assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083);
}
#[test]
/// [`is_dir`], and will be false for symlink metadata
/// obtained from [`symlink_metadata`].
///
+ /// When the goal is simply to read from (or write to) the source, the most
+ /// reliable way to test the source can be read (or written to) is to open
+ /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
+ /// a Unix-like system for example. See [`File::open`] or
+ /// [`OpenOptions::open`] for more information.
+ ///
/// [`is_dir`]: struct.Metadata.html#method.is_dir
/// [`symlink_metadata`]: fn.symlink_metadata.html
+ /// [`File::open`]: struct.File.html#method.open
+ /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
///
/// # Examples
///
/// [`is_dir`] and [`is_symlink`]; only zero or one of these
/// tests may pass.
///
+ /// When the goal is simply to read from (or write to) the source, the most
+ /// reliable way to test the source can be read (or written to) is to open
+ /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
+ /// a Unix-like system for example. See [`File::open`] or
+ /// [`OpenOptions::open`] for more information.
+ ///
/// [`is_dir`]: struct.FileType.html#method.is_dir
/// [`is_symlink`]: struct.FileType.html#method.is_symlink
+ /// [`File::open`]: struct.File.html#method.open
+ /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
///
/// # Examples
///
/// Returns the metadata for the file that this entry points at.
///
/// This function will not traverse symlinks if this entry points at a
- /// symlink.
+ /// symlink. To traverse symlinks use [`fs::metadata`] or [`fs::File::metadata`].
+ ///
+ /// [`fs::metadata`]: fn.metadata.html
+ /// [`fs::File::metadata`]: struct.File.html#method.metadata
///
/// # Platform-specific behavior
///
/// in memory, like a `Vec<u8>`.
///
/// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though
-/// dropping will attempt to flush the the contents of the buffer, any errors
+/// dropping will attempt to flush the contents of the buffer, any errors
/// that happen in the process of dropping will be ignored. Calling [`flush`]
/// ensures that the buffer is empty and thus dropping will not even attempt
/// file operations.
#[stable(feature = "rust1", since = "1.0.0")]
Interrupted,
/// Any I/O error not part of this list.
+ ///
+ /// Errors that are `Other` now may move to a different or a new
+ /// [`ErrorKind`] variant in the future. It is not recommended to match
+ /// an error against `Other` and to expect any additional characteristics,
+ /// e.g., a specific [`Error::raw_os_error`] return value.
#[stable(feature = "rust1", since = "1.0.0")]
Other,
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
+
+ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+ self.0.read_to_end(buf)
+ }
+
+ fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
+ self.0.read_to_string(buf)
+ }
+
+ fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+ self.0.read_exact(buf)
+ }
}
+
impl Write for StdoutRaw {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
+
+ fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+ self.0.write_all(buf)
+ }
+
+ fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+ self.0.write_all_vectored(bufs)
+ }
+
+ fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
+ self.0.write_fmt(fmt)
+ }
}
+
impl Write for StderrRaw {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
+
+ fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+ self.0.write_all(buf)
+ }
+
+ fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+ self.0.write_all_vectored(bufs)
+ }
+
+ fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
+ self.0.write_fmt(fmt)
+ }
}
enum Maybe<T> {
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
+
+ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+ self.inner.read_to_end(buf)
+ }
+
+ fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
+ self.inner.read_to_string(buf)
+ }
+
+ fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+ self.inner.read_exact(buf)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.inner.fill_buf()
}
+
fn consume(&mut self, n: usize) {
self.inner.consume(n)
}
+
+ fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
+ self.inner.read_until(byte, buf)
+ }
+
+ fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
+ self.inner.read_line(buf)
+ }
}
#[stable(feature = "std_debug", since = "1.16.0")]
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.lock().write_all(buf)
}
+ fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+ self.lock().write_all_vectored(bufs)
+ }
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
self.lock().write_fmt(args)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.borrow_mut().flush()
}
+ fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+ self.inner.borrow_mut().write_all(buf)
+ }
+ fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+ self.inner.borrow_mut().write_all_vectored(bufs)
+ }
}
#[stable(feature = "std_debug", since = "1.16.0")]
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.lock().write_all(buf)
}
+ fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+ self.lock().write_all_vectored(bufs)
+ }
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
self.lock().write_fmt(args)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.borrow_mut().flush()
}
+ fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+ self.inner.borrow_mut().write_all(buf)
+ }
+ fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+ self.inner.borrow_mut().write_all_vectored(bufs)
+ }
}
#[stable(feature = "std_debug", since = "1.16.0")]
//
/// Organize code into [modules].
///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// Use `mod` to create new [modules] to encapsulate code, including other
+/// modules:
+///
+/// ```
+/// mod foo {
+/// mod bar {
+/// type MyType = (u8, u8);
+/// fn baz() {}
+/// }
+/// }
+/// ```
+///
+/// Like [`struct`]s and [`enum`]s, a module and its content are private by
+/// default, unaccessible to code outside of the module.
+///
+/// To learn more about allowing access, see the documentation for the [`pub`]
+/// keyword.
///
+/// [`enum`]: keyword.enum.html
+/// [`pub`]: keyword.pub.html
+/// [`struct`]: keyword.struct.html
/// [modules]: ../reference/items/modules.html
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
mod mod_keyword {}
#[doc(keyword = "move")]
#[doc(keyword = "mut")]
//
-/// A mutable binding, reference, or pointer.
+/// A mutable variable, reference, or pointer.
///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// `mut` can be used in several situations. The first is mutable variables,
+/// which can be used anywhere you can bind a value to a variable name. Some
+/// examples:
///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// ```rust
+/// // A mutable variable in the parameter list of a function.
+/// fn foo(mut x: u8, y: u8) -> u8 {
+/// x += y;
+/// x
+/// }
+///
+/// // Modifying a mutable variable.
+/// # #[allow(unused_assignments)]
+/// let mut a = 5;
+/// a = 6;
+///
+/// assert_eq!(foo(3, 4), 7);
+/// assert_eq!(a, 6);
+/// ```
+///
+/// The second is mutable references. They can be created from `mut` variables
+/// and must be unique: no other variables can have a mutable reference, nor a
+/// shared reference.
+///
+/// ```rust
+/// // Taking a mutable reference.
+/// fn push_two(v: &mut Vec<u8>) {
+/// v.push(2);
+/// }
+///
+/// // A mutable reference cannot be taken to a non-mutable variable.
+/// let mut v = vec![0, 1];
+/// // Passing a mutable reference.
+/// push_two(&mut v);
+///
+/// assert_eq!(v, vec![0, 1, 2]);
+/// ```
+///
+/// ```rust,compile_fail,E0502
+/// let mut v = vec![0, 1];
+/// let mut_ref_v = &mut v;
+/// ##[allow(unused)]
+/// let ref_v = &v;
+/// mut_ref_v.push(2);
+/// ```
+///
+/// Mutable raw pointers work much like mutable references, with the added
+/// possibility of not pointing to a valid object. The syntax is `*mut Type`.
+///
+/// More information on mutable references and pointers can be found in```
+/// [Reference].
+///
+/// [Reference]: ../reference/types/pointer.html#mutable-references-mut
mod mut_keyword {}
#[doc(keyword = "pub")]
//
/// Return a value from a function.
///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// A `return` marks the end of an execution path in a function:
///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// ```
+/// fn foo() -> i32 {
+/// return 3;
+/// }
+/// assert_eq!(foo(), 3);
+/// ```
+///
+/// `return` is not needed when the returned value is the last expression in the
+/// function. In this case the `;` is omitted:
+///
+/// ```
+/// fn foo() -> i32 {
+/// 3
+/// }
+/// assert_eq!(foo(), 3);
+/// ```
+///
+/// `return` returns from the function immediately (an "early return"):
+///
+/// ```no_run
+/// use std::fs::File;
+/// use std::io::{Error, ErrorKind, Read, Result};
+///
+/// fn main() -> Result<()> {
+/// let mut file = match File::open("foo.txt") {
+/// Ok(f) => f,
+/// Err(e) => return Err(e),
+/// };
+///
+/// let mut contents = String::new();
+/// let size = match file.read_to_string(&mut contents) {
+/// Ok(s) => s,
+/// Err(e) => return Err(e),
+/// };
+///
+/// if contents.contains("impossible!") {
+/// return Err(Error::new(ErrorKind::Other, "oh no!"));
+/// }
+///
+/// if size > 9000 {
+/// return Err(Error::new(ErrorKind::Other, "over 9000!"));
+/// }
+///
+/// assert_eq!(contents, "Hello, world!");
+/// Ok(())
+/// }
+/// ```
mod return_keyword {}
#[doc(keyword = "self")]
//
/// The receiver of a method, or the current module.
///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// `self` is used in two situations: referencing the current module and marking
+/// the receiver of a method.
///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// In paths, `self` can be used to refer to the current module, either in a
+/// [`use`] statement or in a path to access an element:
+///
+/// ```
+/// # #![allow(unused_imports)]
+/// use std::io::{self, Read};
+/// ```
+///
+/// Is functionally the same as:
+///
+/// ```
+/// # #![allow(unused_imports)]
+/// use std::io;
+/// use std::io::Read;
+/// ```
+///
+/// Using `self` to access an element in the current module:
+///
+/// ```
+/// # #![allow(dead_code)]
+/// # fn main() {}
+/// fn foo() {}
+/// fn bar() {
+/// self::foo()
+/// }
+/// ```
+///
+/// `self` as the current receiver for a method allows to omit the parameter
+/// type most of the time. With the exception of this particularity, `self` is
+/// used much like any other parameter:
+///
+/// ```
+/// struct Foo(i32);
+///
+/// impl Foo {
+/// // No `self`.
+/// fn new() -> Self {
+/// Self(0)
+/// }
+///
+/// // Consuming `self`.
+/// fn consume(self) -> Self {
+/// Self(self.0 + 1)
+/// }
+///
+/// // Borrowing `self`.
+/// fn borrow(&self) -> &i32 {
+/// &self.0
+/// }
+///
+/// // Borrowing `self` mutably.
+/// fn borrow_mut(&mut self) -> &mut i32 {
+/// &mut self.0
+/// }
+/// }
+///
+/// // This method must be called with a `Type::` prefix.
+/// let foo = Foo::new();
+/// assert_eq!(foo.0, 0);
+///
+/// // Those two calls produces the same result.
+/// let foo = Foo::consume(foo);
+/// assert_eq!(foo.0, 1);
+/// let foo = foo.consume();
+/// assert_eq!(foo.0, 2);
+///
+/// // Borrowing is handled automatically with the second syntax.
+/// let borrow_1 = Foo::borrow(&foo);
+/// let borrow_2 = foo.borrow();
+/// assert_eq!(borrow_1, borrow_2);
+///
+/// // Borrowing mutably is handled automatically too with the second syntax.
+/// let mut foo = Foo::new();
+/// *Foo::borrow_mut(&mut foo) += 1;
+/// assert_eq!(foo.0, 1);
+/// *foo.borrow_mut() += 1;
+/// assert_eq!(foo.0, 2);
+/// ```
+///
+/// Note that this automatic conversion when calling `foo.method()` is not
+/// limited to the examples above. See the [Reference] for more information.
+///
+/// [`use`]: keyword.use.html
+/// [Reference]: ../reference/items/associated-items.html#methods
mod self_keyword {}
#[doc(keyword = "Self")]
/// The implementing type within a [`trait`] or [`impl`] block, or the current type within a type
/// definition.
///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// Within a type definition:
+///
+/// ```
+/// # #![allow(dead_code)]
+/// struct Node {
+/// elem: i32,
+/// // `Self` is a `Node` here.
+/// next: Option<Box<Self>>,
+/// }
+/// ```
+///
+/// In an [`impl`] block:
+///
+/// ```
+/// struct Foo(i32);
+///
+/// impl Foo {
+/// fn new() -> Self {
+/// Self(0)
+/// }
+/// }
+///
+/// assert_eq!(Foo::new().0, Foo(0).0);
+/// ```
+///
+/// Generic parameters are implicit with `Self`:
+///
+/// ```
+/// # #![allow(dead_code)]
+/// struct Wrap<T> {
+/// elem: T,
+/// }
+///
+/// impl<T> Wrap<T> {
+/// fn new(elem: T) -> Self {
+/// Self { elem }
+/// }
+/// }
+/// ```
+///
+/// In a [`trait`] definition and related [`impl`] block:
+///
+/// ```
+/// trait Example {
+/// fn example() -> Self;
+/// }
+///
+/// struct Foo(i32);
+///
+/// impl Example for Foo {
+/// fn example() -> Self {
+/// Self(42)
+/// }
+/// }
+///
+/// assert_eq!(Foo::example().0, Foo(42).0);
+/// ```
///
/// [`impl`]: keyword.impl.html
/// [`trait`]: keyword.trait.html
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
mod self_upper_keyword {}
#[doc(keyword = "static")]
//
/// The parent of the current [module].
///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// ```rust
+/// # #![allow(dead_code)]
+/// # fn main() {}
+/// mod a {
+/// pub fn foo() {}
+/// }
+/// mod b {
+/// pub fn foo() {
+/// super::a::foo(); // call a's foo function
+/// }
+/// }
+/// ```
+///
+/// It is also possible to use `super` multiple times: `super::super::foo`,
+/// going up the ancestor chain.
+///
+/// See the [Reference] for more information.
///
/// [module]: ../reference/items/modules.html
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// [Reference]: ../reference/paths.html#super
mod super_keyword {}
#[doc(keyword = "trait")]
#![feature(prelude_import)]
#![feature(ptr_internals)]
#![feature(raw)]
+#![feature(raw_ref_macros)]
#![feature(renamed_spin_loop)]
#![feature(rustc_attrs)]
#![feature(rustc_private)]
}
}
+#[stable(feature = "string_u16_to_socket_addrs", since = "1.46.0")]
+impl ToSocketAddrs for (String, u16) {
+ type Iter = vec::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
+ (&*self.0, self.1).to_socket_addrs()
+ }
+}
+
// accepts strings like 'localhost:12345'
#[stable(feature = "rust1", since = "1.0.0")]
impl ToSocketAddrs for str {
#![stable(feature = "metadata_ext", since = "1.1.0")]
-use libc;
-
use crate::fs::Metadata;
use crate::sys_common::AsInner;
fn default_hook(info: &PanicInfo<'_>) {
// If this is a double panic, make sure that we print a backtrace
// for this panic. Otherwise only print it if logging is enabled.
- let backtrace_env = if update_panic_count(0) >= 2 {
+ let backtrace_env = if panic_count::get() >= 2 {
RustBacktrace::Print(backtrace_rs::PrintFmt::Full)
} else {
backtrace::rust_backtrace_env()
#[cfg(not(test))]
#[doc(hidden)]
#[unstable(feature = "update_panic_count", issue = "none")]
-pub fn update_panic_count(amt: isize) -> usize {
+pub mod panic_count {
use crate::cell::Cell;
- thread_local! { static PANIC_COUNT: Cell<usize> = Cell::new(0) }
+ use crate::sync::atomic::{AtomicUsize, Ordering};
+
+ // Panic count for the current thread.
+ thread_local! { static LOCAL_PANIC_COUNT: Cell<usize> = Cell::new(0) }
+
+ // Sum of panic counts from all threads. The purpose of this is to have
+ // a fast path in `is_zero` (which is used by `panicking`). Access to
+ // this variable can be always be done with relaxed ordering because
+ // it is always guaranteed that, if `GLOBAL_PANIC_COUNT` is zero,
+ // `LOCAL_PANIC_COUNT` will be zero.
+ static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0);
+
+ pub fn increase() -> usize {
+ GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed);
+ LOCAL_PANIC_COUNT.with(|c| {
+ let next = c.get() + 1;
+ c.set(next);
+ next
+ })
+ }
+
+ pub fn decrease() -> usize {
+ GLOBAL_PANIC_COUNT.fetch_sub(1, Ordering::Relaxed);
+ LOCAL_PANIC_COUNT.with(|c| {
+ let next = c.get() - 1;
+ c.set(next);
+ next
+ })
+ }
- PANIC_COUNT.with(|c| {
- let next = (c.get() as isize + amt) as usize;
- c.set(next);
- next
- })
+ pub fn get() -> usize {
+ LOCAL_PANIC_COUNT.with(|c| c.get())
+ }
+
+ #[inline]
+ pub fn is_zero() -> bool {
+ if GLOBAL_PANIC_COUNT.load(Ordering::Relaxed) == 0 {
+ // Fast path: if `GLOBAL_PANIC_COUNT` is zero, all threads
+ // (including the current one) will have `LOCAL_PANIC_COUNT`
+ // equal to zero, so TLS access can be avoided.
+ true
+ } else {
+ is_zero_slow_path()
+ }
+ }
+
+ // Slow path is in a separate function to reduce the amount of code
+ // inlined from `is_zero`.
+ #[inline(never)]
+ #[cold]
+ fn is_zero_slow_path() -> bool {
+ LOCAL_PANIC_COUNT.with(|c| c.get() == 0)
+ }
}
#[cfg(test)]
-pub use realstd::rt::update_panic_count;
+pub use realstd::rt::panic_count;
/// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
#[cold]
unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send + 'static> {
let obj = Box::from_raw(__rust_panic_cleanup(payload));
- update_panic_count(-1);
+ panic_count::decrease();
obj
}
}
/// Determines whether the current thread is unwinding because of panic.
+#[inline]
pub fn panicking() -> bool {
- update_panic_count(0) != 0
+ !panic_count::is_zero()
}
/// The entry point for panicking with a formatted message.
message: Option<&fmt::Arguments<'_>>,
location: &Location<'_>,
) -> ! {
- let panics = update_panic_count(1);
+ let panics = panic_count::increase();
// If this is the third nested call (e.g., panics == 2, this is 0-indexed),
// the panic hook probably triggered the last panic, otherwise the
/// This is the entry point for `resume_unwind`.
/// It just forwards the payload to the panic runtime.
pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
- update_panic_count(1);
+ panic_count::increase();
struct RewrapBox(Box<dyn Any + Send>);
/// # See Also
///
/// This is a convenience function that coerces errors to false. If you want to
- /// check errors, call [fs::metadata] and handle its Result. Then call
- /// [fs::Metadata::is_file] if it was Ok.
- ///
- /// [fs::metadata]: ../../std/fs/fn.metadata.html
- /// [fs::Metadata::is_file]: ../../std/fs/struct.Metadata.html#method.is_file
+ /// check errors, call [`fs::metadata`] and handle its Result. Then call
+ /// [`fs::Metadata::is_file`] if it was Ok.
+ ///
+ /// When the goal is simply to read from (or write to) the source, the most
+ /// reliable way to test the source can be read (or written to) is to open
+ /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
+ /// a Unix-like system for example. See [`File::open`] or
+ /// [`OpenOptions::open`] for more information.
+ ///
+ /// [`fs::metadata`]: ../../std/fs/fn.metadata.html
+ /// [`fs::Metadata`]: ../../std/fs/struct.Metadata.html
+ /// [`fs::Metadata::is_file`]: ../../std/fs/struct.Metadata.html#method.is_file
+ /// [`File::open`]: ../../std/fs/struct.File.html#method.open
+ /// [`OpenOptions::open`]: ../../std/fs/struct.OpenOptions.html#method.open
#[stable(feature = "path_ext", since = "1.5.0")]
pub fn is_file(&self) -> bool {
fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
//! things, particularly traits, which are used in almost every single Rust
//! program.
//!
-//! On a technical level, Rust inserts
-//!
-//! ```
-//! # #[allow(unused_extern_crates)]
-//! extern crate std;
-//! ```
-//!
-//! into the crate root of every crate, and
-//!
-//! ```
-//! # #[allow(unused_imports)]
-//! use std::prelude::v1::*;
-//! ```
-//!
-//! into every module.
-//!
//! # Other preludes
//!
//! Preludes can be seen as a pattern to make using multiple types more
#![doc(hidden)]
// Re-export some of our utilities which are expected by other crates.
-pub use crate::panicking::{begin_panic, begin_panic_fmt, update_panic_count};
+pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count};
// To reduce the generated code of the new `lang_start`, this function is doing
// the real work.
pub fn new() -> io::Result<Stdin> {
Ok(Stdin)
}
+}
- pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+impl io::Read for Stdin {
+ fn read(&mut self, data: &mut [u8]) -> io::Result<usize> {
self.read_vectored(&mut [IoSliceMut::new(data)])
}
- pub fn read_vectored(&self, _data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- //ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDIN_FILENO as u32) })
- // .read(data)
+ fn read_vectored(&mut self, _data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
Ok(0)
}
#[inline]
- pub fn is_read_vectored(&self) -> bool {
+ fn is_read_vectored(&self) -> bool {
true
}
}
pub fn new() -> io::Result<Stdout> {
Ok(Stdout)
}
+}
- pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+impl io::Write for Stdout {
+ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
let len;
unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
}
}
- pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
+ fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
let len;
unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
}
#[inline]
- pub fn is_write_vectored(&self) -> bool {
+ fn is_write_vectored(&self) -> bool {
true
}
- pub fn flush(&self) -> io::Result<()> {
+ fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
pub fn new() -> io::Result<Stderr> {
Ok(Stderr)
}
+}
- pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+impl io::Write for Stderr {
+ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
let len;
unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
}
}
- pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
+ fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
let len;
unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
}
#[inline]
- pub fn is_write_vectored(&self) -> bool {
+ fn is_write_vectored(&self) -> bool {
true
}
- pub fn flush(&self) -> io::Result<()> {
- Ok(())
- }
-}
-
-impl io::Write for Stderr {
- fn write(&mut self, data: &[u8]) -> io::Result<usize> {
- (&*self).write(data)
- }
fn flush(&mut self) -> io::Result<()> {
- (&*self).flush()
+ Ok(())
}
}
.long 1 /* type = NT_VERSION */
0: .asciz "toolchain-version" /* name */
1: .align 4
-2: .long 0 /* desc - toolchain version number, 32-bit LE */
+2: .long 1 /* desc - toolchain version number, 32-bit LE */
3: .align 4
.section .rodata
.Lxsave_clear:
.org .+24
.Lxsave_mxcsr:
- .int 0
+ .short 0x1f80
/* We can store a bunch of data in the gap between MXCSR and the XSAVE header */
-/* MXCSR initialization value for ABI */
-.Lmxcsr_init:
- .int 0x1f80
-
-/* x87 FPU control word initialization value for ABI */
-.Lfpucw_init:
- .int 0x037f
-
/* The following symbols point at read-only data that will be filled in by the */
/* post-linker. */
globvar TEXT_BASE 8
/* The size in bytes of enclacve text section */
globvar TEXT_SIZE 8
- /* The base address (relative to enclave start) of the enclave EH_FRM_HDR section */
- globvar EH_FRM_HDR_BASE 8
- /* The size in bytes of enclacve EH_FRM_HDR section */
- globvar EH_FRM_HDR_SIZE 8
+ /* The base address (relative to enclave start) of the enclave .eh_frame_hdr section */
+ globvar EH_FRM_HDR_OFFSET 8
+ /* The size in bytes of enclave .eh_frame_hdr section */
+ globvar EH_FRM_HDR_LEN 8
+ /* The base address (relative to enclave start) of the enclave .eh_frame section */
+ globvar EH_FRM_OFFSET 8
+ /* The size in bytes of enclacve .eh_frame section */
+ globvar EH_FRM_LEN 8
.org .Lxsave_clear+512
.Lxsave_header:
jz .Lskip_debug_init
mov %r10,%gs:tcsls_debug_panic_buf_ptr
.Lskip_debug_init:
+/* reset cpu state */
+ mov %rdx, %r10
+ mov $-1, %rax
+ mov $-1, %rdx
+ xrstor .Lxsave_clear(%rip)
+ mov %r10, %rdx
+
/* check if returning from usercall */
mov %gs:tcsls_last_rsp,%r11
test %r11,%r11
jnz .Lusercall_ret
-/* reset user state */
- ldmxcsr .Lmxcsr_init(%rip)
- fldcw .Lfpucw_init(%rip)
/* setup stack */
mov %gs:tcsls_tos,%rsp /* initially, RSP is not set to the correct value */
/* here. This is fixed below under "adjust stack". */
// able to specify this
#[cfg(not(test))]
#[no_mangle]
+#[allow(improper_ctypes_definitions)]
extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) {
// FIXME: how to support TLS in library mode?
let tls = Box::new(tls::Tls::new());
#[cfg(target_arch = "aarch64")]
extern "C" {
fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
+ #[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))]
#[link_name = "objc_msgSend"]
fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
}
#[cfg(not(target_arch = "aarch64"))]
extern "C" {
fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
+ #[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))]
#[link_name = "objc_msgSend"]
fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
}
/// let permissions = metadata.permissions();
///
/// println!("permissions: {:o}", permissions.mode());
- /// Ok(()) }
+ /// Ok(())
+ /// }
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&self) -> u32;
///
/// permissions.set_mode(0o644); // Read/write for owner and read for others.
/// assert_eq!(permissions.mode(), 0o644);
- /// Ok(()) }
+ /// Ok(())
+ /// }
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn set_mode(&mut self, mode: u32);
//! Unix-specific networking functionality
-#[cfg(unix)]
-use libc;
-
// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
#[cfg(not(unix))]
#[allow(non_camel_case_types)]
// ignored there.
#[cfg_attr(target_arch = "arm", ignore)]
#[cfg_attr(target_arch = "aarch64", ignore)]
+ #[cfg_attr(target_arch = "riscv64", ignore)]
fn test_process_mask() {
unsafe {
// Test to make sure that a signal mask does not get inherited.
use crate::ffi::{CStr, OsString};
use crate::marker::PhantomData;
use crate::ptr;
- use libc;
use crate::sys_common::mutex::Mutex;
use crate::sys;
use crate::sys::platform::fs::MetadataExt as UnixMetadataExt;
use crate::sys_common::{AsInner, AsInnerMut, FromInner};
-use libc;
/// Unix-specific extensions to [`File`].
///
mod imp {
use crate::io;
use core::sync::atomic::{AtomicBool, Ordering::Relaxed};
- use libc;
pub fn fill_bytes(v: &mut [u8]) {
static RNG_INIT: AtomicBool = AtomicBool::new(false);
use crate::cell::UnsafeCell;
use crate::sync::atomic::{AtomicUsize, Ordering};
-use libc;
pub struct RWLock {
inner: UnsafeCell<libc::pthread_rwlock_t>,
use crate::cmp::Ordering;
use crate::time::Duration;
use ::core::hash::{Hash, Hasher};
-use libc;
pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
use crate::convert::TryInto;
use crate::fmt;
use crate::sys::cvt;
use crate::time::Duration;
- use libc;
use super::Timespec;
use crate::alloc::{GlobalAlloc, Layout, System};
use crate::ptr;
use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN};
-use libc;
#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
Ok(Stdin)
}
- pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+ #[inline]
+ pub fn as_raw_fd(&self) -> u32 {
+ 0
+ }
+}
+
+impl io::Read for Stdin {
+ fn read(&mut self, data: &mut [u8]) -> io::Result<usize> {
self.read_vectored(&mut [IoSliceMut::new(data)])
}
- pub fn read_vectored(&self, data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ fn read_vectored(&mut self, data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).read(data)
}
#[inline]
- pub fn is_read_vectored(&self) -> bool {
+ fn is_read_vectored(&self) -> bool {
true
}
-
- pub fn as_raw_fd(&self) -> u32 {
- 0
- }
}
impl Stdout {
Ok(Stdout)
}
- pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+ #[inline]
+ pub fn as_raw_fd(&self) -> u32 {
+ 1
+ }
+}
+
+impl io::Write for Stdout {
+ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
self.write_vectored(&[IoSlice::new(data)])
}
- pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
+ fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data)
}
#[inline]
- pub fn is_write_vectored(&self) -> bool {
+ fn is_write_vectored(&self) -> bool {
true
}
-
- pub fn flush(&self) -> io::Result<()> {
+ fn flush(&mut self) -> io::Result<()> {
Ok(())
}
-
- pub fn as_raw_fd(&self) -> u32 {
- 1
- }
}
impl Stderr {
Ok(Stderr)
}
- pub fn write(&self, data: &[u8]) -> io::Result<usize> {
- self.write_vectored(&[IoSlice::new(data)])
- }
-
- pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
- ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data)
- }
-
#[inline]
- pub fn is_write_vectored(&self) -> bool {
- true
- }
-
- pub fn flush(&self) -> io::Result<()> {
- Ok(())
- }
-
pub fn as_raw_fd(&self) -> u32 {
2
}
impl io::Write for Stderr {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
- (&*self).write(data)
+ self.write_vectored(&[IoSlice::new(data)])
+ }
+
+ fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
+ ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data)
+ }
+
+ #[inline]
+ fn is_write_vectored(&self) -> bool {
+ true
}
fn flush(&mut self) -> io::Result<()> {
- (&*self).flush()
+ Ok(())
}
}
pub const PROGRESS_CONTINUE: DWORD = 0;
+// List of Windows system error codes with descriptions:
+// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes
pub const ERROR_FILE_NOT_FOUND: DWORD = 2;
pub const ERROR_PATH_NOT_FOUND: DWORD = 3;
pub const ERROR_ACCESS_DENIED: DWORD = 5;
pub const ERROR_INVALID_PARAMETER: DWORD = 87;
pub const ERROR_BROKEN_PIPE: DWORD = 109;
pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120;
+pub const ERROR_SEM_TIMEOUT: DWORD = 121;
pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122;
pub const ERROR_ALREADY_EXISTS: DWORD = 183;
-pub const ERROR_NO_DATA: DWORD = 232;
pub const ERROR_ENVVAR_NOT_FOUND: DWORD = 203;
+pub const ERROR_NO_DATA: DWORD = 232;
+pub const ERROR_DRIVER_CANCEL_TIMEOUT: DWORD = 594;
pub const ERROR_OPERATION_ABORTED: DWORD = 995;
pub const ERROR_IO_PENDING: DWORD = 997;
-pub const ERROR_TIMEOUT: DWORD = 0x5B4;
+pub const ERROR_SERVICE_REQUEST_TIMEOUT: DWORD = 1053;
+pub const ERROR_COUNTER_TIMEOUT: DWORD = 1121;
+pub const ERROR_TIMEOUT: DWORD = 1460;
+pub const ERROR_RESOURCE_CALL_TIMED_OUT: DWORD = 5910;
+pub const ERROR_CTX_MODEM_RESPONSE_TIMEOUT: DWORD = 7012;
+pub const ERROR_CTX_CLIENT_QUERY_TIMEOUT: DWORD = 7040;
+pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: DWORD = 8014;
+pub const ERROR_DS_TIMELIMIT_EXCEEDED: DWORD = 8226;
+pub const DNS_ERROR_RECORD_TIMED_OUT: DWORD = 9705;
+pub const ERROR_IPSEC_IKE_TIMED_OUT: DWORD = 13805;
+pub const ERROR_RUNLEVEL_SWITCH_TIMEOUT: DWORD = 15402;
+pub const ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT: DWORD = 15403;
pub const E_NOTIMPL: HRESULT = 0x80004001u32 as HRESULT;
c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound,
c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound,
c::ERROR_NO_DATA => return ErrorKind::BrokenPipe,
- c::ERROR_OPERATION_ABORTED => return ErrorKind::TimedOut,
+ c::ERROR_SEM_TIMEOUT
+ | c::WAIT_TIMEOUT
+ | c::ERROR_DRIVER_CANCEL_TIMEOUT
+ | c::ERROR_OPERATION_ABORTED
+ | c::ERROR_SERVICE_REQUEST_TIMEOUT
+ | c::ERROR_COUNTER_TIMEOUT
+ | c::ERROR_TIMEOUT
+ | c::ERROR_RESOURCE_CALL_TIMED_OUT
+ | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT
+ | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT
+ | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT
+ | c::ERROR_DS_TIMELIMIT_EXCEEDED
+ | c::DNS_ERROR_RECORD_TIMED_OUT
+ | c::ERROR_IPSEC_IKE_TIMED_OUT
+ | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT
+ | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return ErrorKind::TimedOut,
_ => {}
}
/// }
/// ```
///
+/// # OS-specific behaviors
+///
+/// An `Instant` is a wrapper around system-specific types and it may behave
+/// differently depending on the underlying operating system. For example,
+/// the following snippet is fine on Linux but panics on macOS:
+///
+/// ```no_run
+/// use std::time::{Instant, Duration};
+///
+/// let now = Instant::now();
+/// let max_nanoseconds = u64::MAX / 1_000_000_000;
+/// let duration = Duration::new(max_nanoseconds, 0);
+/// println!("{:?}", now + duration);
+/// ```
+///
/// # Underlying System calls
/// Currently, the following system calls are being used to get the current time using `now()`:
///
// Right now for CI this test is run in an emulator, and apparently the
// aarch64 emulator's sense of time is that we're still living in the
- // 70s.
+ // 70s. This is also true for riscv (also qemu)
//
// Otherwise let's assume that we're all running computers later than
// 2000.
- if !cfg!(target_arch = "aarch64") {
+ if !cfg!(target_arch = "aarch64") && !cfg!(target_arch = "riscv64") {
assert!(a > thirty_years);
}
{
// Build the unwinding from libunwind C/C++ source code.
llvm_libunwind::compile();
+ } else if target.contains("x86_64-fortanix-unknown-sgx") {
+ llvm_libunwind::compile();
} else if target.contains("linux") {
if target.contains("musl") {
// linking for musl is handled in lib.rs
/// Compile the libunwind C/C++ source code.
pub fn compile() {
+ let target = env::var("TARGET").expect("TARGET was not set");
let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
let target_endian_little = env::var("CARGO_CFG_TARGET_ENDIAN").unwrap() != "big";
cfg.flag("/EHsc");
cfg.define("_CRT_SECURE_NO_WARNINGS", None);
cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
+ } else if target.contains("x86_64-fortanix-unknown-sgx") {
+ cfg.cpp(false);
+
+ cfg.static_flag(true);
+ cfg.opt_level(3);
+
+ cfg.flag("-nostdinc++");
+ cfg.flag("-fno-exceptions");
+ cfg.flag("-fno-rtti");
+ cfg.flag("-fstrict-aliasing");
+ cfg.flag("-funwind-tables");
+ cfg.flag("-fvisibility=hidden");
+ cfg.flag("-fno-stack-protector");
+ cfg.flag("-ffreestanding");
+ cfg.flag("-fexceptions");
+
+ // easiest way to undefine since no API available in cc::Build to undefine
+ cfg.flag("-U_FORTIFY_SOURCE");
+ cfg.define("_FORTIFY_SOURCE", "0");
+
+ cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
+
+ cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
+ cfg.define("RUST_SGX", "1");
+ cfg.define("__NO_STRING_INLINES", None);
+ cfg.define("__NO_MATH_INLINES", None);
+ cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
+ cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
+ cfg.define("NDEBUG", None);
} else {
cfg.flag("-std=c99");
cfg.flag("-std=c++11");
unwind_sources.push("Unwind_AppleExtras.cpp");
}
+ if target.contains("x86_64-fortanix-unknown-sgx") {
+ unwind_sources.push("UnwindRustSgx.c");
+ }
+
let root = Path::new("../llvm-project/libunwind");
cfg.include(root.join("include"));
for src in unwind_sources {
-Subproject commit 0ddefeca92b2e1835c80e9b01d9ecc7efc906b1c
+Subproject commit 6c040dd86ed62d38e585279027486e6efc42fb36
DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
+#if LLVM_VERSION_LT(11, 0)
DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder,
LLVMPassManagerBuilderRef)
+#endif
extern "C" void LLVMInitializePasses() {
PassRegistry &Registry = *PassRegistry::getPassRegistry();
static PassBuilder::OptimizationLevel fromRust(LLVMRustPassBuilderOptLevel Level) {
switch (Level) {
case LLVMRustPassBuilderOptLevel::O0:
- return PassBuilder::O0;
+ return PassBuilder::OptimizationLevel::O0;
case LLVMRustPassBuilderOptLevel::O1:
- return PassBuilder::O1;
+ return PassBuilder::OptimizationLevel::O1;
case LLVMRustPassBuilderOptLevel::O2:
- return PassBuilder::O2;
+ return PassBuilder::OptimizationLevel::O2;
case LLVMRustPassBuilderOptLevel::O3:
- return PassBuilder::O3;
+ return PassBuilder::OptimizationLevel::O3;
case LLVMRustPassBuilderOptLevel::Os:
- return PassBuilder::Os;
+ return PassBuilder::OptimizationLevel::Os;
case LLVMRustPassBuilderOptLevel::Oz:
- return PassBuilder::Oz;
+ return PassBuilder::OptimizationLevel::Oz;
default:
report_fatal_error("Bad PassBuilderOptLevel.");
}
printf("Available features for this target:\n");
for (auto &Feature : FeatTable)
printf(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc);
+ printf("\nRust-specific features:\n");
+ printf(" %-*s - %s.\n",
+ MaxFeatLen,
+ "crt-static",
+ "Enables libraries with C Run-time Libraries(CRT) to be statically linked"
+ );
printf("\n");
printf("Use +feature to enable a feature, or -feature to disable it.\n"
};
struct LLVMRustSanitizerOptions {
+ bool SanitizeAddress;
+ bool SanitizeAddressRecover;
bool SanitizeMemory;
+ bool SanitizeMemoryRecover;
+ int SanitizeMemoryTrackOrigins;
bool SanitizeThread;
- bool SanitizeAddress;
- bool SanitizeRecover;
- int SanitizeMemoryTrackOrigins;
};
extern "C" void
// We manually collect pipeline callbacks so we can apply them at O0, where the
// PassBuilder does not create a pipeline.
std::vector<std::function<void(ModulePassManager &)>> PipelineStartEPCallbacks;
+#if LLVM_VERSION_GE(11, 0)
+ std::vector<std::function<void(ModulePassManager &, PassBuilder::OptimizationLevel)>>
+ OptimizerLastEPCallbacks;
+#else
std::vector<std::function<void(FunctionPassManager &, PassBuilder::OptimizationLevel)>>
OptimizerLastEPCallbacks;
+#endif
if (VerifyIR) {
PipelineStartEPCallbacks.push_back([VerifyIR](ModulePassManager &MPM) {
if (SanitizerOptions->SanitizeMemory) {
MemorySanitizerOptions Options(
SanitizerOptions->SanitizeMemoryTrackOrigins,
- SanitizerOptions->SanitizeRecover,
+ SanitizerOptions->SanitizeMemoryRecover,
/*CompileKernel=*/false);
+#if LLVM_VERSION_GE(11, 0)
+ OptimizerLastEPCallbacks.push_back(
+ [Options](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ MPM.addPass(MemorySanitizerPass(Options));
+ MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options)));
+ }
+ );
+#else
#if LLVM_VERSION_GE(10, 0)
PipelineStartEPCallbacks.push_back([Options](ModulePassManager &MPM) {
MPM.addPass(MemorySanitizerPass(Options));
FPM.addPass(MemorySanitizerPass(Options));
}
);
+#endif
}
if (SanitizerOptions->SanitizeThread) {
+#if LLVM_VERSION_GE(11, 0)
+ OptimizerLastEPCallbacks.push_back(
+ [](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ MPM.addPass(ThreadSanitizerPass());
+ MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
+ }
+ );
+#else
#if LLVM_VERSION_GE(10, 0)
PipelineStartEPCallbacks.push_back([](ModulePassManager &MPM) {
MPM.addPass(ThreadSanitizerPass());
FPM.addPass(ThreadSanitizerPass());
}
);
+#endif
}
if (SanitizerOptions->SanitizeAddress) {
+#if LLVM_VERSION_GE(11, 0)
+ OptimizerLastEPCallbacks.push_back(
+ [SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
+ MPM.addPass(ModuleAddressSanitizerPass(
+ /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
+ MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(
+ /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
+ /*UseAfterScope=*/true)));
+ }
+ );
+#else
PipelineStartEPCallbacks.push_back([&](ModulePassManager &MPM) {
MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
});
OptimizerLastEPCallbacks.push_back(
[SanitizerOptions](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
FPM.addPass(AddressSanitizerPass(
- /*CompileKernel=*/false, SanitizerOptions->SanitizeRecover,
+ /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
/*UseAfterScope=*/true));
}
);
PipelineStartEPCallbacks.push_back(
[SanitizerOptions](ModulePassManager &MPM) {
MPM.addPass(ModuleAddressSanitizerPass(
- /*CompileKernel=*/false, SanitizerOptions->SanitizeRecover));
+ /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
}
);
+#endif
}
}
ModulePassManager MPM(DebugPassManager);
if (!NoPrepopulatePasses) {
- if (OptLevel == PassBuilder::O0) {
+ if (OptLevel == PassBuilder::OptimizationLevel::O0) {
for (const auto &C : PipelineStartEPCallbacks)
C(MPM);
+#if LLVM_VERSION_GE(11, 0)
+ for (const auto &C : OptimizerLastEPCallbacks)
+ C(MPM, OptLevel);
+#else
if (!OptimizerLastEPCallbacks.empty()) {
FunctionPassManager FPM(DebugPassManager);
for (const auto &C : OptimizerLastEPCallbacks)
C(FPM, OptLevel);
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
}
+#endif
MPM.addPass(AlwaysInlinerPass(EmitLifetimeMarkers));
break;
case LLVMRustOptStage::PreLinkThinLTO:
MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
+#if LLVM_VERSION_GE(11, 0)
+ for (const auto &C : OptimizerLastEPCallbacks)
+ C(MPM, OptLevel);
+#else
if (!OptimizerLastEPCallbacks.empty()) {
FunctionPassManager FPM(DebugPassManager);
for (const auto &C : OptimizerLastEPCallbacks)
C(FPM, OptLevel);
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
}
+#endif
break;
case LLVMRustOptStage::PreLinkFatLTO:
MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
const Value *Value;
if (const CallInst *CI = dyn_cast<CallInst>(I)) {
Name = "call";
- Value = CI->getCalledValue();
+ Value = CI->getCalledOperand();
} else if (const InvokeInst* II = dyn_cast<InvokeInst>(I)) {
Name = "invoke";
- Value = II->getCalledValue();
+ Value = II->getCalledOperand();
} else {
// Could demangle more operations, e. g.
// `store %place, @function`.
// `ProcessThinLTOModule` function. Here they're split up into separate steps
// so rustc can save off the intermediate bytecode between each step.
+#if LLVM_VERSION_GE(11, 0)
+static bool
+clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) {
+ // When linking an ELF shared object, dso_local should be dropped. We
+ // conservatively do this for -fpic.
+ bool ClearDSOLocalOnDeclarations =
+ TM.getTargetTriple().isOSBinFormatELF() &&
+ TM.getRelocationModel() != Reloc::Static &&
+ Mod.getPIELevel() == PIELevel::Default;
+ return ClearDSOLocalOnDeclarations;
+}
+#endif
+
extern "C" bool
-LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
+ LLVMTargetMachineRef TM) {
Module &Mod = *unwrap(M);
- if (renameModuleForThinLTO(Mod, Data->Index)) {
+ TargetMachine &Target = *unwrap(TM);
+
+#if LLVM_VERSION_GE(11, 0)
+ bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
+ bool error = renameModuleForThinLTO(Mod, Data->Index, ClearDSOLocal);
+#else
+ bool error = renameModuleForThinLTO(Mod, Data->Index);
+#endif
+
+ if (error) {
LLVMRustSetLastError("renameModuleForThinLTO failed");
return false;
}
}
extern "C" bool
-LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
+ LLVMTargetMachineRef TM) {
Module &Mod = *unwrap(M);
+ TargetMachine &Target = *unwrap(TM);
const auto &ImportList = Data->ImportLists.lookup(Mod.getModuleIdentifier());
auto Loader = [&](StringRef Identifier) {
return MOrErr;
};
+#if LLVM_VERSION_GE(11, 0)
+ bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
+ FunctionImporter Importer(Data->Index, Loader, ClearDSOLocal);
+#else
FunctionImporter Importer(Data->Index, Loader);
+#endif
Expected<bool> Result = Importer.importFunctions(Mod, ImportList);
if (!Result) {
LLVMRustSetLastError(toString(Result.takeError()).c_str());
}
// Use LLVM's built-in `DebugInfoFinder` to find a bunch of debuginfo and
- // process it recursively. Note that we specifically iterate over instructions
- // to ensure we feed everything into it.
+ // process it recursively. Note that we used to specifically iterate over
+ // instructions to ensure we feed everything into it, but `processModule`
+ // started doing this the same way in LLVM 7 (commit d769eb36ab2b8).
DebugInfoFinder Finder;
Finder.processModule(*M);
- for (Function &F : M->functions()) {
- for (auto &FI : F) {
- for (Instruction &BI : FI) {
- if (auto Loc = BI.getDebugLoc())
- Finder.processLocation(*M, Loc);
- if (auto DVI = dyn_cast<DbgValueInst>(&BI))
- Finder.processValue(*M, DVI);
- if (auto DDI = dyn_cast<DbgDeclareInst>(&BI))
- Finder.processDeclare(*M, DDI);
- }
- }
- }
// After we've found all our debuginfo, rewrite all subprograms to point to
// the same `DICompileUnit`.
#include "rustllvm.h"
-#include "llvm/IR/CallSite.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned Index,
LLVMRustAttribute RustAttr) {
- CallSite Call = CallSite(unwrap<Instruction>(Instr));
+ CallBase *Call = unwrap<CallBase>(Instr);
Attribute Attr = Attribute::get(Call->getContext(), fromRust(RustAttr));
- Call.addAttribute(Index, Attr);
+ Call->addAttribute(Index, Attr);
}
extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr,
unsigned Index,
uint32_t Bytes) {
- CallSite Call = CallSite(unwrap<Instruction>(Instr));
+ CallBase *Call = unwrap<CallBase>(Instr);
AttrBuilder B;
B.addAlignmentAttr(Bytes);
- Call.setAttributes(Call.getAttributes().addAttributes(
+ Call->setAttributes(Call->getAttributes().addAttributes(
Call->getContext(), Index, B));
}
extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr,
unsigned Index,
uint64_t Bytes) {
- CallSite Call = CallSite(unwrap<Instruction>(Instr));
+ CallBase *Call = unwrap<CallBase>(Instr);
AttrBuilder B;
B.addDereferenceableAttr(Bytes);
- Call.setAttributes(Call.getAttributes().addAttributes(
+ Call->setAttributes(Call->getAttributes().addAttributes(
Call->getContext(), Index, B));
}
extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr,
unsigned Index,
uint64_t Bytes) {
- CallSite Call = CallSite(unwrap<Instruction>(Instr));
+ CallBase *Call = unwrap<CallBase>(Instr);
AttrBuilder B;
B.addDereferenceableOrNullAttr(Bytes);
- Call.setAttributes(Call.getAttributes().addAttributes(
+ Call->setAttributes(Call->getAttributes().addAttributes(
Call->getContext(), Index, B));
}
extern "C" void LLVMRustAddByValCallSiteAttr(LLVMValueRef Instr, unsigned Index,
LLVMTypeRef Ty) {
- CallSite Call = CallSite(unwrap<Instruction>(Instr));
+ CallBase *Call = unwrap<CallBase>(Instr);
#if LLVM_VERSION_GE(9, 0)
Attribute Attr = Attribute::getWithByValType(Call->getContext(), unwrap(Ty));
#else
Attribute Attr = Attribute::get(Call->getContext(), Attribute::ByVal);
#endif
- Call.addAttribute(Index, Attr);
+ Call->addAttribute(Index, Attr);
}
extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned Index,
extern "C" LLVMValueRef
LLVMRustBuildAtomicLoad(LLVMBuilderRef B, LLVMValueRef Source, const char *Name,
LLVMAtomicOrdering Order) {
- LoadInst *LI = new LoadInst(unwrap(Source));
+ Value *Ptr = unwrap(Source);
+ Type *Ty = Ptr->getType()->getPointerElementType();
+ LoadInst *LI = unwrap(B)->CreateLoad(Ty, Ptr, Name);
LI->setAtomic(fromRust(Order));
- return wrap(unwrap(B)->Insert(LI, Name));
+ return wrap(LI);
}
extern "C" LLVMValueRef LLVMRustBuildAtomicStore(LLVMBuilderRef B,
LLVMValueRef V,
LLVMValueRef Target,
LLVMAtomicOrdering Order) {
- StoreInst *SI = new StoreInst(unwrap(V), unwrap(Target));
+ StoreInst *SI = unwrap(B)->CreateStore(unwrap(V), unwrap(Target));
SI->setAtomic(fromRust(Order));
- return wrap(unwrap(B)->Insert(SI));
+ return wrap(SI);
}
+// FIXME: Use the C-API LLVMBuildAtomicCmpXchg and LLVMSetWeak
+// once we raise our minimum support to LLVM 10.
extern "C" LLVMValueRef
LLVMRustBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Target,
LLVMValueRef Old, LLVMValueRef Source,
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter(
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
const char *Name, size_t NameLen, LLVMMetadataRef Ty) {
+#if LLVM_VERSION_GE(11, 0)
+ bool IsDefault = false; // FIXME: should we ever set this true?
+ return wrap(Builder->createTemplateTypeParameter(
+ unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty), IsDefault));
+#else
return wrap(Builder->createTemplateTypeParameter(
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty)));
+#endif
}
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateNameSpace(
return LLVMArrayTypeKind;
case Type::PointerTyID:
return LLVMPointerTypeKind;
+#if LLVM_VERSION_GE(11, 0)
+ case Type::FixedVectorTyID:
+ return LLVMVectorTypeKind;
+#else
case Type::VectorTyID:
return LLVMVectorTypeKind;
+#endif
case Type::X86_MMXTyID:
return LLVMX86_MMXTypeKind;
case Type::TokenTyID:
return LLVMTokenTypeKind;
+#if LLVM_VERSION_GE(11, 0)
+ case Type::ScalableVectorTyID:
+ return LLVMScalableVectorTypeKind;
+ case Type::BFloatTyID:
+ return LLVMBFloatTypeKind;
+#endif
}
report_fatal_error("Unhandled TypeID.");
}
extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn,
LLVMValueRef *Args, unsigned NumArgs,
OperandBundleDef *Bundle) {
+ Value *Callee = unwrap(Fn);
+ FunctionType *FTy = cast<FunctionType>(Callee->getType()->getPointerElementType());
unsigned Len = Bundle ? 1 : 0;
ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
return wrap(unwrap(B)->CreateCall(
- unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Bundles));
+ FTy, Callee, makeArrayRef(unwrap(Args), NumArgs), Bundles));
+}
+
+extern "C" LLVMValueRef LLVMRustGetInstrprofIncrementIntrinsic(LLVMModuleRef M) {
+ return wrap(llvm::Intrinsic::getDeclaration(unwrap(M),
+ (llvm::Intrinsic::ID)llvm::Intrinsic::instrprof_increment));
}
extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B,
unsigned NumArgs, LLVMBasicBlockRef Then,
LLVMBasicBlockRef Catch, OperandBundleDef *Bundle,
const char *Name) {
+ Value *Callee = unwrap(Fn);
+ FunctionType *FTy = cast<FunctionType>(Callee->getType()->getPointerElementType());
unsigned Len = Bundle ? 1 : 0;
ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
- return wrap(unwrap(B)->CreateInvoke(unwrap(Fn), unwrap(Then), unwrap(Catch),
+ return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch),
makeArrayRef(unwrap(Args), NumArgs),
Bundles, Name));
}
# source tarball for a stable release you'll likely see `1.x.0` for rustc and
# `0.(x+1).0` for Cargo where they were released on `date`.
-date: 2020-06-03
+date: 2020-06-16
rustc: beta
cargo: beta
--- /dev/null
+// no-system-llvm
+// assembly-output: emit-asm
+// compile-flags: --target hexagon-unknown-linux-musl
+
+#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![crate_type = "rlib"]
+#![no_core]
+#![allow(asm_sub_register, non_camel_case_types)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! stringify {
+ () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+type ptr = *const i32;
+
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for f32 {}
+impl Copy for ptr {}
+extern "C" {
+ fn extern_func();
+ static extern_static: u8;
+}
+
+macro_rules! check {
+ ($func:ident $ty:ident $class:ident) => {
+ #[no_mangle]
+ pub unsafe fn $func(x: $ty) -> $ty {
+ // Hack to avoid function merging
+ extern "Rust" {
+ fn dont_merge(s: &str);
+ }
+ dont_merge(stringify!($func));
+
+ let y;
+ asm!("{} = {}", out($class) y, in($class) x);
+ y
+ }
+ };
+}
+
+// CHECK-LABEL: sym_static:
+// CHECK: InlineAsm Start
+// CHECK: r0 = #extern_static
+// CHECK: InlineAsm End
+#[no_mangle]
+pub unsafe fn sym_static() {
+ // Hack to avoid function merging
+ extern "Rust" {
+ fn dont_merge(s: &str);
+ }
+ dont_merge(stringify!($func));
+
+ asm!("r0 = #{}", sym extern_static);
+}
+
+// CHECK-LABEL: sym_fn:
+// CHECK: InlineAsm Start
+// CHECK: r0 = #extern_func
+// CHECK: InlineAsm End
+#[no_mangle]
+pub unsafe fn sym_fn() {
+ // Hack to avoid function merging
+ extern "Rust" {
+ fn dont_merge(s: &str);
+ }
+ dont_merge(stringify!($func));
+
+ asm!("r0 = #{}", sym extern_func);
+}
+
+// This is a test for multi-instruction packets,
+// which require the escaped braces.
+//
+// CHECK-LABEL: packet:
+// CHECK: InlineAsm Start
+// CHECK: {
+// CHECK: r{{[0-9]+}} = r0
+// CHECK: memw(r1) = r{{[0-9]+}}
+// CHECK: }
+// CHECK: InlineAsm End
+#[no_mangle]
+pub unsafe fn packet() {
+ let val = 1024;
+ asm!("{{
+ {} = r0
+ memw(r1) = {}
+ }}", out(reg) _, in(reg) &val);
+}
+
+// CHECK-LABEL: ptr:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_ptr ptr reg);
+
+// CHECK-LABEL: reg_f32:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_f32 f32 reg);
+
+// CHECK-LABEL: reg_i32:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_i32 i32 reg);
+
+// CHECK-LABEL: reg_i8:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_i8 i8 reg);
+
+// CHECK-LABEL: reg_i16:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_i16 i16 reg);
+++ /dev/null
-// Verifies that during compiler_builtins compilation the codegen units are kept
-// unmerged. Even when only a single codegen unit is requested with -Ccodegen-units=1.
-//
-// compile-flags: -Zprint-mono-items=eager -Ccodegen-units=1
-
-#![compiler_builtins]
-#![crate_type="lib"]
-#![feature(compiler_builtins)]
-
-mod atomics {
- //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_1[0] @@ compiler_builtins-cgu.0[External]
- #[no_mangle]
- pub extern "C" fn sync_1() {}
-
- //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_2[0] @@ compiler_builtins-cgu.0[External]
- #[no_mangle]
- pub extern "C" fn sync_2() {}
-
- //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_3[0] @@ compiler_builtins-cgu.0[External]
- #[no_mangle]
- pub extern "C" fn sync_3() {}
-}
-
-mod x {
- //~ MONO_ITEM fn compiler_builtins::x[0]::x[0] @@ compiler_builtins-cgu.1[External]
- #[no_mangle]
- pub extern "C" fn x() {}
-}
-
-mod y {
- //~ MONO_ITEM fn compiler_builtins::y[0]::y[0] @@ compiler_builtins-cgu.2[External]
- #[no_mangle]
- pub extern "C" fn y() {}
-}
-
-mod z {
- //~ MONO_ITEM fn compiler_builtins::z[0]::z[0] @@ compiler_builtins-cgu.3[External]
- #[no_mangle]
- pub extern "C" fn z() {}
-}
--- /dev/null
+// compile-flags: -O
+// only-x86_64
+
+#![crate_type = "rlib"]
+#![feature(asm)]
+
+// CHECK-LABEL: @pure
+// CHECK-NOT: asm
+// CHECK: ret void
+#[no_mangle]
+pub unsafe fn pure(x: i32) {
+ let y: i32;
+ asm!("", out("ax") y, in("bx") x, options(pure), options(nomem));
+}
+
+pub static mut VAR: i32 = 0;
+pub static mut DUMMY_OUTPUT: i32 = 0;
+
+// CHECK-LABEL: @readonly
+// CHECK: call i32 asm
+// CHECK: ret i32 1
+#[no_mangle]
+pub unsafe fn readonly() -> i32 {
+ VAR = 1;
+ asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly));
+ VAR
+}
+
+// CHECK-LABEL: @nomem
+// CHECK-NOT: store
+// CHECK: call i32 asm
+// CHECK: store
+// CHECK: ret i32 2
+#[no_mangle]
+pub unsafe fn nomem() -> i32 {
+ VAR = 1;
+ asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(nomem));
+ VAR = 2;
+ VAR
+}
+
+// CHECK-LABEL: @not_nomem
+// CHECK: store
+// CHECK: call i32 asm
+// CHECK: store
+// CHECK: ret i32 2
+#[no_mangle]
+pub unsafe fn not_nomem() -> i32 {
+ VAR = 1;
+ asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly));
+ VAR = 2;
+ VAR
+}
--- /dev/null
+// Verify debuginfo for generators:
+// - Each variant points to the file and line of its yield point
+// - The generator types and variants are marked artificial
+// - Captured vars from the source are not marked artificial
+//
+// ignore-tidy-linelength
+// compile-flags: -C debuginfo=2 --edition=2018
+// only-msvc
+
+async fn foo() {}
+async fn async_fn_test() {
+ foo().await;
+ let s = String::from("foo");
+ foo().await;
+}
+
+// FIXME: No way to reliably check the filename.
+
+// CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
+// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// For brevity, we only check the struct name and members of the last variant.
+// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 12,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 14,
+// CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[ASYNC_FN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+
+fn main() {
+ let _dummy = async_fn_test();
+}
--- /dev/null
+// Verify debuginfo for async fn:
+// - Each variant points to the file and line of its yield point
+// - The generator types and variants are marked artificial
+// - Captured vars from the source are not marked artificial
+//
+// ignore-tidy-linelength
+// compile-flags: -C debuginfo=2 --edition=2018
+// ignore-msvc
+
+async fn foo() {}
+async fn async_fn_test() {
+ foo().await;
+ let s = String::from("foo");
+ foo().await;
+}
+
+// FIXME: No way to reliably check the filename.
+
+// CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
+// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[ASYNC_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[ASYNC_FN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-SAME: discriminator: [[DISC:![0-9]*]]
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 12,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 14,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: [[DISC]] = !DIDerivedType(tag: DW_TAG_member, name: "__state", scope: [[ASYNC_FN]],
+// CHECK-SAME: flags: DIFlagArtificial
+
+fn main() {
+ let _dummy = async_fn_test();
+}
--- /dev/null
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "cdylib"]
+
+// CHECK: define void @a()
+#[no_mangle]
+#[inline]
+pub extern "C" fn a() {}
+
+// CHECK: define void @b()
+#[export_name = "b"]
+#[inline]
+pub extern "C" fn b() {}
+
+// CHECK: define void @c()
+#[no_mangle]
+#[inline]
+extern "C" fn c() {}
+
+// CHECK: define void @d()
+#[export_name = "d"]
+#[inline]
+extern "C" fn d() {}
+
+// CHECK: define void @e()
+#[no_mangle]
+#[inline(always)]
+pub extern "C" fn e() {}
+
+// CHECK: define void @f()
+#[export_name = "f"]
+#[inline(always)]
+pub extern "C" fn f() {}
+
+// CHECK: define void @g()
+#[no_mangle]
+#[inline(always)]
+extern "C" fn g() {}
+
+// CHECK: define void @h()
+#[export_name = "h"]
+#[inline(always)]
+extern "C" fn h() {}
-// compile-flags: -Z control_flow_guard=checks
+// compile-flags: -Z control-flow-guard=checks
#![crate_type = "lib"]
-// compile-flags: -Z control_flow_guard=disabled
+// compile-flags: -Z control-flow-guard=no
#![crate_type = "lib"]
-// compile-flags: -Z control_flow_guard=nochecks
+// compile-flags: -Z control-flow-guard=nochecks
#![crate_type = "lib"]
--- /dev/null
+// Verifies that linkage name is omitted when it is
+// the same as variable / function name.
+//
+// compile-flags: -C no-prepopulate-passes
+// compile-flags: -C debuginfo=2
+#![crate_type = "lib"]
+
+pub mod xyz {
+ // CHECK: !DIGlobalVariable(name: "A",
+ // CHECK: linkageName:
+ // CHECK-SAME: line: 12,
+ pub static A: u32 = 1;
+
+ // CHECK: !DIGlobalVariable(name: "B",
+ // CHECK-NOT: linkageName:
+ // CHECK-SAME: line: 18,
+ #[no_mangle]
+ pub static B: u32 = 2;
+
+ // CHECK: !DIGlobalVariable(name: "C",
+ // CHECK-NOT: linkageName:
+ // CHECK-SAME: line: 24,
+ #[export_name = "C"]
+ pub static C: u32 = 2;
+
+ // CHECK: !DISubprogram(name: "e",
+ // CHECK: linkageName:
+ // CHECK-SAME: line: 29,
+ pub extern fn e() {}
+
+ // CHECK: !DISubprogram(name: "f",
+ // CHECK-NOT: linkageName:
+ // CHECK-SAME: line: 35,
+ #[no_mangle]
+ pub extern fn f() {}
+
+ // CHECK: !DISubprogram(name: "g",
+ // CHECK-NOT: linkageName:
+ // CHECK-SAME: line: 41,
+ #[export_name = "g"]
+ pub extern fn g() {}
+}
#[export_name = "BAR"]
static BAR: u32 = 3;
- // CHECK: void @foo()
+ // CHECK: void @a()
#[no_mangle]
- pub extern fn foo() {}
+ pub extern fn a() {}
- // CHECK: void @bar()
- #[export_name = "bar"]
- extern fn bar() {}
+ // CHECK: void @b()
+ #[export_name = "b"]
+ extern fn b() {}
+
+ // CHECK: void @c()
+ #[export_name = "c"]
+ #[inline]
+ extern fn c() {}
+
+ // CHECK: void @d()
+ #[export_name = "d"]
+ #[inline(always)]
+ extern fn d() {}
}
core::ptr::read_volatile(&42);
}
}
+
+// CHECK: define void @i()
+#[no_mangle]
+#[inline]
+fn i() {}
+
+// CHECK: define void @j()
+#[no_mangle]
+#[inline]
+pub fn j() {}
+
+// CHECK: define void @k()
+#[no_mangle]
+#[inline(always)]
+fn k() {}
+
+// CHECK: define void @l()
+#[no_mangle]
+#[inline(always)]
+pub fn l() {}
--- /dev/null
+// Verify debuginfo for generators:
+// - Each variant points to the file and line of its yield point
+// - The generator types and variants are marked artificial
+// - Captured vars from the source are not marked artificial
+//
+// ignore-tidy-linelength
+// compile-flags: -C debuginfo=2
+// only-msvc
+
+#![feature(generators, generator_trait)]
+use std::ops::Generator;
+
+fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
+ || {
+ yield 0;
+ let s = String::from("foo");
+ yield 1;
+ }
+}
+
+// FIXME: No way to reliably check the filename.
+
+// CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "generator_test"
+// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// For brevity, we only check the struct name and members of the last variant.
+// CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 17,
+// CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN_FN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+
+fn main() {
+ let _dummy = generator_test();
+}
--- /dev/null
+// Verify debuginfo for generators:
+// - Each variant points to the file and line of its yield point
+// - The generator types and variants are marked artificial
+// - Captured vars from the source are not marked artificial
+//
+// ignore-tidy-linelength
+// compile-flags: -C debuginfo=2 --edition=2018
+// ignore-msvc
+
+#![feature(generators, generator_trait)]
+use std::ops::Generator;
+
+fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
+ || {
+ yield 0;
+ let s = String::from("foo");
+ yield 1;
+ }
+}
+
+// FIXME: No way to reliably check the filename.
+
+// CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "generator_test"
+// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[GEN_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN_FN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-SAME: discriminator: [[DISC:![0-9]*]]
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 17,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: [[DISC]] = !DIDerivedType(tag: DW_TAG_member, name: "__state", scope: [[GEN_FN]],
+// CHECK-SAME: flags: DIFlagArtificial
+
+fn main() {
+ let _dummy = generator_test();
+}
--- /dev/null
+// no-system-llvm
+// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
+#![crate_type = "lib"]
+
+// Make sure no bounds checks are emitted in the loop when upfront slicing
+// ensures that the slices are big enough.
+// In particular, bounds checks were not always optimized out if the upfront
+// check was for a greater len than the loop requires.
+// (i.e. `already_sliced_no_bounds_check` was not always optimized even when
+// `already_sliced_no_bounds_check_exact` was)
+// CHECK-LABEL: @already_sliced_no_bounds_check
+#[no_mangle]
+pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
+ // CHECK: slice_index_len_fail
+ // CHECK-NOT: panic_bounds_check
+ let _ = (&a[..2048], &b[..2048], &mut c[..2048]);
+ for i in 0..1024 {
+ c[i] = a[i] ^ b[i];
+ }
+}
+
+// CHECK-LABEL: @already_sliced_no_bounds_check_exact
+#[no_mangle]
+pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) {
+ // CHECK: slice_index_len_fail
+ // CHECK-NOT: panic_bounds_check
+ let _ = (&a[..1024], &b[..1024], &mut c[..1024]);
+ for i in 0..1024 {
+ c[i] = a[i] ^ b[i];
+ }
+}
+
+// Make sure we're checking for the right thing: there can be a panic if the slice is too small.
+// CHECK-LABEL: @already_sliced_bounds_check
+#[no_mangle]
+pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
+ // CHECK: slice_index_len_fail
+ // CHECK: panic_bounds_check
+ let _ = (&a[..1023], &b[..2048], &mut c[..2048]);
+ for i in 0..1024 {
+ c[i] = a[i] ^ b[i];
+ }
+}
// Verifies that MemorySanitizer track-origins level can be controlled
// with -Zsanitizer-memory-track-origins option.
//
-// needs-sanitizer-support
-// only-linux
-// only-x86_64
+// needs-sanitizer-memory
// revisions:MSAN-0 MSAN-1 MSAN-2 MSAN-1-LTO MSAN-2-LTO
//
//[MSAN-0] compile-flags: -Zsanitizer=memory
// Verifies that no_sanitize attribute prevents inlining when
// given sanitizer is enabled, but has no effect on inlining otherwise.
//
-// needs-sanitizer-support
-// only-x86_64
-//
+// needs-sanitizer-address
+// needs-sanitizer-leak
// revisions: ASAN LSAN
-//
//[ASAN] compile-flags: -Zsanitizer=address -C opt-level=3 -Z mir-opt-level=3
//[LSAN] compile-flags: -Zsanitizer=leak -C opt-level=3 -Z mir-opt-level=3
#![feature(no_sanitize)]
// ASAN-LABEL: define void @test
-// ASAN: tail call fastcc void @random_inline
+// ASAN: call {{.*}} @random_inline
// ASAN: }
//
// LSAN-LABEL: define void @test
// Verifies that no_sanitze attribute can be used to
// selectively disable sanitizer instrumentation.
//
-// needs-sanitizer-support
+// needs-sanitizer-address
// compile-flags: -Zsanitizer=address
#![crate_type="lib"]
// Verifies that AddressSanitizer and MemorySanitizer
// recovery mode can be enabled with -Zsanitizer-recover.
//
-// needs-sanitizer-support
-// only-linux
-// only-x86_64
+// needs-sanitizer-address
+// needs-sanitizer-memory
// revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER MSAN-RECOVER-LTO
// no-prefer-dynamic
//
// ASAN: }
//
// MSAN-LABEL: define i32 @penguin(
-// MSAN: call void @__msan_warning_noreturn()
+// MSAN: call void @__msan_warning{{(_with_origin_noreturn\(i32 0\)|_noreturn\(\))}}
// MSAN: unreachable
// MSAN: }
//
// MSAN-RECOVER-LABEL: define i32 @penguin(
-// MSAN-RECOVER: call void @__msan_warning()
+// MSAN-RECOVER: call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}}
// MSAN-RECOVER-NOT: unreachable
// MSAN-RECOVER: }
//
// MSAN-RECOVER-LTO-LABEL: define i32 @penguin(
-// MSAN-RECOVER-LTO: call void @__msan_warning()
+// MSAN-RECOVER-LTO: call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}}
// MSAN-RECOVER-LTO-NOT: unreachable
// MSAN-RECOVER-LTO: }
//
--- /dev/null
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "staticlib"]
+
+// CHECK: define void @a()
+#[no_mangle]
+#[inline]
+pub extern "C" fn a() {}
+
+// CHECK: define void @b()
+#[export_name = "b"]
+#[inline]
+pub extern "C" fn b() {}
+
+// CHECK: define void @c()
+#[no_mangle]
+#[inline]
+extern "C" fn c() {}
+
+// CHECK: define void @d()
+#[export_name = "d"]
+#[inline]
+extern "C" fn d() {}
+
+// CHECK: define void @e()
+#[no_mangle]
+#[inline(always)]
+pub extern "C" fn e() {}
+
+// CHECK: define void @f()
+#[export_name = "f"]
+#[inline(always)]
+pub extern "C" fn f() {}
+
+// CHECK: define void @g()
+#[no_mangle]
+#[inline(always)]
+extern "C" fn g() {}
+
+// CHECK: define void @h()
+#[export_name = "h"]
+#[inline(always)]
+extern "C" fn h() {}
-// ignore-debug: the debug assertions get in the way
// compile-flags: -O
#![crate_type = "lib"]
-//
// ignore-debug: the debug assertions get in the way
// no-system-llvm
// compile-flags: -O
fn main() {
[(); & { loop { continue } } ]; //~ ERROR mismatched types
- //~^ ERROR `loop` is not allowed in a `const`
+
[(); loop { break }]; //~ ERROR mismatched types
- //~^ ERROR `loop` is not allowed in a `const`
+
[(); {while true {break}; 0}];
- //~^ ERROR `while` is not allowed in a `const`
- //~| WARN denote infinite loops with
+ //~^ WARN denote infinite loops with
+
[(); { for _ in 0usize.. {}; 0}];
//~^ ERROR `for` is not allowed in a `const`
//~| ERROR calls in constants are limited to constant functions
- //~| ERROR references in constants may only refer to immutable values
+ //~| ERROR mutable references are not allowed in constants
//~| ERROR calls in constants are limited to constant functions
//~| ERROR evaluation of constant value failed
}
// compile-fail
-
#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
pub trait Foo {
fn foo();
| 8: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:16:12: 16:24
| 9: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:16:12: 16:24
| 10: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:18:5: 18:18
-| 11: Canonical { max_universe: U3, variables: [CanonicalVarInfo { kind: Region(U3) }], value: Ty(*const dyn std::marker::Send) } at $DIR/address-of.rs:20:5: 20:25
+| 11: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) } at $DIR/address-of.rs:20:5: 20:25
| 12: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:23:12: 23:20
| 13: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:23:12: 23:20
| 14: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) } at $DIR/address-of.rs:24:12: 24:28
| 18: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:26:12: 26:24
| 19: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:26:12: 26:24
| 20: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:28:5: 28:16
-| 21: Canonical { max_universe: U6, variables: [CanonicalVarInfo { kind: Region(U6) }], value: Ty(*mut dyn std::marker::Send) } at $DIR/address-of.rs:30:5: 30:23
+| 21: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) } at $DIR/address-of.rs:30:5: 30:23
| 22: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:33:12: 33:18
| 23: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:33:12: 33:18
| 24: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32; 10]) } at $DIR/address-of.rs:34:12: 34:26
bb0: {
StorageLive(_1); // scope 0 at $DIR/address-of.rs:4:9: 4:10
StorageLive(_2); // scope 0 at $DIR/address-of.rs:4:14: 4:21
- _2 = [const 0i32; 10]; // scope 0 at $DIR/address-of.rs:4:14: 4:21
+ _2 = [const 0_i32; 10]; // scope 0 at $DIR/address-of.rs:4:14: 4:21
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
FakeRead(ForLet, _1); // scope 0 at $DIR/address-of.rs:4:9: 4:10
StorageLive(_3); // scope 1 at $DIR/address-of.rs:5:9: 5:14
StorageLive(_4); // scope 1 at $DIR/address-of.rs:5:22: 5:29
- _4 = [const 0i32; 10]; // scope 1 at $DIR/address-of.rs:5:22: 5:29
+ _4 = [const 0_i32; 10]; // scope 1 at $DIR/address-of.rs:5:22: 5:29
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
bb0: {
StorageLive(_1); // scope 0 at $DIR/array-index-is-temporary.rs:13:9: 13:14
- _1 = [const 42u32, const 43u32, const 44u32]; // scope 0 at $DIR/array-index-is-temporary.rs:13:17: 13:29
+ _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:13:17: 13:29
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x0000002a))
// + span: $DIR/array-index-is-temporary.rs:13:26: 13:28
// + literal: Const { ty: u32, val: Value(Scalar(0x0000002c)) }
StorageLive(_2); // scope 1 at $DIR/array-index-is-temporary.rs:14:9: 14:14
- _2 = const 1usize; // scope 1 at $DIR/array-index-is-temporary.rs:14:17: 14:18
+ _2 = const 1_usize; // scope 1 at $DIR/array-index-is-temporary.rs:14:17: 14:18
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000001))
bb0: {
StorageLive(_1); // scope 0 at $DIR/array-index-is-temporary.rs:13:9: 13:14
- _1 = [const 42u32, const 43u32, const 44u32]; // scope 0 at $DIR/array-index-is-temporary.rs:13:17: 13:29
+ _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:13:17: 13:29
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x0000002a))
// + span: $DIR/array-index-is-temporary.rs:13:26: 13:28
// + literal: Const { ty: u32, val: Value(Scalar(0x0000002c)) }
StorageLive(_2); // scope 1 at $DIR/array-index-is-temporary.rs:14:9: 14:14
- _2 = const 1usize; // scope 1 at $DIR/array-index-is-temporary.rs:14:17: 14:18
+ _2 = const 1_usize; // scope 1 at $DIR/array-index-is-temporary.rs:14:17: 14:18
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000001))
// + span: $DIR/byte_slice.rs:5:13: 5:19
// + literal: Const { ty: &[u8; 3], val: Value(Scalar(alloc0)) }
StorageLive(_2); // scope 1 at $DIR/byte_slice.rs:6:9: 6:10
- _2 = [const 5u8, const 120u8]; // scope 1 at $DIR/byte_slice.rs:6:13: 6:24
+ _2 = [const 5_u8, const 120_u8]; // scope 1 at $DIR/byte_slice.rs:6:13: 6:24
// ty::Const
// + ty: u8
// + val: Value(Scalar(0x05))
bb0: {
StorageLive(_2); // scope 0 at $DIR/combine_array_len.rs:5:9: 5:10
StorageLive(_3); // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16
- _3 = const 0usize; // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16
+ _3 = const 0_usize; // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000000))
// + span: $DIR/combine_array_len.rs:5:15: 5:16
// + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) }
- _4 = Len(_1); // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
-+ _4 = const 2usize; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
++ _4 = const 2_usize; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x00000002))
StorageDead(_3); // scope 0 at $DIR/combine_array_len.rs:5:17: 5:18
StorageLive(_6); // scope 1 at $DIR/combine_array_len.rs:6:9: 6:10
StorageLive(_7); // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16
- _7 = const 1usize; // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16
+ _7 = const 1_usize; // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000001))
// + span: $DIR/combine_array_len.rs:6:15: 6:16
// + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) }
- _8 = Len(_1); // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
-+ _8 = const 2usize; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
++ _8 = const 2_usize; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x00000002))
bb0: {
StorageLive(_2); // scope 0 at $DIR/combine_array_len.rs:5:9: 5:10
StorageLive(_3); // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16
- _3 = const 0usize; // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16
+ _3 = const 0_usize; // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000000))
// + span: $DIR/combine_array_len.rs:5:15: 5:16
// + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) }
- _4 = Len(_1); // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
-+ _4 = const 2usize; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
++ _4 = const 2_usize; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x0000000000000002))
StorageDead(_3); // scope 0 at $DIR/combine_array_len.rs:5:17: 5:18
StorageLive(_6); // scope 1 at $DIR/combine_array_len.rs:6:9: 6:10
StorageLive(_7); // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16
- _7 = const 1usize; // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16
+ _7 = const 1_usize; // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000001))
// + span: $DIR/combine_array_len.rs:6:15: 6:16
// + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) }
- _8 = Len(_1); // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
-+ _8 = const 2usize; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
++ _8 = const 2_usize; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x0000000000000002))
StorageLive(_1); // scope 0 at $DIR/aggregate.rs:5:9: 5:10
StorageLive(_2); // scope 0 at $DIR/aggregate.rs:5:13: 5:24
StorageLive(_3); // scope 0 at $DIR/aggregate.rs:5:13: 5:22
- _3 = (const 0i32, const 1i32, const 2i32); // scope 0 at $DIR/aggregate.rs:5:13: 5:22
+ _3 = (const 0_i32, const 1_i32, const 2_i32); // scope 0 at $DIR/aggregate.rs:5:13: 5:22
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/aggregate.rs:5:20: 5:21
// + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
- _2 = (_3.1: i32); // scope 0 at $DIR/aggregate.rs:5:13: 5:24
-- _1 = Add(move _2, const 0i32); // scope 0 at $DIR/aggregate.rs:5:13: 5:28
-+ _2 = const 1i32; // scope 0 at $DIR/aggregate.rs:5:13: 5:24
+- _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/aggregate.rs:5:13: 5:28
++ _2 = const 1_i32; // scope 0 at $DIR/aggregate.rs:5:13: 5:24
// ty::Const
// + ty: i32
- // + val: Value(Scalar(0x00000000))
- // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
+ // + span: $DIR/aggregate.rs:5:13: 5:24
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
-+ _1 = const 1i32; // scope 0 at $DIR/aggregate.rs:5:13: 5:28
++ _1 = const 1_i32; // scope 0 at $DIR/aggregate.rs:5:13: 5:28
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000001))
bb0: {
StorageLive(_1); // scope 0 at $DIR/array_index.rs:5:9: 5:10
StorageLive(_2); // scope 0 at $DIR/array_index.rs:5:18: 5:30
- _2 = [const 0u32, const 1u32, const 2u32, const 3u32]; // scope 0 at $DIR/array_index.rs:5:18: 5:30
+ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // scope 0 at $DIR/array_index.rs:5:18: 5:30
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/array_index.rs:5:28: 5:29
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_3); // scope 0 at $DIR/array_index.rs:5:31: 5:32
- _3 = const 2usize; // scope 0 at $DIR/array_index.rs:5:31: 5:32
+ _3 = const 2_usize; // scope 0 at $DIR/array_index.rs:5:31: 5:32
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000002))
// mir::Constant
// + span: $DIR/array_index.rs:5:31: 5:32
// + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) }
- _4 = const 4usize; // scope 0 at $DIR/array_index.rs:5:18: 5:33
+ _4 = const 4_usize; // scope 0 at $DIR/array_index.rs:5:18: 5:33
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000004))
bb1: {
- _1 = _2[_3]; // scope 0 at $DIR/array_index.rs:5:18: 5:33
-+ _1 = const 2u32; // scope 0 at $DIR/array_index.rs:5:18: 5:33
++ _1 = const 2_u32; // scope 0 at $DIR/array_index.rs:5:18: 5:33
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000002))
bb0: {
StorageLive(_1); // scope 0 at $DIR/array_index.rs:5:9: 5:10
StorageLive(_2); // scope 0 at $DIR/array_index.rs:5:18: 5:30
- _2 = [const 0u32, const 1u32, const 2u32, const 3u32]; // scope 0 at $DIR/array_index.rs:5:18: 5:30
+ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // scope 0 at $DIR/array_index.rs:5:18: 5:30
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/array_index.rs:5:28: 5:29
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_3); // scope 0 at $DIR/array_index.rs:5:31: 5:32
- _3 = const 2usize; // scope 0 at $DIR/array_index.rs:5:31: 5:32
+ _3 = const 2_usize; // scope 0 at $DIR/array_index.rs:5:31: 5:32
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000002))
// mir::Constant
// + span: $DIR/array_index.rs:5:31: 5:32
// + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) }
- _4 = const 4usize; // scope 0 at $DIR/array_index.rs:5:18: 5:33
+ _4 = const 4_usize; // scope 0 at $DIR/array_index.rs:5:18: 5:33
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000004))
bb1: {
- _1 = _2[_3]; // scope 0 at $DIR/array_index.rs:5:18: 5:33
-+ _1 = const 2u32; // scope 0 at $DIR/array_index.rs:5:18: 5:33
++ _1 = const 2_u32; // scope 0 at $DIR/array_index.rs:5:18: 5:33
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000002))
bb0: {
StorageLive(_1); // scope 0 at $DIR/bad_op_div_by_zero.rs:4:9: 4:10
- _1 = const 0i32; // scope 0 at $DIR/bad_op_div_by_zero.rs:4:13: 4:14
+ _1 = const 0_i32; // scope 0 at $DIR/bad_op_div_by_zero.rs:4:13: 4:14
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
StorageLive(_2); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:9: 5:11
StorageLive(_3); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
- _3 = _1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
-- _4 = Eq(_3, const 0i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
-+ _3 = const 0i32; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
+- _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++ _3 = const 0_i32; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
+ // mir::Constant
+ // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
- assert(!move _4, "attempt to divide by zero") -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ assert(!move _4, "attempt to divide {} by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
+ // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:15
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
}
bb1: {
-- _5 = Eq(_3, const -1i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+- _5 = Eq(_3, const -1_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ _5 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
// ty::Const
- // + ty: i32
// mir::Constant
// + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
- // + literal: Const { ty: i32, val: Value(Scalar(0xffffffff)) }
-- _6 = Eq(const 1i32, const i32::MIN); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+- _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+ _6 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
// ty::Const
// + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
- // + literal: Const { ty: i32, val: Value(Scalar(0x80000000)) }
- _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
-- assert(!move _7, "attempt to divide with overflow") -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+- assert(!move _7, "attempt to compute `{} / {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+ assert(!const false, "attempt to divide with overflow") -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++ assert(!const false, "attempt to compute `{} / {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x00))
+ // mir::Constant
+ // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
+ // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:15
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
}
bb2: {
- _2 = Div(const 1i32, move _3); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ _2 = Div(const 1_i32, move _3); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
bb0: {
StorageLive(_1); // scope 0 at $DIR/bad_op_mod_by_zero.rs:4:9: 4:10
- _1 = const 0i32; // scope 0 at $DIR/bad_op_mod_by_zero.rs:4:13: 4:14
+ _1 = const 0_i32; // scope 0 at $DIR/bad_op_mod_by_zero.rs:4:13: 4:14
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
StorageLive(_2); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:9: 5:11
StorageLive(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
- _3 = _1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
-- _4 = Eq(_3, const 0i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
-+ _3 = const 0i32; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
+- _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++ _3 = const 0_i32; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
+ // mir::Constant
+ // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
- assert(!move _4, "attempt to calculate the remainder with a divisor of zero") -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ assert(!move _4, "attempt to calculate the remainder of {} with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
+ // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:15
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
}
bb1: {
-- _5 = Eq(_3, const -1i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+- _5 = Eq(_3, const -1_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ _5 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
// ty::Const
- // + ty: i32
// mir::Constant
// + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
- // + literal: Const { ty: i32, val: Value(Scalar(0xffffffff)) }
-- _6 = Eq(const 1i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+- _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+ _6 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
// ty::Const
// + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
- // + literal: Const { ty: i32, val: Value(Scalar(0x80000000)) }
- _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
-- assert(!move _7, "attempt to calculate the remainder with overflow") -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+- assert(!move _7, "attempt to compute the remainder of `{} % {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+ assert(!const false, "attempt to calculate the remainder with overflow") -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++ assert(!const false, "attempt to compute the remainder of `{} % {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x00))
+ // mir::Constant
+ // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
+ // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:15
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
}
bb2: {
- _2 = Rem(const 1i32, move _3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ _2 = Rem(const 1_i32, move _3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
StorageDead(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:35: 5:36
StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15
StorageLive(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
- _6 = const 3usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
+ _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000003))
// mir::Constant
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
// + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
-- _7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-- _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+ _7 = const 3usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+ // ty::Const
-+ // + ty: usize
-+ // + val: Value(Scalar(0x00000003))
-+ // mir::Constant
-+ // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+ // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
-+ _8 = const false; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+ // ty::Const
-+ // + ty: bool
-+ // + val: Value(Scalar(0x00))
-+ // mir::Constant
-+ // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+ _7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+ _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
}
StorageDead(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:35: 5:36
StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15
StorageLive(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
- _6 = const 3usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
+ _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000003))
// mir::Constant
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
// + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
-- _7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-- _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+ _7 = const 3usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+ // ty::Const
-+ // + ty: usize
-+ // + val: Value(Scalar(0x0000000000000003))
-+ // mir::Constant
-+ // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
-+ _8 = const false; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+ // ty::Const
-+ // + ty: bool
-+ // + val: Value(Scalar(0x00))
-+ // mir::Constant
-+ // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+ _7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+ _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
}
StorageLive(_3); // scope 0 at $DIR/boxes.rs:12:14: 12:22
StorageLive(_4); // scope 0 at $DIR/boxes.rs:12:14: 12:22
_4 = Box(i32); // scope 0 at $DIR/boxes.rs:12:14: 12:22
- (*_4) = const 42i32; // scope 0 at $DIR/boxes.rs:12:19: 12:21
+ (*_4) = const 42_i32; // scope 0 at $DIR/boxes.rs:12:19: 12:21
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002a))
_3 = move _4; // scope 0 at $DIR/boxes.rs:12:14: 12:22
StorageDead(_4); // scope 0 at $DIR/boxes.rs:12:21: 12:22
_2 = (*_3); // scope 0 at $DIR/boxes.rs:12:13: 12:22
- _1 = Add(move _2, const 0i32); // scope 0 at $DIR/boxes.rs:12:13: 12:26
+ _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/boxes.rs:12:13: 12:26
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
bb0: {
StorageLive(_1); // scope 0 at $DIR/cast.rs:4:9: 4:10
-- _1 = const 42u8 as u32 (Misc); // scope 0 at $DIR/cast.rs:4:13: 4:24
-+ _1 = const 42u32; // scope 0 at $DIR/cast.rs:4:13: 4:24
+- _1 = const 42_u8 as u32 (Misc); // scope 0 at $DIR/cast.rs:4:13: 4:24
++ _1 = const 42_u32; // scope 0 at $DIR/cast.rs:4:13: 4:24
// ty::Const
- // + ty: u8
- // + val: Value(Scalar(0x2a))
- // + span: $DIR/cast.rs:4:13: 4:17
- // + literal: Const { ty: u8, val: Value(Scalar(0x2a)) }
- StorageLive(_2); // scope 1 at $DIR/cast.rs:6:9: 6:10
-- _2 = const 42u32 as u8 (Misc); // scope 1 at $DIR/cast.rs:6:13: 6:24
+- _2 = const 42_u32 as u8 (Misc); // scope 1 at $DIR/cast.rs:6:13: 6:24
- // ty::Const
// + ty: u32
// + val: Value(Scalar(0x0000002a))
+ // + span: $DIR/cast.rs:4:13: 4:24
// + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
+ StorageLive(_2); // scope 1 at $DIR/cast.rs:6:9: 6:10
-+ _2 = const 42u8; // scope 1 at $DIR/cast.rs:6:13: 6:24
++ _2 = const 42_u8; // scope 1 at $DIR/cast.rs:6:13: 6:24
+ // ty::Const
+ // + ty: u8
+ // + val: Value(Scalar(0x2a))
bb0: {
StorageLive(_1); // scope 0 at $DIR/checked_add.rs:5:9: 5:10
-- _2 = CheckedAdd(const 1u32, const 1u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23
-+ _2 = (const 2u32, const false); // scope 0 at $DIR/checked_add.rs:5:18: 5:23
+- _2 = CheckedAdd(const 1_u32, const 1_u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23
++ _2 = (const 2_u32, const false); // scope 0 at $DIR/checked_add.rs:5:18: 5:23
// ty::Const
// + ty: u32
- // + val: Value(Scalar(0x00000001))
// mir::Constant
- // + span: $DIR/checked_add.rs:5:22: 5:23
- // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
-- assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
+- assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
+ // + span: $DIR/checked_add.rs:5:18: 5:23
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+ assert(!const false, "attempt to add with overflow") -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
-+ // ty::Const
++ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x00))
+ // mir::Constant
+ // + span: $DIR/checked_add.rs:5:18: 5:23
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
+ // + span: $DIR/checked_add.rs:5:18: 5:19
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
+ // + span: $DIR/checked_add.rs:5:22: 5:23
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
}
bb1: {
- _1 = move (_2.0: u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23
-+ _1 = const 2u32; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
++ _1 = const 2_u32; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000002))
// compile-flags: -O
+// FIXME(wesleywiser): Ideally, we could const-prop away all of this and just be left with
+// `let x = 42` but that doesn't work because const-prop doesn't support `Operand::Indirect`
+// and `InterpCx::eval_place()` always forces an allocation which creates the `Indirect`.
+// Fixing either of those will allow us to const-prop this away.
+
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR rustc.main.ConstProp.diff
fn main() {
+ // MIR for `main` after ConstProp
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:5:11: 5:11
- let _1: i32; // in scope 0 at $DIR/discriminant.rs:6:9: 6:10
- let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:6:13: 6:64
- let mut _3: std::option::Option<bool>; // in scope 0 at $DIR/discriminant.rs:6:34: 6:44
- let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:6:21: 6:31
+ let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:10:11: 10:11
+ let _1: i32; // in scope 0 at $DIR/discriminant.rs:11:9: 11:10
+ let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:11:13: 11:64
+ let mut _3: std::option::Option<bool>; // in scope 0 at $DIR/discriminant.rs:11:34: 11:44
+ let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:11:21: 11:31
scope 1 {
- debug x => _1; // in scope 1 at $DIR/discriminant.rs:6:9: 6:10
+ debug x => _1; // in scope 1 at $DIR/discriminant.rs:11:9: 11:10
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/discriminant.rs:6:9: 6:10
- StorageLive(_2); // scope 0 at $DIR/discriminant.rs:6:13: 6:64
- StorageLive(_3); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
-- _3 = std::option::Option::<bool>::Some(const true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
-+ _3 = const std::option::Option::<bool>::Some(true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
+ StorageLive(_1); // scope 0 at $DIR/discriminant.rs:11:9: 11:10
+ StorageLive(_2); // scope 0 at $DIR/discriminant.rs:11:13: 11:64
+ StorageLive(_3); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
+- _3 = std::option::Option::<bool>::Some(const true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
++ _3 = const std::option::Option::<bool>::Some(true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
// ty::Const
- // + ty: bool
+ // + ty: std::option::Option<bool>
// + val: Value(Scalar(0x01))
// mir::Constant
-- // + span: $DIR/discriminant.rs:6:39: 6:43
+- // + span: $DIR/discriminant.rs:11:39: 11:43
- // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-- _4 = discriminant(_3); // scope 0 at $DIR/discriminant.rs:6:21: 6:31
-- switchInt(move _4) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
-+ // + span: $DIR/discriminant.rs:6:34: 6:44
+- _4 = discriminant(_3); // scope 0 at $DIR/discriminant.rs:11:21: 11:31
+- switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
++ // + span: $DIR/discriminant.rs:11:34: 11:44
+ // + literal: Const { ty: std::option::Option<bool>, val: Value(Scalar(0x01)) }
-+ _4 = const 1isize; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
++ _4 = const 1_isize; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
+ // ty::Const
+ // + ty: isize
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
-+ // + span: $DIR/discriminant.rs:6:21: 6:31
++ // + span: $DIR/discriminant.rs:11:21: 11:31
+ // + literal: Const { ty: isize, val: Value(Scalar(0x00000001)) }
-+ switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
++ switchInt(const 1_isize) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
+ // ty::Const
+ // + ty: isize
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
-+ // + span: $DIR/discriminant.rs:6:21: 6:31
++ // + span: $DIR/discriminant.rs:11:21: 11:31
+ // + literal: Const { ty: isize, val: Value(Scalar(0x00000001)) }
}
bb1: {
- _2 = const 10i32; // scope 0 at $DIR/discriminant.rs:6:59: 6:61
+ _2 = const 10_i32; // scope 0 at $DIR/discriminant.rs:11:59: 11:61
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000000a))
// mir::Constant
- // + span: $DIR/discriminant.rs:6:59: 6:61
+ // + span: $DIR/discriminant.rs:11:59: 11:61
// + literal: Const { ty: i32, val: Value(Scalar(0x0000000a)) }
- goto -> bb4; // scope 0 at $DIR/discriminant.rs:6:13: 6:64
+ goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64
}
bb2: {
-- switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30
-+ switchInt(const true) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30
-+ // ty::Const
-+ // + ty: bool
-+ // + val: Value(Scalar(0x01))
-+ // mir::Constant
-+ // + span: $DIR/discriminant.rs:6:26: 6:30
-+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+ switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
}
bb3: {
- _2 = const 42i32; // scope 0 at $DIR/discriminant.rs:6:47: 6:49
+ _2 = const 42_i32; // scope 0 at $DIR/discriminant.rs:11:47: 11:49
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002a))
// mir::Constant
- // + span: $DIR/discriminant.rs:6:47: 6:49
+ // + span: $DIR/discriminant.rs:11:47: 11:49
// + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
- goto -> bb4; // scope 0 at $DIR/discriminant.rs:6:13: 6:64
+ goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64
}
bb4: {
- _1 = Add(move _2, const 0i32); // scope 0 at $DIR/discriminant.rs:6:13: 6:68
+ _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/discriminant.rs:11:13: 11:68
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
// mir::Constant
- // + span: $DIR/discriminant.rs:6:67: 6:68
+ // + span: $DIR/discriminant.rs:11:67: 11:68
// + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
- StorageDead(_2); // scope 0 at $DIR/discriminant.rs:6:67: 6:68
- StorageDead(_3); // scope 0 at $DIR/discriminant.rs:6:68: 6:69
- _0 = const (); // scope 0 at $DIR/discriminant.rs:5:11: 7:2
+ StorageDead(_2); // scope 0 at $DIR/discriminant.rs:11:67: 11:68
+ StorageDead(_3); // scope 0 at $DIR/discriminant.rs:11:68: 11:69
+ _0 = const (); // scope 0 at $DIR/discriminant.rs:10:11: 12:2
// ty::Const
// + ty: ()
// + val: Value(Scalar(<ZST>))
// mir::Constant
- // + span: $DIR/discriminant.rs:5:11: 7:2
+ // + span: $DIR/discriminant.rs:10:11: 12:2
// + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
- StorageDead(_1); // scope 0 at $DIR/discriminant.rs:7:1: 7:2
- return; // scope 0 at $DIR/discriminant.rs:7:2: 7:2
+ StorageDead(_1); // scope 0 at $DIR/discriminant.rs:12:1: 12:2
+ return; // scope 0 at $DIR/discriminant.rs:12:2: 12:2
}
}
+ // MIR for `main` after ConstProp
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:5:11: 5:11
- let _1: i32; // in scope 0 at $DIR/discriminant.rs:6:9: 6:10
- let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:6:13: 6:64
- let mut _3: std::option::Option<bool>; // in scope 0 at $DIR/discriminant.rs:6:34: 6:44
- let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:6:21: 6:31
+ let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:10:11: 10:11
+ let _1: i32; // in scope 0 at $DIR/discriminant.rs:11:9: 11:10
+ let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:11:13: 11:64
+ let mut _3: std::option::Option<bool>; // in scope 0 at $DIR/discriminant.rs:11:34: 11:44
+ let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:11:21: 11:31
scope 1 {
- debug x => _1; // in scope 1 at $DIR/discriminant.rs:6:9: 6:10
+ debug x => _1; // in scope 1 at $DIR/discriminant.rs:11:9: 11:10
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/discriminant.rs:6:9: 6:10
- StorageLive(_2); // scope 0 at $DIR/discriminant.rs:6:13: 6:64
- StorageLive(_3); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
-- _3 = std::option::Option::<bool>::Some(const true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
-+ _3 = const std::option::Option::<bool>::Some(true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
+ StorageLive(_1); // scope 0 at $DIR/discriminant.rs:11:9: 11:10
+ StorageLive(_2); // scope 0 at $DIR/discriminant.rs:11:13: 11:64
+ StorageLive(_3); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
+- _3 = std::option::Option::<bool>::Some(const true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
++ _3 = const std::option::Option::<bool>::Some(true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
// ty::Const
- // + ty: bool
+ // + ty: std::option::Option<bool>
// + val: Value(Scalar(0x01))
// mir::Constant
-- // + span: $DIR/discriminant.rs:6:39: 6:43
+- // + span: $DIR/discriminant.rs:11:39: 11:43
- // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-- _4 = discriminant(_3); // scope 0 at $DIR/discriminant.rs:6:21: 6:31
-- switchInt(move _4) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
-+ // + span: $DIR/discriminant.rs:6:34: 6:44
+- _4 = discriminant(_3); // scope 0 at $DIR/discriminant.rs:11:21: 11:31
+- switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
++ // + span: $DIR/discriminant.rs:11:34: 11:44
+ // + literal: Const { ty: std::option::Option<bool>, val: Value(Scalar(0x01)) }
-+ _4 = const 1isize; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
++ _4 = const 1_isize; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
+ // ty::Const
+ // + ty: isize
+ // + val: Value(Scalar(0x0000000000000001))
+ // mir::Constant
-+ // + span: $DIR/discriminant.rs:6:21: 6:31
++ // + span: $DIR/discriminant.rs:11:21: 11:31
+ // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000001)) }
-+ switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
++ switchInt(const 1_isize) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
+ // ty::Const
+ // + ty: isize
+ // + val: Value(Scalar(0x0000000000000001))
+ // mir::Constant
-+ // + span: $DIR/discriminant.rs:6:21: 6:31
++ // + span: $DIR/discriminant.rs:11:21: 11:31
+ // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000001)) }
}
bb1: {
- _2 = const 10i32; // scope 0 at $DIR/discriminant.rs:6:59: 6:61
+ _2 = const 10_i32; // scope 0 at $DIR/discriminant.rs:11:59: 11:61
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000000a))
// mir::Constant
- // + span: $DIR/discriminant.rs:6:59: 6:61
+ // + span: $DIR/discriminant.rs:11:59: 11:61
// + literal: Const { ty: i32, val: Value(Scalar(0x0000000a)) }
- goto -> bb4; // scope 0 at $DIR/discriminant.rs:6:13: 6:64
+ goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64
}
bb2: {
-- switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30
-+ switchInt(const true) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30
-+ // ty::Const
-+ // + ty: bool
-+ // + val: Value(Scalar(0x01))
-+ // mir::Constant
-+ // + span: $DIR/discriminant.rs:6:26: 6:30
-+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+ switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
}
bb3: {
- _2 = const 42i32; // scope 0 at $DIR/discriminant.rs:6:47: 6:49
+ _2 = const 42_i32; // scope 0 at $DIR/discriminant.rs:11:47: 11:49
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002a))
// mir::Constant
- // + span: $DIR/discriminant.rs:6:47: 6:49
+ // + span: $DIR/discriminant.rs:11:47: 11:49
// + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
- goto -> bb4; // scope 0 at $DIR/discriminant.rs:6:13: 6:64
+ goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64
}
bb4: {
- _1 = Add(move _2, const 0i32); // scope 0 at $DIR/discriminant.rs:6:13: 6:68
+ _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/discriminant.rs:11:13: 11:68
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
// mir::Constant
- // + span: $DIR/discriminant.rs:6:67: 6:68
+ // + span: $DIR/discriminant.rs:11:67: 11:68
// + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
- StorageDead(_2); // scope 0 at $DIR/discriminant.rs:6:67: 6:68
- StorageDead(_3); // scope 0 at $DIR/discriminant.rs:6:68: 6:69
- _0 = const (); // scope 0 at $DIR/discriminant.rs:5:11: 7:2
+ StorageDead(_2); // scope 0 at $DIR/discriminant.rs:11:67: 11:68
+ StorageDead(_3); // scope 0 at $DIR/discriminant.rs:11:68: 11:69
+ _0 = const (); // scope 0 at $DIR/discriminant.rs:10:11: 12:2
// ty::Const
// + ty: ()
// + val: Value(Scalar(<ZST>))
// mir::Constant
- // + span: $DIR/discriminant.rs:5:11: 7:2
+ // + span: $DIR/discriminant.rs:10:11: 12:2
// + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
- StorageDead(_1); // scope 0 at $DIR/discriminant.rs:7:1: 7:2
- return; // scope 0 at $DIR/discriminant.rs:7:2: 7:2
+ StorageDead(_1); // scope 0 at $DIR/discriminant.rs:12:1: 12:2
+ return; // scope 0 at $DIR/discriminant.rs:12:2: 12:2
}
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/indirect.rs:5:9: 5:10
StorageLive(_2); // scope 0 at $DIR/indirect.rs:5:13: 5:25
-- _2 = const 2u32 as u8 (Misc); // scope 0 at $DIR/indirect.rs:5:13: 5:25
-+ _2 = const 2u8; // scope 0 at $DIR/indirect.rs:5:13: 5:25
+- _2 = const 2_u32 as u8 (Misc); // scope 0 at $DIR/indirect.rs:5:13: 5:25
++ _2 = const 2_u8; // scope 0 at $DIR/indirect.rs:5:13: 5:25
// ty::Const
- // + ty: u32
- // + val: Value(Scalar(0x00000002))
// mir::Constant
- // + span: $DIR/indirect.rs:5:14: 5:18
- // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
-- _3 = CheckedAdd(move _2, const 1u8); // scope 0 at $DIR/indirect.rs:5:13: 5:29
+- _3 = CheckedAdd(_2, const 1_u8); // scope 0 at $DIR/indirect.rs:5:13: 5:29
+ // + span: $DIR/indirect.rs:5:13: 5:25
+ // + literal: Const { ty: u8, val: Value(Scalar(0x02)) }
-+ _3 = (const 3u8, const false); // scope 0 at $DIR/indirect.rs:5:13: 5:29
++ _3 = (const 3_u8, const false); // scope 0 at $DIR/indirect.rs:5:13: 5:29
// ty::Const
// + ty: u8
- // + val: Value(Scalar(0x01))
// mir::Constant
- // + span: $DIR/indirect.rs:5:28: 5:29
- // + literal: Const { ty: u8, val: Value(Scalar(0x01)) }
-- assert(!move (_3.1: bool), "attempt to add with overflow") -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
+- assert(!move (_3.1: bool), "attempt to compute `{} + {}` which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
+ // + span: $DIR/indirect.rs:5:13: 5:29
+ // + literal: Const { ty: u8, val: Value(Scalar(0x03)) }
-+ // ty::Const
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x00))
+ // mir::Constant
+ // + span: $DIR/indirect.rs:5:13: 5:29
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+ assert(!const false, "attempt to add with overflow") -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
++ assert(!const false, "attempt to compute `{} + {}` which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x00))
+ // mir::Constant
+ // + span: $DIR/indirect.rs:5:13: 5:29
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++ // ty::Const
+ // + ty: u8
+ // + val: Value(Scalar(0x01))
+ // mir::Constant
+ // + span: $DIR/indirect.rs:5:28: 5:29
+ // + literal: Const { ty: u8, val: Value(Scalar(0x01)) }
}
bb1: {
- _1 = move (_3.0: u8); // scope 0 at $DIR/indirect.rs:5:13: 5:29
-+ _1 = const 3u8; // scope 0 at $DIR/indirect.rs:5:13: 5:29
++ _1 = const 3_u8; // scope 0 at $DIR/indirect.rs:5:13: 5:29
+ // ty::Const
+ // + ty: u8
+ // + val: Value(Scalar(0x03))
+ // mir::Constant
+ // + span: $DIR/issue-66971.rs:16:13: 16:15
+ // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
- _2 = (move _3, const 0u8, const 0u8); // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
+ _2 = (move _3, const 0_u8, const 0_u8); // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
// ty::Const
// + ty: u8
// + val: Value(Scalar(0x00))
StorageLive(_1); // scope 0 at $DIR/issue-67019.rs:11:5: 11:20
StorageLive(_2); // scope 0 at $DIR/issue-67019.rs:11:10: 11:19
StorageLive(_3); // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
- _3 = (const 1u8, const 2u8); // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
+ _3 = (const 1_u8, const 2_u8); // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
// ty::Const
// + ty: u8
// + val: Value(Scalar(0x01))
bb0: {
StorageLive(_1); // scope 0 at $DIR/mutable_variable.rs:5:9: 5:14
- _1 = const 42i32; // scope 0 at $DIR/mutable_variable.rs:5:17: 5:19
+ _1 = const 42_i32; // scope 0 at $DIR/mutable_variable.rs:5:17: 5:19
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002a))
// mir::Constant
// + span: $DIR/mutable_variable.rs:5:17: 5:19
// + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
- _1 = const 99i32; // scope 1 at $DIR/mutable_variable.rs:6:5: 6:11
+ _1 = const 99_i32; // scope 1 at $DIR/mutable_variable.rs:6:5: 6:11
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000063))
// + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
StorageLive(_2); // scope 1 at $DIR/mutable_variable.rs:7:9: 7:10
- _2 = _1; // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14
-+ _2 = const 99i32; // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14
++ _2 = const 99_i32; // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000063))
bb0: {
StorageLive(_1); // scope 0 at $DIR/mutable_variable_aggregate.rs:5:9: 5:14
- _1 = (const 42i32, const 43i32); // scope 0 at $DIR/mutable_variable_aggregate.rs:5:17: 5:25
+ _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/mutable_variable_aggregate.rs:5:17: 5:25
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002a))
- // + span: $DIR/mutable_variable_aggregate.rs:5:22: 5:24
+ // + span: $DIR/mutable_variable_aggregate.rs:5:17: 5:25
// + literal: Const { ty: i32, val: Value(Scalar(0x0000002b)) }
- (_1.1: i32) = const 99i32; // scope 1 at $DIR/mutable_variable_aggregate.rs:6:5: 6:13
+ (_1.1: i32) = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate.rs:6:5: 6:13
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000063))
// + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10
- _2 = _1; // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
-+ _2 = (const 42i32, const 99i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
++ _2 = (const 42_i32, const 99_i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x0000002a))
bb0: {
StorageLive(_1); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:9: 5:14
- _1 = (const 42i32, const 43i32); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
+ _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002a))
// mir::Constant
- // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:18: 5:20
+- // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:18: 5:20
++ // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
// + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002b))
// mir::Constant
- // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:22: 5:24
+- // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:22: 5:24
++ // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
// + literal: Const { ty: i32, val: Value(Scalar(0x0000002b)) }
StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10
_2 = &mut _1; // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:13: 6:19
- ((*_2).1: i32) = const 99i32; // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:7:5: 7:13
+ ((*_2).1: i32) = const 99_i32; // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:7:5: 7:13
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000063))
}
bb1: {
- (_1.1: i32) = const 99i32; // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:6:5: 6:13
+ (_1.1: i32) = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:6:5: 6:13
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000063))
// mir::Constant
// + span: $DIR/mutable_variable_aggregate_partial_read.rs:6:11: 6:13
// + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
- (_1.0: i32) = const 42i32; // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:7:5: 7:13
+ (_1.0: i32) = const 42_i32; // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:7:5: 7:13
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002a))
// + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:9: 8:10
- _2 = (_1.1: i32); // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:13: 8:16
-+ _2 = const 99i32; // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:13: 8:16
++ _2 = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:13: 8:16
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000063))
bb0: {
StorageLive(_1); // scope 0 at $DIR/mutable_variable_no_prop.rs:7:9: 7:14
- _1 = const 42u32; // scope 0 at $DIR/mutable_variable_no_prop.rs:7:17: 7:19
+ _1 = const 42_u32; // scope 0 at $DIR/mutable_variable_no_prop.rs:7:17: 7:19
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x0000002a))
bb1: {
StorageLive(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:9: 6:14
- _2 = (const 1i32, const 2i32); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35
+ _2 = (const 1_i32, const 2_i32); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
bb0: {
StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10
-- _2 = CheckedAdd(const 2i32, const 2i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+ _2 = (const 4i32, const false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+- _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
++ _2 = (const 4_i32, const false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
// ty::Const
// + ty: i32
- // + val: Value(Scalar(0x00000002))
// mir::Constant
- // + span: $DIR/optimizes_into_variable.rs:12:17: 12:18
- // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
-- assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+- assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+ // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+ assert(!const false, "attempt to add with overflow") -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+ // ty::Const
++ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x00))
+ // mir::Constant
+ // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000002))
+ // mir::Constant
+ // + span: $DIR/optimizes_into_variable.rs:12:13: 12:14
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000002))
+ // mir::Constant
+ // + span: $DIR/optimizes_into_variable.rs:12:17: 12:18
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
}
bb1: {
- _1 = move (_2.0: i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+ _1 = const 4i32; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
++ _1 = const 4_i32; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000004))
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) }
StorageLive(_3); // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10
StorageLive(_4); // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31
- _4 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32]; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31
+ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/optimizes_into_variable.rs:13:29: 13:30
// + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
StorageLive(_5); // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33
- _5 = const 3usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33
+ _5 = const 3_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000003))
// mir::Constant
// + span: $DIR/optimizes_into_variable.rs:13:32: 13:33
// + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
- _6 = const 6usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
+ _6 = const 6_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000006))
bb2: {
- _3 = _4[_5]; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
-+ _3 = const 3i32; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
++ _3 = const 3_i32; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000003))
StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:13:34: 13:35
StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10
StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
- _9 = Point { x: const 12u32, y: const 42u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
+ _9 = Point { x: const 12_u32, y: const 42_u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x0000000c))
// + span: $DIR/optimizes_into_variable.rs:14:32: 14:34
// + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
-+ _8 = const 42u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
++ _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x0000002a))
bb0: {
StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10
- _1 = const 4i32; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+ _1 = const 4_i32; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000004))
// + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
// + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) }
StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10
- _2 = const 3i32; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
+ _2 = const 3_i32; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000003))
// + span: $DIR/optimizes_into_variable.rs:13:13: 13:34
// + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10
- _3 = const 42u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
+ _3 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x0000002a))
bb0: {
StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10
-- _2 = CheckedAdd(const 2i32, const 2i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+ _2 = (const 4i32, const false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+- _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
++ _2 = (const 4_i32, const false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
// ty::Const
// + ty: i32
- // + val: Value(Scalar(0x00000002))
// mir::Constant
- // + span: $DIR/optimizes_into_variable.rs:12:17: 12:18
- // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
-- assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+- assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+ // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+ assert(!const false, "attempt to add with overflow") -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+ // ty::Const
++ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x00))
+ // mir::Constant
+ // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000002))
+ // mir::Constant
+ // + span: $DIR/optimizes_into_variable.rs:12:13: 12:14
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000002))
+ // mir::Constant
+ // + span: $DIR/optimizes_into_variable.rs:12:17: 12:18
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
}
bb1: {
- _1 = move (_2.0: i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+ _1 = const 4i32; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
++ _1 = const 4_i32; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000004))
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) }
StorageLive(_3); // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10
StorageLive(_4); // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31
- _4 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32]; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31
+ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/optimizes_into_variable.rs:13:29: 13:30
// + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
StorageLive(_5); // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33
- _5 = const 3usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33
+ _5 = const 3_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000003))
// mir::Constant
// + span: $DIR/optimizes_into_variable.rs:13:32: 13:33
// + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
- _6 = const 6usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
+ _6 = const 6_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000006))
bb2: {
- _3 = _4[_5]; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
-+ _3 = const 3i32; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
++ _3 = const 3_i32; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000003))
StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:13:34: 13:35
StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10
StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
- _9 = Point { x: const 12u32, y: const 42u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
+ _9 = Point { x: const 12_u32, y: const 42_u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x0000000c))
// + span: $DIR/optimizes_into_variable.rs:14:32: 14:34
// + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
-+ _8 = const 42u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
++ _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x0000002a))
bb0: {
StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10
- _1 = const 4i32; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+ _1 = const 4_i32; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000004))
// + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
// + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) }
StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10
- _2 = const 3i32; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
+ _2 = const 3_i32; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000003))
// + span: $DIR/optimizes_into_variable.rs:13:13: 13:34
// + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10
- _3 = const 42u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
+ _3 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x0000002a))
// + span: $DIR/read_immutable_static.rs:7:13: 7:16
// + literal: Const { ty: &u8, val: Value(Scalar(alloc0)) }
- _2 = (*_3); // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
-+ _2 = const 2u8; // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
++ _2 = const 2_u8; // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
+ // ty::Const
+ // + ty: u8
+ // + val: Value(Scalar(0x02))
// + literal: Const { ty: &u8, val: Value(Scalar(alloc0)) }
- _4 = (*_5); // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
- _1 = Add(move _2, move _4); // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:22
-+ _4 = const 2u8; // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
++ _4 = const 2_u8; // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
+ // ty::Const
+ // + ty: u8
+ // + val: Value(Scalar(0x02))
+ // mir::Constant
+ // + span: $DIR/read_immutable_static.rs:7:19: 7:22
+ // + literal: Const { ty: u8, val: Value(Scalar(0x02)) }
-+ _1 = const 4u8; // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:22
++ _1 = const 4_u8; // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:22
+ // ty::Const
+ // + ty: u8
+ // + val: Value(Scalar(0x04))
// + literal: Const { ty: &i32, val: Unevaluated(DefId(0:3 ~ ref_deref[317d]::main[0]), [], Some(promoted[0])) }
_2 = _4; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
- _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
-+ _1 = const 4i32; // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
++ _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000004))
StorageLive(_1); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
StorageLive(_2); // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
- StorageLive(_3); // scope 0 at $DIR/ref_deref.rs:5:8: 5:9
-- _3 = const 4i32; // scope 0 at $DIR/ref_deref.rs:5:8: 5:9
+- _3 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:8: 5:9
+ _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
// ty::Const
- // + ty: i32
StorageLive(_1); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
StorageLive(_2); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
- StorageLive(_3); // scope 0 at $DIR/ref_deref_project.rs:5:8: 5:14
-- _3 = (const 4i32, const 5i32); // scope 0 at $DIR/ref_deref_project.rs:5:8: 5:14
+- _3 = (const 4_i32, const 5_i32); // scope 0 at $DIR/ref_deref_project.rs:5:8: 5:14
+ _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
// ty::Const
- // + ty: i32
StorageLive(_1); // scope 0 at $DIR/repeat.rs:6:9: 6:10
StorageLive(_2); // scope 0 at $DIR/repeat.rs:6:18: 6:28
StorageLive(_3); // scope 0 at $DIR/repeat.rs:6:18: 6:25
- _3 = [const 42u32; 8]; // scope 0 at $DIR/repeat.rs:6:18: 6:25
+ _3 = [const 42_u32; 8]; // scope 0 at $DIR/repeat.rs:6:18: 6:25
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x0000002a))
// + span: $DIR/repeat.rs:6:19: 6:21
// + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
StorageLive(_4); // scope 0 at $DIR/repeat.rs:6:26: 6:27
- _4 = const 2usize; // scope 0 at $DIR/repeat.rs:6:26: 6:27
+ _4 = const 2_usize; // scope 0 at $DIR/repeat.rs:6:26: 6:27
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000002))
// mir::Constant
// + span: $DIR/repeat.rs:6:26: 6:27
// + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) }
- _5 = const 8usize; // scope 0 at $DIR/repeat.rs:6:18: 6:28
+ _5 = const 8_usize; // scope 0 at $DIR/repeat.rs:6:18: 6:28
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000008))
bb1: {
- _2 = _3[_4]; // scope 0 at $DIR/repeat.rs:6:18: 6:28
-- _1 = Add(move _2, const 0u32); // scope 0 at $DIR/repeat.rs:6:18: 6:32
-+ _2 = const 42u32; // scope 0 at $DIR/repeat.rs:6:18: 6:28
+- _1 = Add(move _2, const 0_u32); // scope 0 at $DIR/repeat.rs:6:18: 6:32
++ _2 = const 42_u32; // scope 0 at $DIR/repeat.rs:6:18: 6:28
// ty::Const
// + ty: u32
- // + val: Value(Scalar(0x00000000))
- // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
+ // + span: $DIR/repeat.rs:6:18: 6:28
+ // + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
-+ _1 = const 42u32; // scope 0 at $DIR/repeat.rs:6:18: 6:32
++ _1 = const 42_u32; // scope 0 at $DIR/repeat.rs:6:18: 6:32
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x0000002a))
StorageLive(_1); // scope 0 at $DIR/repeat.rs:6:9: 6:10
StorageLive(_2); // scope 0 at $DIR/repeat.rs:6:18: 6:28
StorageLive(_3); // scope 0 at $DIR/repeat.rs:6:18: 6:25
- _3 = [const 42u32; 8]; // scope 0 at $DIR/repeat.rs:6:18: 6:25
+ _3 = [const 42_u32; 8]; // scope 0 at $DIR/repeat.rs:6:18: 6:25
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x0000002a))
// + span: $DIR/repeat.rs:6:19: 6:21
// + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
StorageLive(_4); // scope 0 at $DIR/repeat.rs:6:26: 6:27
- _4 = const 2usize; // scope 0 at $DIR/repeat.rs:6:26: 6:27
+ _4 = const 2_usize; // scope 0 at $DIR/repeat.rs:6:26: 6:27
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000002))
// mir::Constant
// + span: $DIR/repeat.rs:6:26: 6:27
// + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) }
- _5 = const 8usize; // scope 0 at $DIR/repeat.rs:6:18: 6:28
+ _5 = const 8_usize; // scope 0 at $DIR/repeat.rs:6:18: 6:28
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000008))
bb1: {
- _2 = _3[_4]; // scope 0 at $DIR/repeat.rs:6:18: 6:28
-- _1 = Add(move _2, const 0u32); // scope 0 at $DIR/repeat.rs:6:18: 6:32
-+ _2 = const 42u32; // scope 0 at $DIR/repeat.rs:6:18: 6:28
+- _1 = Add(move _2, const 0_u32); // scope 0 at $DIR/repeat.rs:6:18: 6:32
++ _2 = const 42_u32; // scope 0 at $DIR/repeat.rs:6:18: 6:28
// ty::Const
// + ty: u32
- // + val: Value(Scalar(0x00000000))
- // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
+ // + span: $DIR/repeat.rs:6:18: 6:28
+ // + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
-+ _1 = const 42u32; // scope 0 at $DIR/repeat.rs:6:18: 6:32
++ _1 = const 42_u32; // scope 0 at $DIR/repeat.rs:6:18: 6:32
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x0000002a))
let mut _1: (u32, bool); // in scope 0 at $DIR/return_place.rs:6:5: 6:10
bb0: {
-- _1 = CheckedAdd(const 2u32, const 2u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10
-+ _1 = (const 4u32, const false); // scope 0 at $DIR/return_place.rs:6:5: 6:10
+- _1 = CheckedAdd(const 2_u32, const 2_u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10
++ _1 = (const 4_u32, const false); // scope 0 at $DIR/return_place.rs:6:5: 6:10
// ty::Const
// + ty: u32
- // + val: Value(Scalar(0x00000002))
// mir::Constant
- // + span: $DIR/return_place.rs:6:9: 6:10
- // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
-- assert(!move (_1.1: bool), "attempt to add with overflow") -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10
+- assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10
+ // + span: $DIR/return_place.rs:6:5: 6:10
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+ assert(!const false, "attempt to add with overflow") -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10
-+ // ty::Const
++ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x00))
+ // mir::Constant
+ // + span: $DIR/return_place.rs:6:5: 6:10
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000002))
+ // mir::Constant
+ // + span: $DIR/return_place.rs:6:5: 6:6
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000002))
+ // mir::Constant
+ // + span: $DIR/return_place.rs:6:9: 6:10
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
}
bb1: {
- _0 = move (_1.0: u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10
-+ _0 = const 4u32; // scope 0 at $DIR/return_place.rs:6:5: 6:10
++ _0 = const 4_u32; // scope 0 at $DIR/return_place.rs:6:5: 6:10
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000004))
let mut _0: u32; // return place in scope 0 at $DIR/return_place.rs:5:13: 5:16
bb0: {
- _0 = const 4u32; // scope 0 at $DIR/return_place.rs:6:5: 6:10
+ _0 = const 4_u32; // scope 0 at $DIR/return_place.rs:6:5: 6:10
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000004))
bb0: {
StorageLive(_1); // scope 0 at $DIR/scalar_literal_propagation.rs:3:9: 3:10
- _1 = const 1u32; // scope 0 at $DIR/scalar_literal_propagation.rs:3:13: 3:14
+ _1 = const 1_u32; // scope 0 at $DIR/scalar_literal_propagation.rs:3:13: 3:14
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000001))
StorageLive(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
- _3 = _1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
- _2 = const consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15
-+ _3 = const 1u32; // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
++ _3 = const 1_u32; // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
// ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
+ // + span: $DIR/scalar_literal_propagation.rs:4:13: 4:14
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
-+ _2 = const consume(const 1u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15
++ _2 = const consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15
+ // ty::Const
// + ty: fn(u32) {consume}
// + val: Value(Scalar(<ZST>))
_2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
StorageDead(_3); // scope 0 at $DIR/slice_len.rs:5:18: 5:19
StorageLive(_6); // scope 0 at $DIR/slice_len.rs:5:31: 5:32
- _6 = const 1usize; // scope 0 at $DIR/slice_len.rs:5:31: 5:32
+ _6 = const 1_usize; // scope 0 at $DIR/slice_len.rs:5:31: 5:32
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000001))
- _7 = Len((*_2)); // scope 0 at $DIR/slice_len.rs:5:5: 5:33
- _8 = Lt(_6, _7); // scope 0 at $DIR/slice_len.rs:5:5: 5:33
- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
-+ _7 = const 3usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
++ _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x00000003))
bb1: {
- _1 = (*_2)[_6]; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
-+ _1 = const 2u32; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
++ _1 = const 2_u32; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000002))
_2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
StorageDead(_3); // scope 0 at $DIR/slice_len.rs:5:18: 5:19
StorageLive(_6); // scope 0 at $DIR/slice_len.rs:5:31: 5:32
- _6 = const 1usize; // scope 0 at $DIR/slice_len.rs:5:31: 5:32
+ _6 = const 1_usize; // scope 0 at $DIR/slice_len.rs:5:31: 5:32
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000001))
- _7 = Len((*_2)); // scope 0 at $DIR/slice_len.rs:5:5: 5:33
- _8 = Lt(_6, _7); // scope 0 at $DIR/slice_len.rs:5:5: 5:33
- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
-+ _7 = const 3usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
++ _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x0000000000000003))
bb1: {
- _1 = (*_2)[_6]; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
-+ _1 = const 2u32; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
++ _1 = const 2_u32; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000002))
bb0: {
StorageLive(_1); // scope 0 at $DIR/switch_int.rs:7:11: 7:12
- _1 = const 1i32; // scope 0 at $DIR/switch_int.rs:7:11: 7:12
+ _1 = const 1_i32; // scope 0 at $DIR/switch_int.rs:7:11: 7:12
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
// mir::Constant
// + span: $DIR/switch_int.rs:7:11: 7:12
// + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
-- switchInt(_1) -> [1i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:8:9: 8:10
-+ switchInt(const 1i32) -> [1i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:8:9: 8:10
+- switchInt(_1) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:8:9: 8:10
++ switchInt(const 1_i32) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:8:9: 8:10
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000001))
}
bb1: {
- _0 = const foo(const -1i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21
+ _0 = const foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21
// ty::Const
// + ty: fn(i32) {foo}
// + val: Value(Scalar(<ZST>))
}
bb2: {
- _0 = const foo(const 0i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20
+ _0 = const foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20
// ty::Const
// + ty: fn(i32) {foo}
// + val: Value(Scalar(<ZST>))
bb0: {
StorageLive(_1); // scope 0 at $DIR/switch_int.rs:7:11: 7:12
- _1 = const 1i32; // scope 0 at $DIR/switch_int.rs:7:11: 7:12
+ _1 = const 1_i32; // scope 0 at $DIR/switch_int.rs:7:11: 7:12
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
// mir::Constant
// + span: $DIR/switch_int.rs:7:11: 7:12
// + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
-- switchInt(const 1i32) -> [1i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:8:9: 8:10
+- switchInt(const 1_i32) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:8:9: 8:10
- // ty::Const
- // + ty: i32
- // + val: Value(Scalar(0x00000001))
}
bb1: {
- _0 = const foo(const -1i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21
+ _0 = const foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21
// ty::Const
// + ty: fn(i32) {foo}
// + val: Value(Scalar(<ZST>))
}
bb2: {
- _0 = const foo(const 0i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20
+ _0 = const foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20
// ty::Const
// + ty: fn(i32) {foo}
// + val: Value(Scalar(<ZST>))
bb0: {
StorageLive(_1); // scope 0 at $DIR/tuple_literal_propagation.rs:3:9: 3:10
- _1 = (const 1u32, const 2u32); // scope 0 at $DIR/tuple_literal_propagation.rs:3:13: 3:19
+ _1 = (const 1_u32, const 2_u32); // scope 0 at $DIR/tuple_literal_propagation.rs:3:13: 3:19
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000001))
StorageLive(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15
StorageLive(_3); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
- _3 = _1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
-+ _3 = (const 1u32, const 2u32); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
++ _3 = (const 1_u32, const 2_u32); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000001))
--- /dev/null
+#![feature(raw_ref_op)]
+
+// EMIT_MIR rustc.foo.ConstProp.diff
+fn foo() {
+ let mut u = (1,);
+ *&mut u.0 = 5;
+ let y = { u.0 } == 5;
+}
+
+// EMIT_MIR rustc.bar.ConstProp.diff
+fn bar() {
+ let mut v = (1,);
+ unsafe {
+ *&raw mut v.0 = 5;
+ }
+ let y = { v.0 } == 5;
+}
+
+fn main() {
+ foo();
+ bar();
+}
--- /dev/null
+- // MIR for `bar` before ConstProp
++ // MIR for `bar` after ConstProp
+
+ fn bar() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/const_prop_miscompile.rs:11:10: 11:10
+ let mut _1: (i32,); // in scope 0 at $DIR/const_prop_miscompile.rs:12:9: 12:14
+ let _2: (); // in scope 0 at $DIR/const_prop_miscompile.rs:13:5: 15:6
+ let mut _3: *mut i32; // in scope 0 at $DIR/const_prop_miscompile.rs:14:10: 14:22
+ let mut _5: i32; // in scope 0 at $DIR/const_prop_miscompile.rs:16:13: 16:20
+ scope 1 {
+ debug v => _1; // in scope 1 at $DIR/const_prop_miscompile.rs:12:9: 12:14
+ let _4: bool; // in scope 1 at $DIR/const_prop_miscompile.rs:16:9: 16:10
+ scope 2 {
+ }
+ scope 3 {
+ debug y => _4; // in scope 3 at $DIR/const_prop_miscompile.rs:16:9: 16:10
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/const_prop_miscompile.rs:12:9: 12:14
+- _1 = (const 1_i32,); // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21
++ _1 = const (1_i32,); // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21
+ // ty::Const
+- // + ty: i32
++ // + ty: (i32,)
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
+- // + span: $DIR/const_prop_miscompile.rs:12:18: 12:19
+- // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
++ // + span: $DIR/const_prop_miscompile.rs:12:17: 12:21
++ // + literal: Const { ty: (i32,), val: Value(Scalar(0x00000001)) }
+ StorageLive(_2); // scope 1 at $DIR/const_prop_miscompile.rs:13:5: 15:6
+ StorageLive(_3); // scope 2 at $DIR/const_prop_miscompile.rs:14:10: 14:22
+ _3 = &raw mut (_1.0: i32); // scope 2 at $DIR/const_prop_miscompile.rs:14:10: 14:22
+ (*_3) = const 5_i32; // scope 2 at $DIR/const_prop_miscompile.rs:14:9: 14:26
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000005))
+ // mir::Constant
+ // + span: $DIR/const_prop_miscompile.rs:14:25: 14:26
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+ StorageDead(_3); // scope 2 at $DIR/const_prop_miscompile.rs:14:26: 14:27
+ _2 = const (); // scope 2 at $DIR/const_prop_miscompile.rs:13:5: 15:6
+ // ty::Const
+ // + ty: ()
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/const_prop_miscompile.rs:13:5: 15:6
+ // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+ StorageDead(_2); // scope 1 at $DIR/const_prop_miscompile.rs:15:5: 15:6
+ StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:16:9: 16:10
+ StorageLive(_5); // scope 1 at $DIR/const_prop_miscompile.rs:16:13: 16:20
+ _5 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:16:15: 16:18
+ _4 = Eq(move _5, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:16:13: 16:25
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000005))
+ // mir::Constant
+ // + span: $DIR/const_prop_miscompile.rs:16:24: 16:25
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+ StorageDead(_5); // scope 1 at $DIR/const_prop_miscompile.rs:16:24: 16:25
+ _0 = const (); // scope 0 at $DIR/const_prop_miscompile.rs:11:10: 17:2
+ // ty::Const
+ // + ty: ()
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/const_prop_miscompile.rs:11:10: 17:2
+ // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+ StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:17:1: 17:2
+ StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:17:1: 17:2
+ return; // scope 0 at $DIR/const_prop_miscompile.rs:17:2: 17:2
+ }
+ }
+
--- /dev/null
+- // MIR for `foo` before ConstProp
++ // MIR for `foo` after ConstProp
+
+ fn foo() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/const_prop_miscompile.rs:4:10: 4:10
+ let mut _1: (i32,); // in scope 0 at $DIR/const_prop_miscompile.rs:5:9: 5:14
+ let mut _2: &mut i32; // in scope 0 at $DIR/const_prop_miscompile.rs:6:6: 6:14
+ let mut _4: i32; // in scope 0 at $DIR/const_prop_miscompile.rs:7:13: 7:20
+ scope 1 {
+ debug u => _1; // in scope 1 at $DIR/const_prop_miscompile.rs:5:9: 5:14
+ let _3: bool; // in scope 1 at $DIR/const_prop_miscompile.rs:7:9: 7:10
+ scope 2 {
+ debug y => _3; // in scope 2 at $DIR/const_prop_miscompile.rs:7:9: 7:10
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/const_prop_miscompile.rs:5:9: 5:14
+- _1 = (const 1_i32,); // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21
++ _1 = const (1_i32,); // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21
+ // ty::Const
+- // + ty: i32
++ // + ty: (i32,)
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
+- // + span: $DIR/const_prop_miscompile.rs:5:18: 5:19
+- // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
++ // + span: $DIR/const_prop_miscompile.rs:5:17: 5:21
++ // + literal: Const { ty: (i32,), val: Value(Scalar(0x00000001)) }
+ StorageLive(_2); // scope 1 at $DIR/const_prop_miscompile.rs:6:6: 6:14
+ _2 = &mut (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:6:6: 6:14
+ (*_2) = const 5_i32; // scope 1 at $DIR/const_prop_miscompile.rs:6:5: 6:18
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000005))
+ // mir::Constant
+ // + span: $DIR/const_prop_miscompile.rs:6:17: 6:18
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+ StorageDead(_2); // scope 1 at $DIR/const_prop_miscompile.rs:6:18: 6:19
+ StorageLive(_3); // scope 1 at $DIR/const_prop_miscompile.rs:7:9: 7:10
+ StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:7:13: 7:20
+ _4 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:7:15: 7:18
+ _3 = Eq(move _4, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:7:13: 7:25
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000005))
+ // mir::Constant
+ // + span: $DIR/const_prop_miscompile.rs:7:24: 7:25
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+ StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:7:24: 7:25
+ _0 = const (); // scope 0 at $DIR/const_prop_miscompile.rs:4:10: 8:2
+ // ty::Const
+ // + ty: ()
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/const_prop_miscompile.rs:4:10: 8:2
+ // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+ StorageDead(_3); // scope 1 at $DIR/const_prop_miscompile.rs:8:1: 8:2
+ StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:8:1: 8:2
+ return; // scope 0 at $DIR/const_prop_miscompile.rs:8:2: 8:2
+ }
+ }
+
bb0: {
StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10
_2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14
- _1 = const 123i32; // scope 1 at $DIR/copy_propagation_arg.rs:29:5: 29:12
+ _1 = const 123_i32; // scope 1 at $DIR/copy_propagation_arg.rs:29:5: 29:12
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000007b))
bb1: {
StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:16:12: 16:13
StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:16:13: 16:14
- _1 = const 5u8; // scope 0 at $DIR/copy_propagation_arg.rs:17:5: 17:10
+ _1 = const 5_u8; // scope 0 at $DIR/copy_propagation_arg.rs:17:5: 17:10
// ty::Const
// + ty: u8
// + val: Value(Scalar(0x05))
bb0: {
FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/exponential-or.rs:7:11: 7:12
- switchInt((_1.0: u32)) -> [1u32: bb2, 4u32: bb2, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:8:15: 8:16
+ switchInt((_1.0: u32)) -> [1_u32: bb2, 4_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:8:15: 8:16
}
bb1: {
- _0 = const 0u32; // scope 0 at $DIR/exponential-or.rs:9:14: 9:15
+ _0 = const 0_u32; // scope 0 at $DIR/exponential-or.rs:9:14: 9:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
bb2: {
_2 = discriminant((_1.2: std::option::Option<i32>)); // scope 0 at $DIR/exponential-or.rs:8:37: 8:48
- switchInt(move _2) -> [0isize: bb4, 1isize: bb3, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:8:37: 8:48
+ switchInt(move _2) -> [0_isize: bb4, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:8:37: 8:48
}
bb3: {
- switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1i32: bb4, 8i32: bb4, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:8:42: 8:43
+ switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1_i32: bb4, 8_i32: bb4, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:8:42: 8:43
}
bb4: {
- _5 = Le(const 6u32, (_1.3: u32)); // scope 0 at $DIR/exponential-or.rs:8:62: 8:67
+ _5 = Le(const 6_u32, (_1.3: u32)); // scope 0 at $DIR/exponential-or.rs:8:62: 8:67
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000006))
}
bb5: {
- _6 = Le((_1.3: u32), const 9u32); // scope 0 at $DIR/exponential-or.rs:8:62: 8:67
+ _6 = Le((_1.3: u32), const 9_u32); // scope 0 at $DIR/exponential-or.rs:8:62: 8:67
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000009))
}
bb6: {
- _3 = Le(const 13u32, (_1.3: u32)); // scope 0 at $DIR/exponential-or.rs:8:70: 8:77
+ _3 = Le(const 13_u32, (_1.3: u32)); // scope 0 at $DIR/exponential-or.rs:8:70: 8:77
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x0000000d))
}
bb7: {
- _4 = Le((_1.3: u32), const 16u32); // scope 0 at $DIR/exponential-or.rs:8:70: 8:77
+ _4 = Le((_1.3: u32), const 16_u32); // scope 0 at $DIR/exponential-or.rs:8:70: 8:77
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000010))
--- /dev/null
+// compile-flags: -Zmir-opt-level=0 -Zvalidate-mir
+
+// Tests that the `<fn() as Fn>` shim does not create a `Call` terminator with a `Self` callee
+// (as only `FnDef` and `FnPtr` callees are allowed in MIR).
+
+// EMIT_MIR rustc.ops-function-Fn-call.AddMovesForPackedDrops.before.mir
+fn main() {
+ call(noop as fn());
+}
+
+fn noop() {}
+
+fn call<F: Fn()>(f: F) {
+ f();
+}
--- /dev/null
+// MIR for `std::ops::Fn::call` before AddMovesForPackedDrops
+
+fn std::ops::Fn::call(_1: *const fn(), _2: Args) -> <Self as std::ops::FnOnce<Args>>::Output {
+ let mut _0: <Self as std::ops::FnOnce<Args>>::Output; // return place in scope 0 at $SRC_DIR/libcore/ops/function.rs:LL:COL
+
+ bb0: {
+ _0 = move (*_1)() -> bb1; // scope 0 at $SRC_DIR/libcore/ops/function.rs:LL:COL
+ }
+
+ bb1: {
+ return; // scope 0 at $SRC_DIR/libcore/ops/function.rs:LL:COL
+ }
+}
// MIR for `main::{{closure}}#0` 0 generator_drop
-// generator_layout = GeneratorLayout { field_tys: [std::string::String], variant_fields: [[], [], [], [_0]], storage_conflicts: BitMatrix { num_rows: 1, num_columns: 1, words: [1], marker: PhantomData } }
+/* generator_layout = GeneratorLayout {
+ field_tys: {
+ _0: std::string::String,
+ },
+ variant_fields: {
+ Unresumed(0): [],
+ Returned (1): [],
+ Panicked (2): [],
+ Suspend0 (3): [_0],
+ },
+ storage_conflicts: BitMatrix(1x1) {
+ (_0, _0),
+ },
+} */
fn main::{{closure}}#0(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6 {std::string::String, ()}]) -> () {
let mut _0: (); // return place in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
bb0: {
_9 = discriminant((*_1)); // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
- switchInt(move _9) -> [0u32: bb7, 3u32: bb11, otherwise: bb12]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+ switchInt(move _9) -> [0_u32: bb7, 3_u32: bb11, otherwise: bb12]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
}
bb1 (cleanup): {
bb0: {
StorageLive(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:13: 23:14
- _3 = Foo(const 5i32); // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
+ _3 = Foo(const 5_i32); // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000005))
// + span: $DIR/generator-storage-dead-unwind.rs:23:21: 23:22
// + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
StorageLive(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:13: 24:14
- _4 = Bar(const 6i32); // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
+ _4 = Bar(const 6_i32); // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000006))
// MIR for `main::{{closure}}#0` 0 generator_resume
-// generator_layout = GeneratorLayout { field_tys: [HasDrop], variant_fields: [[], [], [], [_0]], storage_conflicts: BitMatrix { num_rows: 1, num_columns: 1, words: [1], marker: PhantomData } }
+/* generator_layout = GeneratorLayout {
+ field_tys: {
+ _0: HasDrop,
+ },
+ variant_fields: {
+ Unresumed(0): [],
+ Returned (1): [],
+ Panicked (2): [],
+ Suspend0 (3): [_0],
+ },
+ storage_conflicts: BitMatrix(1x1) {
+ (_0, _0),
+ },
+} */
fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]>, _2: u8) -> std::ops::GeneratorState<(), ()> {
debug _x => _10; // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19
bb0: {
_11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]))); // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
- switchInt(move _11) -> [0u32: bb1, 3u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
+ switchInt(move _11) -> [0_u32: bb1, 3_u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
}
bb1: {
// + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar(<ZST>)) }
StorageLive(_2); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
_2 = _1; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
- _3 = const 1i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+ _3 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
// mir::Constant
// + span: $DIR/inline-any-operand.rs:12:7: 12:8
// + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
- _4 = const -1i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+ _4 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
// ty::Const
// + ty: i32
// + val: Value(Scalar(0xffffffff))
_2 = Box(std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
- (*_2) = const std::vec::Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ _4 = &mut (*_2); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+ ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: std::ptr::Unique::<u32> { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData::<u32> }, cap: 0usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
++ ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: std::ptr::Unique::<u32> { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
// ty::Const
- // + ty: fn() -> std::vec::Vec<u32> {std::vec::Vec::<u32>::new}
- // + val: Value(Scalar(<ZST>))
+ // + span: $SRC_DIR/liballoc/vec.rs:LL:COL
+ // + user_ty: UserType(0)
+ // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
-+ ((*_4).1: usize) = const 0usize; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
++ ((*_4).1: usize) = const 0_usize; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x00000000))
_2 = Box(std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
- (*_2) = const std::vec::Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ _4 = &mut (*_2); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+ ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: std::ptr::Unique::<u32> { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData::<u32> }, cap: 0usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
++ ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: std::ptr::Unique::<u32> { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
// ty::Const
- // + ty: fn() -> std::vec::Vec<u32> {std::vec::Vec::<u32>::new}
- // + val: Value(Scalar(<ZST>))
+ // + span: $SRC_DIR/liballoc/vec.rs:LL:COL
+ // + user_ty: UserType(0)
+ // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, size: Size { raw: 16 }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
-+ ((*_4).1: usize) = const 0usize; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
++ ((*_4).1: usize) = const 0_usize; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x0000000000000000))
bb0: {
StorageLive(_1); // scope 0 at $DIR/inline-specialization.rs:5:9: 5:10
- _1 = const <std::vec::Vec<()> as Foo>::bar() -> bb1; // scope 0 at $DIR/inline-specialization.rs:5:13: 5:38
-+ _1 = const 123u32; // scope 2 at $DIR/inline-specialization.rs:14:31: 14:34
++ _1 = const 123_u32; // scope 2 at $DIR/inline-specialization.rs:14:31: 14:34
// ty::Const
- // + ty: fn() -> u32 {<std::vec::Vec<()> as Foo>::bar}
- // + val: Value(Scalar(<ZST>))
--- /dev/null
+// Test that the initial version of Rust coverage injects count_code_region() placeholder calls,
+// at the top of each function. The placeholders are later converted into LLVM instrprof.increment
+// intrinsics, during codegen.
+
+// needs-profiler-support
+// compile-flags: -Zinstrument-coverage
+// EMIT_MIR rustc.main.InstrumentCoverage.diff
+// EMIT_MIR rustc.bar.InstrumentCoverage.diff
+fn main() {
+ loop {
+ if bar() {
+ break;
+ }
+ }
+}
+
+#[inline(never)]
+fn bar() -> bool {
+ true
+}
--- /dev/null
+- // MIR for `bar` before InstrumentCoverage
++ // MIR for `bar` after InstrumentCoverage
+
+ fn bar() -> bool {
+ let mut _0: bool; // return place in scope 0 at $DIR/instrument_coverage.rs:18:13: 18:17
++ let mut _1: (); // in scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
+
+ bb0: {
++ StorageLive(_1); // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
++ _1 = const std::intrinsics::count_code_region(const 0_u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
++ // ty::Const
++ // + ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}
++ // + val: Value(Scalar(<ZST>))
++ // mir::Constant
++ // + span: $DIR/instrument_coverage.rs:18:1: 18:1
++ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++ // ty::Const
++ // + ty: u32
++ // + val: Value(Scalar(0x00000000))
++ // mir::Constant
++ // + span: $DIR/instrument_coverage.rs:18:1: 18:1
++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
++ }
++
++ bb1 (cleanup): {
++ resume; // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
++ }
++
++ bb2: {
++ StorageDead(_1); // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9
+ _0 = const true; // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x01))
+ // mir::Constant
+ // + span: $DIR/instrument_coverage.rs:19:5: 19:9
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+ return; // scope 0 at $DIR/instrument_coverage.rs:20:2: 20:2
+ }
+ }
+
--- /dev/null
+- // MIR for `main` before InstrumentCoverage
++ // MIR for `main` after InstrumentCoverage
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
+ let mut _1: (); // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
+ let mut _2: bool; // in scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
+ let mut _3: !; // in scope 0 at $DIR/instrument_coverage.rs:11:18: 13:10
++ let mut _4: (); // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
+
+ bb0: {
+- falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
++ StorageLive(_4); // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
++ _4 = const std::intrinsics::count_code_region(const 0_u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
++ // ty::Const
++ // + ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}
++ // + val: Value(Scalar(<ZST>))
++ // mir::Constant
++ // + span: $DIR/instrument_coverage.rs:9:1: 9:1
++ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++ // ty::Const
++ // + ty: u32
++ // + val: Value(Scalar(0x00000000))
++ // mir::Constant
++ // + span: $DIR/instrument_coverage.rs:9:1: 9:1
++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
+ }
+
+ bb1: {
+ StorageLive(_2); // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
+ _2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
+ // ty::Const
+ // + ty: fn() -> bool {bar}
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/instrument_coverage.rs:11:12: 11:15
+ // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb2 (cleanup): {
+ resume; // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
+ }
+
+ bb3: {
+ FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
+ switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
+ }
+
+ bb4: {
+ falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
+ }
+
+ bb5: {
+ _1 = const (); // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
+ // ty::Const
+ // + ty: ()
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/instrument_coverage.rs:11:9: 13:10
+ // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+ StorageDead(_2); // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6
+ goto -> bb0; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
+ }
+
+ bb6: {
+ _0 = const (); // scope 0 at $DIR/instrument_coverage.rs:12:13: 12:18
+ // ty::Const
+ // + ty: ()
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/instrument_coverage.rs:12:13: 12:18
+ // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+ StorageDead(_2); // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6
+ return; // scope 0 at $DIR/instrument_coverage.rs:15:2: 15:2
++ }
++
++ bb7: {
++ StorageDead(_4); // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
++ falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
+ }
+ }
+
let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:18:19: 18:22
bb0: {
- _1 = CheckedAdd(const 1usize, const 1usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
+ _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
+ // + span: $DIR/issue-41697.rs:18:19: 18:20
+ // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) }
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
+ // + span: $DIR/issue-41697.rs:18:21: 18:22
+ // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) }
+ assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_usize, const 1_usize) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000001))
// mir::Constant
// + span: $DIR/issue-41697.rs:18:21: 18:22
// + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) }
- assert(!move (_1.1: bool), "attempt to add with overflow") -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
}
bb1 (cleanup): {
let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:18:19: 18:22
bb0: {
- _1 = CheckedAdd(const 1usize, const 1usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
+ _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x0000000000000001))
+ // mir::Constant
+ // + span: $DIR/issue-41697.rs:18:19: 18:20
+ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) }
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x0000000000000001))
+ // mir::Constant
+ // + span: $DIR/issue-41697.rs:18:21: 18:22
+ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) }
+ assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_usize, const 1_usize) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000001))
// mir::Constant
// + span: $DIR/issue-41697.rs:18:21: 18:22
// + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) }
- assert(!move (_1.1: bool), "attempt to add with overflow") -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
}
bb1 (cleanup): {
bb8: {
StorageDead(_3); // scope 1 at $DIR/issue-41888.rs:9:19: 9:20
_5 = discriminant(_1); // scope 1 at $DIR/issue-41888.rs:10:16: 10:24
- switchInt(move _5) -> [0isize: bb10, otherwise: bb9]; // scope 1 at $DIR/issue-41888.rs:10:16: 10:24
+ switchInt(move _5) -> [0_isize: bb10, otherwise: bb9]; // scope 1 at $DIR/issue-41888.rs:10:16: 10:24
}
bb9: {
bb20: {
_10 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
- switchInt(move _10) -> [0isize: bb15, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+ switchInt(move _10) -> [0_isize: bb15, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
}
bb21: {
bb22 (cleanup): {
_11 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
- switchInt(move _11) -> [0isize: bb17, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+ switchInt(move _11) -> [0_isize: bb17, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
}
bb23 (cleanup): {
}
bb7: {
- _2 = const 4i32; // scope 0 at $DIR/issue-49232.rs:9:26: 9:27
+ _2 = const 4_i32; // scope 0 at $DIR/issue-49232.rs:9:26: 9:27
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000004))
bb2: {
StorageDead(_4); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
_5 = discriminant(_3); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
- switchInt(move _5) -> [0isize: bb4, 1isize: bb6, otherwise: bb5]; // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+ switchInt(move _5) -> [0_isize: bb4, 1_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
}
bb3 (cleanup): {
--- /dev/null
+// compile-flags: -Z mir-opt-level=1
+// Regression test for #72181, this ICE requires `-Z mir-opt-level=1` flags.
+
+#![feature(never_type)]
+#![allow(unused, invalid_value)]
+
+enum Void {}
+
+// EMIT_MIR rustc.f.mir_map.0.mir
+fn f(v: Void) -> ! {
+ match v {}
+}
+
+// EMIT_MIR rustc.main.mir_map.0.mir
+fn main() {
+ let v: Void = unsafe {
+ std::mem::transmute::<(), Void>(())
+ };
+
+ f(v);
+}
--- /dev/null
+// MIR for `f` 0 mir_map
+
+fn f(_1: Void) -> ! {
+ debug v => _1; // in scope 0 at $DIR/issue-72181-1.rs:10:6: 10:7
+ let mut _0: !; // return place in scope 0 at $DIR/issue-72181-1.rs:10:18: 10:19
+ let mut _2: !; // in scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2
+ let mut _3: !; // in scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2
+ StorageLive(_3); // scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15
+ FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12
+ unreachable; // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12
+ }
+
+ bb1 (cleanup): {
+ resume; // scope 0 at $DIR/issue-72181-1.rs:10:1: 12:2
+ }
+
+ bb2: {
+ unreachable; // scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15
+ }
+
+ bb3: {
+ StorageDead(_3); // scope 0 at $DIR/issue-72181-1.rs:11:14: 11:15
+ unreachable; // scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2
+ }
+
+ bb4: {
+ StorageDead(_2); // scope 0 at $DIR/issue-72181-1.rs:12:1: 12:2
+ goto -> bb5; // scope 0 at $DIR/issue-72181-1.rs:12:2: 12:2
+ }
+
+ bb5: {
+ return; // scope 0 at $DIR/issue-72181-1.rs:12:2: 12:2
+ }
+}
--- /dev/null
+// MIR for `main` 0 mir_map
+
+| User Type Annotations
+| 0: Canonical { max_universe: U0, variables: [], value: Ty(Void) } at $DIR/issue-72181-1.rs:16:12: 16:16
+| 1: Canonical { max_universe: U0, variables: [], value: Ty(Void) } at $DIR/issue-72181-1.rs:16:12: 16:16
+|
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/issue-72181-1.rs:15:11: 15:11
+ let mut _1: !; // in scope 0 at $DIR/issue-72181-1.rs:15:11: 21:2
+ let _2: Void as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
+ let mut _3: (); // in scope 0 at $DIR/issue-72181-1.rs:17:41: 17:43
+ let _4: !; // in scope 0 at $DIR/issue-72181-1.rs:20:5: 20:9
+ let mut _5: Void; // in scope 0 at $DIR/issue-72181-1.rs:20:7: 20:8
+ scope 1 {
+ debug v => _2; // in scope 1 at $DIR/issue-72181-1.rs:16:9: 16:10
+ }
+ scope 2 {
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
+ StorageLive(_3); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
+ _3 = (); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
+ _2 = const std::intrinsics::transmute::<(), Void>(move _3) -> [return: bb2, unwind: bb1]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
+ // ty::Const
+ // + ty: unsafe extern "rust-intrinsic" fn(()) -> Void {std::intrinsics::transmute::<(), Void>}
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/issue-72181-1.rs:17:9: 17:40
+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {std::intrinsics::transmute::<(), Void>}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1 (cleanup): {
+ resume; // scope 0 at $DIR/issue-72181-1.rs:15:1: 21:2
+ }
+
+ bb2: {
+ StorageDead(_3); // scope 2 at $DIR/issue-72181-1.rs:17:43: 17:44
+ FakeRead(ForLet, _2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
+ AscribeUserType(_2, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue-72181-1.rs:16:12: 16:16
+ StorageLive(_4); // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9
+ StorageLive(_5); // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8
+ _5 = move _2; // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8
+ const f(move _5) -> bb1; // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9
+ // ty::Const
+ // + ty: fn(Void) -> ! {f}
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/issue-72181-1.rs:20:5: 20:6
+ // + literal: Const { ty: fn(Void) -> ! {f}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb3: {
+ StorageDead(_5); // scope 1 at $DIR/issue-72181-1.rs:20:8: 20:9
+ StorageDead(_4); // scope 1 at $DIR/issue-72181-1.rs:20:9: 20:10
+ StorageDead(_2); // scope 0 at $DIR/issue-72181-1.rs:21:1: 21:2
+ unreachable; // scope 0 at $DIR/issue-72181-1.rs:15:11: 21:2
+ }
+
+ bb4: {
+ goto -> bb5; // scope 0 at $DIR/issue-72181-1.rs:21:2: 21:2
+ }
+
+ bb5: {
+ return; // scope 0 at $DIR/issue-72181-1.rs:21:2: 21:2
+ }
+}
--- /dev/null
+// compile-flags: -Z mir-opt-level=1
+// Regression test for #72181, this ICE requires `-Z mir-opt-level=1` flags.
+
+use std::mem;
+
+#[derive(Copy, Clone)]
+enum Never {}
+
+union Foo {
+ a: u64,
+ b: Never
+}
+
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// EMIT_MIR rustc.foo.mir_map.0.mir
+fn foo(xs: [(Never, u32); 1]) -> u32 { xs[0].1 }
+
+// EMIT_MIR rustc.bar.mir_map.0.mir
+fn bar([(_, x)]: [(Never, u32); 1]) -> u32 { x }
+
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// EMIT_MIR rustc.main.mir_map.0.mir
+fn main() {
+ let _ = mem::size_of::<Foo>();
+
+ let f = [Foo { a: 42 }, Foo { a: 10 }];
+ let _ = unsafe { f[0].a };
+}
--- /dev/null
+// MIR for `bar` 0 mir_map
+
+fn bar(_1: [(Never, u32); 1]) -> u32 {
+ let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:19:40: 19:43
+ let _2: u32; // in scope 0 at $DIR/issue-72181.rs:19:13: 19:14
+ scope 1 {
+ debug x => _2; // in scope 1 at $DIR/issue-72181.rs:19:13: 19:14
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14
+ _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14
+ _0 = _2; // scope 1 at $DIR/issue-72181.rs:19:46: 19:47
+ StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:19:48: 19:49
+ goto -> bb2; // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
+ }
+
+ bb1 (cleanup): {
+ resume; // scope 0 at $DIR/issue-72181.rs:19:1: 19:49
+ }
+
+ bb2: {
+ return; // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
+ }
+}
--- /dev/null
+// MIR for `foo` 0 mir_map
+
+fn foo(_1: [(Never, u32); 1]) -> u32 {
+ debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:16:8: 16:10
+ let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:16:34: 16:37
+ let _2: usize; // in scope 0 at $DIR/issue-72181.rs:16:43: 16:44
+ let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+ let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:16:43: 16:44
+ _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:16:43: 16:44
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x00000000))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:16:43: 16:44
+ // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) }
+ _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+ _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+ assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+ }
+
+ bb1 (cleanup): {
+ resume; // scope 0 at $DIR/issue-72181.rs:16:1: 16:49
+ }
+
+ bb2: {
+ _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:16:40: 16:47
+ StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:16:48: 16:49
+ goto -> bb3; // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
+ }
+
+ bb3: {
+ return; // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
+ }
+}
--- /dev/null
+// MIR for `main` 0 mir_map
+
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:23:11: 23:11
+ let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+ let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:26:14: 26:27
+ let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:26:29: 26:42
+ let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:27:13: 27:30
+ let _6: usize; // in scope 0 at $DIR/issue-72181.rs:27:24: 27:25
+ let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26
+ let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26
+ scope 1 {
+ let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:26:9: 26:10
+ scope 2 {
+ debug f => _2; // in scope 2 at $DIR/issue-72181.rs:26:9: 26:10
+ scope 3 {
+ }
+ scope 4 {
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+ _1 = const std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+ // ty::Const
+ // + ty: fn() -> usize {std::mem::size_of::<Foo>}
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:24:13: 24:32
+ // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1 (cleanup): {
+ resume; // scope 0 at $DIR/issue-72181.rs:23:1: 28:2
+ }
+
+ bb2: {
+ StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:24:34: 24:35
+ StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
+ StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:26:14: 26:27
+ _3 = Foo { a: const 42_u64 }; // scope 1 at $DIR/issue-72181.rs:26:14: 26:27
+ // ty::Const
+ // + ty: u64
+ // + val: Value(Scalar(0x000000000000002a))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:26:23: 26:25
+ // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000002a)) }
+ StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:26:29: 26:42
+ _4 = Foo { a: const 10_u64 }; // scope 1 at $DIR/issue-72181.rs:26:29: 26:42
+ // ty::Const
+ // + ty: u64
+ // + val: Value(Scalar(0x000000000000000a))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:26:38: 26:40
+ // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000000a)) }
+ _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:26:13: 26:43
+ StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
+ StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
+ FakeRead(ForLet, _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
+ StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:27:13: 27:30
+ StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
+ _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x00000000))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:27:24: 27:25
+ // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) }
+ _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
+ _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
+ assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
+ }
+
+ bb3: {
+ _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:27:22: 27:28
+ StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
+ StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
+ _0 = const (); // scope 0 at $DIR/issue-72181.rs:23:11: 28:2
+ // ty::Const
+ // + ty: ()
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:23:11: 28:2
+ // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+ StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:28:1: 28:2
+ goto -> bb4; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
+ }
+
+ bb4: {
+ return; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
+ }
+}
--- /dev/null
+// MIR for `bar` 0 mir_map
+
+fn bar(_1: [(Never, u32); 1]) -> u32 {
+ let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:19:40: 19:43
+ let _2: u32; // in scope 0 at $DIR/issue-72181.rs:19:13: 19:14
+ scope 1 {
+ debug x => _2; // in scope 1 at $DIR/issue-72181.rs:19:13: 19:14
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14
+ _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14
+ _0 = _2; // scope 1 at $DIR/issue-72181.rs:19:46: 19:47
+ StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:19:48: 19:49
+ goto -> bb2; // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
+ }
+
+ bb1 (cleanup): {
+ resume; // scope 0 at $DIR/issue-72181.rs:19:1: 19:49
+ }
+
+ bb2: {
+ return; // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
+ }
+}
--- /dev/null
+// MIR for `foo` 0 mir_map
+
+fn foo(_1: [(Never, u32); 1]) -> u32 {
+ debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:16:8: 16:10
+ let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:16:34: 16:37
+ let _2: usize; // in scope 0 at $DIR/issue-72181.rs:16:43: 16:44
+ let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+ let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:16:43: 16:44
+ _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:16:43: 16:44
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x0000000000000000))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:16:43: 16:44
+ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) }
+ _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+ _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+ assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+ }
+
+ bb1 (cleanup): {
+ resume; // scope 0 at $DIR/issue-72181.rs:16:1: 16:49
+ }
+
+ bb2: {
+ _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:16:40: 16:47
+ StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:16:48: 16:49
+ goto -> bb3; // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
+ }
+
+ bb3: {
+ return; // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
+ }
+}
--- /dev/null
+// MIR for `main` 0 mir_map
+
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:23:11: 23:11
+ let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+ let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:26:14: 26:27
+ let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:26:29: 26:42
+ let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:27:13: 27:30
+ let _6: usize; // in scope 0 at $DIR/issue-72181.rs:27:24: 27:25
+ let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26
+ let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26
+ scope 1 {
+ let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:26:9: 26:10
+ scope 2 {
+ debug f => _2; // in scope 2 at $DIR/issue-72181.rs:26:9: 26:10
+ scope 3 {
+ }
+ scope 4 {
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+ _1 = const std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+ // ty::Const
+ // + ty: fn() -> usize {std::mem::size_of::<Foo>}
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:24:13: 24:32
+ // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1 (cleanup): {
+ resume; // scope 0 at $DIR/issue-72181.rs:23:1: 28:2
+ }
+
+ bb2: {
+ StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:24:34: 24:35
+ StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
+ StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:26:14: 26:27
+ _3 = Foo { a: const 42_u64 }; // scope 1 at $DIR/issue-72181.rs:26:14: 26:27
+ // ty::Const
+ // + ty: u64
+ // + val: Value(Scalar(0x000000000000002a))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:26:23: 26:25
+ // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000002a)) }
+ StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:26:29: 26:42
+ _4 = Foo { a: const 10_u64 }; // scope 1 at $DIR/issue-72181.rs:26:29: 26:42
+ // ty::Const
+ // + ty: u64
+ // + val: Value(Scalar(0x000000000000000a))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:26:38: 26:40
+ // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000000a)) }
+ _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:26:13: 26:43
+ StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
+ StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
+ FakeRead(ForLet, _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
+ StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:27:13: 27:30
+ StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
+ _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x0000000000000000))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:27:24: 27:25
+ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) }
+ _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
+ _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
+ assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
+ }
+
+ bb3: {
+ _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:27:22: 27:28
+ StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
+ StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
+ _0 = const (); // scope 0 at $DIR/issue-72181.rs:23:11: 28:2
+ // ty::Const
+ // + ty: ()
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:23:11: 28:2
+ // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+ StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:28:1: 28:2
+ goto -> bb4; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
+ }
+
+ bb4: {
+ return; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
+ }
+}
--- /dev/null
+// MIR for `bar` 0 mir_map
+
+fn bar(_1: [(Never, u32); 1]) -> u32 {
+ let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:18:40: 18:43
+ let _2: u32; // in scope 0 at $DIR/issue-72181.rs:18:13: 18:14
+ scope 1 {
+ debug x => _2; // in scope 1 at $DIR/issue-72181.rs:18:13: 18:14
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:18:13: 18:14
+ _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:18:13: 18:14
+ _0 = _2; // scope 1 at $DIR/issue-72181.rs:18:46: 18:47
+ StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:18:48: 18:49
+ goto -> bb2; // scope 0 at $DIR/issue-72181.rs:18:49: 18:49
+ }
+
+ bb1 (cleanup): {
+ resume; // scope 0 at $DIR/issue-72181.rs:18:1: 18:49
+ }
+
+ bb2: {
+ return; // scope 0 at $DIR/issue-72181.rs:18:49: 18:49
+ }
+}
--- /dev/null
+// MIR for `foo` 0 mir_map
+
+fn foo(_1: [(Never, u32); 1]) -> u32 {
+ debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:15:8: 15:10
+ let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:15:34: 15:37
+ let _2: usize; // in scope 0 at $DIR/issue-72181.rs:15:43: 15:44
+ let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:15:40: 15:45
+ let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:15:40: 15:45
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:15:43: 15:44
+ _2 = const 0usize; // scope 0 at $DIR/issue-72181.rs:15:43: 15:44
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x0000000000000000))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:15:43: 15:44
+ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) }
+ _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:15:40: 15:45
+ _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:15:40: 15:45
+ assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:15:40: 15:45
+ }
+
+ bb1 (cleanup): {
+ resume; // scope 0 at $DIR/issue-72181.rs:15:1: 15:49
+ }
+
+ bb2: {
+ _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:15:40: 15:47
+ StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:15:48: 15:49
+ goto -> bb3; // scope 0 at $DIR/issue-72181.rs:15:49: 15:49
+ }
+
+ bb3: {
+ return; // scope 0 at $DIR/issue-72181.rs:15:49: 15:49
+ }
+}
--- /dev/null
+// MIR for `main` 0 mir_map
+
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:21:11: 21:11
+ let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:22:13: 22:34
+ let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:24:14: 24:27
+ let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:24:29: 24:42
+ let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:25:13: 25:30
+ let _6: usize; // in scope 0 at $DIR/issue-72181.rs:25:24: 25:25
+ let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:25:22: 25:26
+ let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:25:22: 25:26
+ scope 1 {
+ let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:24:9: 24:10
+ scope 2 {
+ debug f => _2; // in scope 2 at $DIR/issue-72181.rs:24:9: 24:10
+ scope 3 {
+ }
+ scope 4 {
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:22:13: 22:34
+ _1 = const std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:22:13: 22:34
+ // ty::Const
+ // + ty: fn() -> usize {std::mem::size_of::<Foo>}
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:22:13: 22:32
+ // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1 (cleanup): {
+ resume; // scope 0 at $DIR/issue-72181.rs:21:1: 26:2
+ }
+
+ bb2: {
+ StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:22:34: 22:35
+ StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:24:9: 24:10
+ StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:24:14: 24:27
+ _3 = Foo { a: const 42u64 }; // scope 1 at $DIR/issue-72181.rs:24:14: 24:27
+ // ty::Const
+ // + ty: u64
+ // + val: Value(Scalar(0x000000000000002a))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:24:23: 24:25
+ // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000002a)) }
+ StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:24:29: 24:42
+ _4 = Foo { a: const 10u64 }; // scope 1 at $DIR/issue-72181.rs:24:29: 24:42
+ // ty::Const
+ // + ty: u64
+ // + val: Value(Scalar(0x000000000000000a))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:24:38: 24:40
+ // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000000a)) }
+ _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:24:13: 24:43
+ StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:24:42: 24:43
+ StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:24:42: 24:43
+ FakeRead(ForLet, _2); // scope 1 at $DIR/issue-72181.rs:24:9: 24:10
+ StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:25:13: 25:30
+ StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:25:24: 25:25
+ _6 = const 0usize; // scope 4 at $DIR/issue-72181.rs:25:24: 25:25
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x0000000000000000))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:25:24: 25:25
+ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) }
+ _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:25:22: 25:26
+ _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:25:22: 25:26
+ assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:25:22: 25:26
+ }
+
+ bb3: {
+ _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:25:22: 25:28
+ StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:25:30: 25:31
+ StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:25:30: 25:31
+ _0 = const (); // scope 0 at $DIR/issue-72181.rs:21:11: 26:2
+ // ty::Const
+ // + ty: ()
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:21:11: 26:2
+ // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+ StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:26:1: 26:2
+ goto -> bb4; // scope 0 at $DIR/issue-72181.rs:26:2: 26:2
+ }
+
+ bb4: {
+ return; // scope 0 at $DIR/issue-72181.rs:26:2: 26:2
+ }
+}
bb6: {
StorageLive(_6); // scope 0 at $DIR/loop_test.rs:14:13: 14:14
- _6 = const 1i32; // scope 0 at $DIR/loop_test.rs:14:17: 14:18
+ _6 = const 1_i32; // scope 0 at $DIR/loop_test.rs:14:17: 14:18
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
}
bb5: {
- _0 = const 1i32; // scope 1 at $DIR/match-arm-scopes.rs:16:77: 16:78
+ _0 = const 1_i32; // scope 1 at $DIR/match-arm-scopes.rs:16:77: 16:78
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
}
bb8: {
- _0 = const 3i32; // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
+ _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000003))
}
bb16: {
- _0 = const 3i32; // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
+ _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000003))
}
bb20: {
- _0 = const 2i32; // scope 2 at $DIR/match-arm-scopes.rs:17:41: 17:42
+ _0 = const 2_i32; // scope 2 at $DIR/match-arm-scopes.rs:17:41: 17:42
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000002))
}
bb8: {
- _0 = const 1i32; // scope 1 at $DIR/match-arm-scopes.rs:16:77: 16:78
+ _0 = const 1_i32; // scope 1 at $DIR/match-arm-scopes.rs:16:77: 16:78
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
}
bb12: {
- _0 = const 3i32; // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
+ _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000003))
}
bb21: {
- _0 = const 3i32; // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
+ _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000003))
}
bb25: {
- _0 = const 2i32; // scope 2 at $DIR/match-arm-scopes.rs:17:41: 17:42
+ _0 = const 2_i32; // scope 2 at $DIR/match-arm-scopes.rs:17:41: 17:42
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000002))
bb0: {
StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:15:13: 19:6
StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
- _2 = std::option::Option::<i32>::Some(const 42i32); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
+ _2 = std::option::Option::<i32>::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002a))
// + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
_3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16
- switchInt(move _3) -> [0isize: bb2, 1isize: bb3, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16
+ switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16
}
bb1 (cleanup): {
}
bb2: {
- _1 = (const 3i32, const 3i32); // scope 0 at $DIR/match_false_edges.rs:18:17: 18:23
+ _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:18:17: 18:23
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000003))
_5 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15
StorageLive(_8); // scope 2 at $DIR/match_false_edges.rs:16:35: 16:36
_8 = _5; // scope 2 at $DIR/match_false_edges.rs:16:35: 16:36
- _1 = (const 1i32, move _8); // scope 2 at $DIR/match_false_edges.rs:16:31: 16:37
+ _1 = (const 1_i32, move _8); // scope 2 at $DIR/match_false_edges.rs:16:31: 16:37
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
_9 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:17:14: 17:15
StorageLive(_10); // scope 3 at $DIR/match_false_edges.rs:17:24: 17:25
_10 = _9; // scope 3 at $DIR/match_false_edges.rs:17:24: 17:25
- _1 = (const 2i32, move _10); // scope 3 at $DIR/match_false_edges.rs:17:20: 17:26
+ _1 = (const 2_i32, move _10); // scope 3 at $DIR/match_false_edges.rs:17:20: 17:26
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000002))
bb0: {
StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:26:13: 30:6
StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
- _2 = std::option::Option::<i32>::Some(const 42i32); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
+ _2 = std::option::Option::<i32>::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002a))
// + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
_3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16
- switchInt(move _3) -> [0isize: bb2, 1isize: bb3, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16
+ switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16
}
bb1 (cleanup): {
_9 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:29:14: 29:15
StorageLive(_10); // scope 3 at $DIR/match_false_edges.rs:29:24: 29:25
_10 = _9; // scope 3 at $DIR/match_false_edges.rs:29:24: 29:25
- _1 = (const 2i32, move _10); // scope 3 at $DIR/match_false_edges.rs:29:20: 29:26
+ _1 = (const 2_i32, move _10); // scope 3 at $DIR/match_false_edges.rs:29:20: 29:26
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000002))
_5 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:27:14: 27:15
StorageLive(_8); // scope 2 at $DIR/match_false_edges.rs:27:35: 27:36
_8 = _5; // scope 2 at $DIR/match_false_edges.rs:27:35: 27:36
- _1 = (const 1i32, move _8); // scope 2 at $DIR/match_false_edges.rs:27:31: 27:37
+ _1 = (const 1_i32, move _8); // scope 2 at $DIR/match_false_edges.rs:27:31: 27:37
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
}
bb10: {
- _1 = (const 3i32, const 3i32); // scope 0 at $DIR/match_false_edges.rs:28:17: 28:23
+ _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:28:17: 28:23
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000003))
bb0: {
StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:35:13: 40:6
StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
- _2 = std::option::Option::<i32>::Some(const 1i32); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
+ _2 = std::option::Option::<i32>::Some(const 1_i32); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
// + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
_4 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17
- switchInt(move _4) -> [1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17
+ switchInt(move _4) -> [1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17
}
bb1 (cleanup): {
bb4: {
StorageLive(_14); // scope 0 at $DIR/match_false_edges.rs:39:9: 39:11
_14 = _2; // scope 0 at $DIR/match_false_edges.rs:39:9: 39:11
- _1 = const 4i32; // scope 5 at $DIR/match_false_edges.rs:39:15: 39:16
+ _1 = const 4_i32; // scope 5 at $DIR/match_false_edges.rs:39:15: 39:16
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000004))
FakeRead(ForGuardBinding, _7); // scope 0 at $DIR/match_false_edges.rs:36:27: 36:28
StorageLive(_6); // scope 0 at $DIR/match_false_edges.rs:36:14: 36:16
_6 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:36:14: 36:16
- _1 = const 1i32; // scope 2 at $DIR/match_false_edges.rs:36:32: 36:33
+ _1 = const 1_i32; // scope 2 at $DIR/match_false_edges.rs:36:32: 36:33
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
bb10: {
StorageLive(_9); // scope 0 at $DIR/match_false_edges.rs:37:9: 37:11
_9 = _2; // scope 0 at $DIR/match_false_edges.rs:37:9: 37:11
- _1 = const 2i32; // scope 3 at $DIR/match_false_edges.rs:37:15: 37:16
+ _1 = const 2_i32; // scope 3 at $DIR/match_false_edges.rs:37:15: 37:16
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000002))
FakeRead(ForGuardBinding, _11); // scope 0 at $DIR/match_false_edges.rs:38:28: 38:29
StorageLive(_10); // scope 0 at $DIR/match_false_edges.rs:38:14: 38:15
_10 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:38:14: 38:15
- _1 = const 3i32; // scope 4 at $DIR/match_false_edges.rs:38:33: 38:34
+ _1 = const 3_i32; // scope 4 at $DIR/match_false_edges.rs:38:33: 38:34
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000003))
bb0: {
StorageLive(_1); // scope 0 at $DIR/match_test.rs:7:9: 7:10
- _1 = const 3i32; // scope 0 at $DIR/match_test.rs:7:13: 7:14
+ _1 = const 3_i32; // scope 0 at $DIR/match_test.rs:7:13: 7:14
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000003))
FakeRead(ForLet, _2); // scope 1 at $DIR/match_test.rs:8:9: 8:10
StorageLive(_3); // scope 2 at $DIR/match_test.rs:12:5: 17:6
FakeRead(ForMatchedPlace, _1); // scope 2 at $DIR/match_test.rs:12:11: 12:12
- _6 = Le(const 0i32, _1); // scope 2 at $DIR/match_test.rs:13:9: 13:14
+ _6 = Le(const 0_i32, _1); // scope 2 at $DIR/match_test.rs:13:9: 13:14
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
}
bb1: {
- _7 = Lt(_1, const 10i32); // scope 2 at $DIR/match_test.rs:13:9: 13:14
+ _7 = Lt(_1, const 10_i32); // scope 2 at $DIR/match_test.rs:13:9: 13:14
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000000a))
}
bb3: {
- _3 = const 3i32; // scope 2 at $DIR/match_test.rs:16:14: 16:15
+ _3 = const 3_i32; // scope 2 at $DIR/match_test.rs:16:14: 16:15
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000003))
}
bb4: {
- _4 = Le(const 10i32, _1); // scope 2 at $DIR/match_test.rs:14:9: 14:16
+ _4 = Le(const 10_i32, _1); // scope 2 at $DIR/match_test.rs:14:9: 14:16
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000000a))
}
bb5: {
- _5 = Le(_1, const 20i32); // scope 2 at $DIR/match_test.rs:14:9: 14:16
+ _5 = Le(_1, const 20_i32); // scope 2 at $DIR/match_test.rs:14:9: 14:16
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000014))
}
bb7: {
- switchInt(_1) -> [-1i32: bb8, otherwise: bb3]; // scope 2 at $DIR/match_test.rs:15:9: 15:11
+ switchInt(_1) -> [-1_i32: bb8, otherwise: bb3]; // scope 2 at $DIR/match_test.rs:15:9: 15:11
}
bb8: {
bb10: {
StorageDead(_9); // scope 2 at $DIR/match_test.rs:13:24: 13:25
FakeRead(ForMatchGuard, _8); // scope 2 at $DIR/match_test.rs:13:18: 13:19
- _3 = const 0i32; // scope 2 at $DIR/match_test.rs:13:23: 13:24
+ _3 = const 0_i32; // scope 2 at $DIR/match_test.rs:13:23: 13:24
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
}
bb12: {
- _3 = const 1i32; // scope 2 at $DIR/match_test.rs:14:20: 14:21
+ _3 = const 1_i32; // scope 2 at $DIR/match_test.rs:14:20: 14:21
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
}
bb13: {
- _3 = const 2i32; // scope 2 at $DIR/match_test.rs:15:15: 15:16
+ _3 = const 2_i32; // scope 2 at $DIR/match_test.rs:15:15: 15:16
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000002))
bb0: {
_2 = discriminant(_1); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:9: 9:16
- switchInt(move _2) -> [0isize: bb2, 1isize: bb4, otherwise: bb3]; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:9: 9:16
+ switchInt(move _2) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:9: 9:16
}
bb1 (cleanup): {
bb0: {
- StorageLive(_2); // scope 0 at $DIR/nrvo-simple.rs:3:9: 3:16
-- _2 = [const 0u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28
-+ _0 = [const 0u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28
+- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28
++ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28
// ty::Const
// + ty: u8
// + val: Value(Scalar(0x00))
StorageLive(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:9: 6:14
StorageLive(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:24: 6:42
StorageLive(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41
- _3 = Droppy(const 0usize); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41
+ _3 = Droppy(const 0_usize); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000000))
StorageDead(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:42: 6:43
StorageLive(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:11: 7:29
StorageLive(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28
- _5 = Droppy(const 0usize); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28
+ _5 = Droppy(const 0_usize); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000000))
StorageLive(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:9: 6:14
StorageLive(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:24: 6:42
StorageLive(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41
- _3 = Droppy(const 0usize); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41
+ _3 = Droppy(const 0_usize); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000000))
StorageDead(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:42: 6:43
StorageLive(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:11: 7:29
StorageLive(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28
- _5 = Droppy(const 0usize); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28
+ _5 = Droppy(const 0_usize); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000000))
- FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12
+ nop; // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12
_3 = discriminant(_1); // scope 0 at $DIR/remove_fake_borrows.rs:8:9: 8:16
- switchInt(move _3) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:8:9: 8:16
+ switchInt(move _3) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:8:9: 8:16
}
bb1: {
- _0 = const 1i32; // scope 0 at $DIR/remove_fake_borrows.rs:9:14: 9:15
+ _0 = const 1_i32; // scope 0 at $DIR/remove_fake_borrows.rs:9:14: 9:15
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
}
bb2: {
- switchInt((*(*((_1 as Some).0: &&i32)))) -> [0i32: bb3, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:8:14: 8:15
+ switchInt((*(*((_1 as Some).0: &&i32)))) -> [0_i32: bb3, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:8:14: 8:15
}
bb3: {
+ nop; // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21
+ nop; // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21
+ nop; // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21
- _0 = const 0i32; // scope 0 at $DIR/remove_fake_borrows.rs:8:25: 8:26
+ _0 = const 0_i32; // scope 0 at $DIR/remove_fake_borrows.rs:8:25: 8:26
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
bb0: {
StorageLive(_1); // scope 0 at $DIR/retag.rs:30:9: 30:14
- _1 = const 0i32; // scope 0 at $DIR/retag.rs:30:17: 30:18
+ _1 = const 0_i32; // scope 0 at $DIR/retag.rs:30:17: 30:18
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
StorageLive(_3); // scope 1 at $DIR/retag.rs:32:13: 32:14
StorageLive(_4); // scope 1 at $DIR/retag.rs:32:17: 32:24
StorageLive(_5); // scope 1 at $DIR/retag.rs:32:17: 32:24
- _5 = Test(const 0i32); // scope 1 at $DIR/retag.rs:32:17: 32:24
+ _5 = Test(const 0_i32); // scope 1 at $DIR/retag.rs:32:17: 32:24
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
StorageLive(_19); // scope 7 at $DIR/retag.rs:47:5: 47:24
StorageLive(_20); // scope 7 at $DIR/retag.rs:47:5: 47:12
StorageLive(_21); // scope 7 at $DIR/retag.rs:47:5: 47:12
- _21 = Test(const 0i32); // scope 7 at $DIR/retag.rs:47:5: 47:12
+ _21 = Test(const 0_i32); // scope 7 at $DIR/retag.rs:47:5: 47:12
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
}
bb3: {
- _0 = const 20usize; // scope 0 at $DIR/simple-match.rs:8:14: 8:16
+ _0 = const 20_usize; // scope 0 at $DIR/simple-match.rs:8:14: 8:16
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000014))
}
bb4: {
- _0 = const 10usize; // scope 0 at $DIR/simple-match.rs:7:17: 7:19
+ _0 = const 10_usize; // scope 0 at $DIR/simple-match.rs:7:17: 7:19
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000a))
}
bb3: {
- _0 = const 20usize; // scope 0 at $DIR/simple-match.rs:8:14: 8:16
+ _0 = const 20_usize; // scope 0 at $DIR/simple-match.rs:8:14: 8:16
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000014))
}
bb4: {
- _0 = const 10usize; // scope 0 at $DIR/simple-match.rs:7:17: 7:19
+ _0 = const 10_usize; // scope 0 at $DIR/simple-match.rs:7:17: 7:19
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x000000000000000a))
bb0: {
StorageLive(_1); // scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
- ((_1 as Foo).0: u8) = const 0u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
+ ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
// ty::Const
// + ty: u8
// + val: Value(Scalar(0x00))
// + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
discriminant(_1) = 0; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
StorageLive(_2); // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
- _3 = const 0isize; // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+ _3 = const 0_isize; // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
// ty::Const
// + ty: isize
// + val: Value(Scalar(0x00000000))
}
bb1: {
- ((_2 as Foo).0: u8) = const 0u8; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+ _2 = const Dst::Foo(0_u8); // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
// ty::Const
- // + ty: u8
+ // + ty: Dst
// + val: Value(Scalar(0x00))
// mir::Constant
- // + span: $DIR/simplify-arm-identity.rs:21:30: 21:31
- // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
- discriminant(_2) = 0; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+ // + span: $DIR/simplify-arm-identity.rs:21:21: 21:32
+ // + literal: Const { ty: Dst, val: Value(Scalar(0x00)) }
goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
- ((_1 as Foo).0: u8) = const 0u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
+ ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
// ty::Const
// + ty: u8
// + val: Value(Scalar(0x00))
// + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
discriminant(_1) = 0; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
StorageLive(_2); // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
- _3 = const 0isize; // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+ _3 = const 0_isize; // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
// ty::Const
// + ty: isize
// + val: Value(Scalar(0x0000000000000000))
}
bb1: {
- ((_2 as Foo).0: u8) = const 0u8; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+ _2 = const Dst::Foo(0_u8); // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
// ty::Const
- // + ty: u8
+ // + ty: Dst
// + val: Value(Scalar(0x00))
// mir::Constant
- // + span: $DIR/simplify-arm-identity.rs:21:30: 21:31
- // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
- discriminant(_2) = 0; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+ // + span: $DIR/simplify-arm-identity.rs:21:21: 21:32
+ // + literal: Const { ty: Dst, val: Value(Scalar(0x00)) }
goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
}
}
bb1: {
- ((_2 as Foo).0: u8) = const 0u8; // scope 1 at $DIR/simplify-arm-identity.rs:20:21: 20:32
+ _2 = const Dst::Foo(0u8); // bb1[0]: scope 1 at $DIR/simplify-arm-identity.rs:20:21: 20:32
// ty::Const
- // + ty: u8
+ // + ty: Dst
// + val: Value(Scalar(0x00))
// mir::Constant
- // + span: $DIR/simplify-arm-identity.rs:20:30: 20:31
- // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
- discriminant(_2) = 0; // scope 1 at $DIR/simplify-arm-identity.rs:20:21: 20:32
- goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:18:18: 21:6
+ // + span: $DIR/simplify-arm-identity.rs:20:21: 20:32
+ // + literal: Const { ty: Dst, val: Value(Scalar(0x00)) }
+ goto -> bb4; // bb1[1]: scope 1 at $DIR/simplify-arm-identity.rs:18:18: 21:6
}
bb2: {
bb0: {
_2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
- switchInt(move _2) -> [0isize: bb1, 1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+ switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
}
bb1: {
bb0: {
_2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
- switchInt(move _2) -> [0isize: bb1, 1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+ switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
}
bb1: {
bb0: {
_2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
- switchInt(move _2) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+ switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
}
bb1: {
bb0: {
_2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
- switchInt(move _2) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+ switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
}
bb1: {
bb1: {
StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
_5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
- switchInt(move _5) -> [0isize: bb2, 1isize: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+ switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
}
bb2: {
bb1: {
StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
_5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
- switchInt(move _5) -> [0isize: bb2, 1isize: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+ switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
}
bb2: {
StorageDead(_3); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:68: 4:69
StorageDead(_2); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:68: 4:69
_5 = discriminant((_1.0: std::option::Option<u8>)); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20
- switchInt(move _5) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20
+ switchInt(move _5) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20
}
bb1: {
bb2: {
_4 = discriminant((_1.1: std::option::Option<T>)); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26
- switchInt(move _4) -> [0isize: bb3, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26
+ switchInt(move _4) -> [0_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26
}
bb3: {
StorageLive(_7); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
StorageLive(_8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13
_8 = _6; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13
- _7 = Gt(move _8, const 42u8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
+ _7 = Gt(move _8, const 42_u8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
// ty::Const
// + ty: u8
// + val: Value(Scalar(0x2a))
- StorageLive(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34
- StorageLive(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30
- StorageLive(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
-- _11 = const Temp { x: 40u8 }; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
+- _11 = const Temp { x: 40_u8 }; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
+ StorageDead(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:22: 14:23
+ StorageLive(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
-+ _2 = const use_u8(const 42u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
++ _2 = const use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
// ty::Const
- // + ty: Temp
- // + val: Value(Scalar(0x28))
- // mir::Constant
- // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
- // + literal: Const { ty: Temp, val: Value(Scalar(0x28)) }
-- _10 = const 40u8; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30
+- _10 = const 40_u8; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30
- // ty::Const
- // + ty: u8
- // + val: Value(Scalar(0x28))
- // mir::Constant
- // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30
- // + literal: Const { ty: u8, val: Value(Scalar(0x28)) }
-- _9 = const 42u8; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34
+- _9 = const 42_u8; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34
- // ty::Const
- // + ty: u8
- // + val: Value(Scalar(0x2a))
- // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34
- // + literal: Const { ty: u8, val: Value(Scalar(0x2a)) }
- StorageDead(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:33: 16:34
-- _8 = const use_u8(const 42u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
+- _8 = const use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
- // ty::Const
// + ty: fn(u8) {use_u8}
// + val: Value(Scalar(<ZST>))
map(None);
}
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR rustc.map.SimplifyLocals.diff
--- /dev/null
+- // MIR for `map` before SimplifyLocals
++ // MIR for `map` after SimplifyLocals
+
+ fn map(_1: std::option::Option<std::boxed::Box<()>>) -> std::option::Option<std::boxed::Box<()>> {
+ debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9
+ let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46
+ let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+ let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
+- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26
+- let mut _5: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+ scope 1 {
+ debug x => _3; // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
+ }
+
+ bb0: {
+ _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+ switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+ }
+
+ bb1: {
+ _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27
+ goto -> bb3; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:2:5: 5:6
+ }
+
+ bb2: {
+ _0 = const std::option::Option::<std::boxed::Box<()>>::None; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
+ // ty::Const
+ // + ty: std::option::Option<std::boxed::Box<()>>
+ // + val: Value(Scalar(0x00000000))
+ // mir::Constant
+ // + span: $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
+ // + literal: Const { ty: std::option::Option<std::boxed::Box<()>>, val: Value(Scalar(0x00000000)) }
+ goto -> bb3; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:2:5: 5:6
+ }
+
+ bb3: {
+- _5 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+ return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2
+ }
+ }
+
--- /dev/null
+- // MIR for `map` before SimplifyLocals
++ // MIR for `map` after SimplifyLocals
+
+ fn map(_1: std::option::Option<std::boxed::Box<()>>) -> std::option::Option<std::boxed::Box<()>> {
+ debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9
+ let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46
+ let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+ let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
+- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26
+- let mut _5: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+ scope 1 {
+ debug x => _3; // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
+ }
+
+ bb0: {
+ _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+ switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+ }
+
+ bb1: {
+ _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27
+ goto -> bb3; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:2:5: 5:6
+ }
+
+ bb2: {
+ _0 = const std::option::Option::<std::boxed::Box<()>>::None; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
+ // ty::Const
+ // + ty: std::option::Option<std::boxed::Box<()>>
+ // + val: Value(Scalar(0x0000000000000000))
+ // mir::Constant
+ // + span: $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
+ // + literal: Const { ty: std::option::Option<std::boxed::Box<()>>, val: Value(Scalar(0x0000000000000000)) }
+ goto -> bb3; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:2:5: 5:6
+ }
+
+ bb3: {
+- _5 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+ return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `map` before SimplifyLocals
-+ // MIR for `map` after SimplifyLocals
-
- fn map(_1: std::option::Option<std::boxed::Box<()>>) -> std::option::Option<std::boxed::Box<()>> {
- debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9
- let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46
- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
-- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26
-- let mut _5: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
-- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
- scope 1 {
- debug x => _3; // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
- }
-
- bb0: {
- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
- switchInt(move _2) -> [0isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
- }
-
- bb1: {
- _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27
- goto -> bb3; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:2:5: 5:6
- }
-
- bb2: {
- discriminant(_0) = 0; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
- goto -> bb3; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:2:5: 5:6
- }
-
- bb3: {
-- _5 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
- return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2
- }
- }
-
_3 = move _4; // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
_5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
- switchInt(move _5) -> [0isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+ switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
}
bb1: {
bb0: {
_3 = discriminant(((*_1).1: std::option::Option<std::ptr::NonNull<Node>>)); // scope 0 at $DIR/simplify_try_if_let.rs:22:13: 22:17
- switchInt(move _3) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try_if_let.rs:22:13: 22:17
+ switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try_if_let.rs:22:13: 22:17
}
bb1: {
bb4: {
StorageDead(_6); // scope 1 at $DIR/simplify_try_if_let.rs:26:59: 26:60
_7 = discriminant(_5); // scope 1 at $DIR/simplify_try_if_let.rs:26:24: 26:40
- switchInt(move _7) -> [1isize: bb6, otherwise: bb5]; // scope 1 at $DIR/simplify_try_if_let.rs:26:24: 26:40
+ switchInt(move _7) -> [1_isize: bb6, otherwise: bb5]; // scope 1 at $DIR/simplify_try_if_let.rs:26:24: 26:40
}
bb5: {
bb3 (cleanup): {
_5 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
- _4 = Add(move _4, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000001))
bb5: {
_7 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
- _4 = Add(move _4, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000001))
}
bb7: {
- _4 = const 0usize; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ _4 = const 0_usize; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000000))
bb9 (cleanup): {
_11 = _9; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
- _9 = Offset(move _9, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000001))
bb11: {
_13 = _9; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
- _9 = Offset(move _9, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x00000001))
bb15: {
_2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
_3 = Len((*_1)); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
- switchInt(move _2) -> [0usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
}
}
bb3 (cleanup): {
_5 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
- _4 = Add(move _4, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000001))
bb5: {
_7 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
- _4 = Add(move _4, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000001))
}
bb7: {
- _4 = const 0usize; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ _4 = const 0_usize; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000000))
bb9 (cleanup): {
_11 = _9; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
- _9 = Offset(move _9, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000001))
bb11: {
_13 = _9; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
- _9 = Offset(move _9, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
// ty::Const
// + ty: usize
// + val: Value(Scalar(0x0000000000000001))
bb15: {
_2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
_3 = Len((*_1)); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
- switchInt(move _2) -> [0usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
}
}
StorageLive(_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6
StorageLive(_6); // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:12: 22:6
StorageLive(_7); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:9: 8:15
- _7 = (const 0u32, const 1u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:9: 8:15
+ _7 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:9: 8:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:8:13: 8:14
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
StorageLive(_8); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:17: 8:23
- _8 = (const 0u32, const 2u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:17: 8:23
+ _8 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:17: 8:23
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:8:21: 8:22
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
StorageLive(_9); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:25: 8:31
- _9 = (const 0u32, const 3u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:25: 8:31
+ _9 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:25: 8:31
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:8:29: 8:30
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_10); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:9: 9:15
- _10 = (const 0u32, const 1u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:9: 9:15
+ _10 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:9: 9:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:9:13: 9:14
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
StorageLive(_11); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:17: 9:23
- _11 = (const 0u32, const 2u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:17: 9:23
+ _11 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:17: 9:23
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:9:21: 9:22
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
StorageLive(_12); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:25: 9:31
- _12 = (const 0u32, const 3u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:25: 9:31
+ _12 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:25: 9:31
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:9:29: 9:30
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_13); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:9: 10:15
- _13 = (const 0u32, const 1u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:9: 10:15
+ _13 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:9: 10:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:10:13: 10:14
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
StorageLive(_14); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:17: 10:23
- _14 = (const 0u32, const 2u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:17: 10:23
+ _14 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:17: 10:23
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:10:21: 10:22
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
StorageLive(_15); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:25: 10:31
- _15 = (const 0u32, const 3u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:25: 10:31
+ _15 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:25: 10:31
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:10:29: 10:30
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_16); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:9: 11:15
- _16 = (const 0u32, const 1u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:9: 11:15
+ _16 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:9: 11:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:11:13: 11:14
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
StorageLive(_17); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:17: 11:23
- _17 = (const 0u32, const 2u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:17: 11:23
+ _17 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:17: 11:23
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:11:21: 11:22
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
StorageLive(_18); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:25: 11:31
- _18 = (const 0u32, const 3u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:25: 11:31
+ _18 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:25: 11:31
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:11:29: 11:30
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_19); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:9: 12:15
- _19 = (const 0u32, const 1u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:9: 12:15
+ _19 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:9: 12:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:12:13: 12:14
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
StorageLive(_20); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:17: 12:23
- _20 = (const 0u32, const 2u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:17: 12:23
+ _20 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:17: 12:23
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:12:21: 12:22
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
StorageLive(_21); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:25: 12:31
- _21 = (const 0u32, const 3u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:25: 12:31
+ _21 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:25: 12:31
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:12:29: 12:30
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_22); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:9: 13:15
- _22 = (const 0u32, const 1u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:9: 13:15
+ _22 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:9: 13:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:13:13: 13:14
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
StorageLive(_23); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:17: 13:23
- _23 = (const 0u32, const 2u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:17: 13:23
+ _23 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:17: 13:23
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:13:21: 13:22
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
StorageLive(_24); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:25: 13:31
- _24 = (const 0u32, const 3u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:25: 13:31
+ _24 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:25: 13:31
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:13:29: 13:30
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_25); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:9: 14:15
- _25 = (const 0u32, const 1u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:9: 14:15
+ _25 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:9: 14:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:14:13: 14:14
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
StorageLive(_26); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:17: 14:23
- _26 = (const 0u32, const 2u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:17: 14:23
+ _26 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:17: 14:23
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:14:21: 14:22
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
StorageLive(_27); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:25: 14:31
- _27 = (const 0u32, const 3u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:25: 14:31
+ _27 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:25: 14:31
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:14:29: 14:30
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_28); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:9: 15:15
- _28 = (const 0u32, const 1u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:9: 15:15
+ _28 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:9: 15:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:15:13: 15:14
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
StorageLive(_29); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:17: 15:23
- _29 = (const 0u32, const 2u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:17: 15:23
+ _29 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:17: 15:23
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:15:21: 15:22
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
StorageLive(_30); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:25: 15:31
- _30 = (const 0u32, const 3u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:25: 15:31
+ _30 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:25: 15:31
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:15:29: 15:30
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_31); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:9: 16:15
- _31 = (const 0u32, const 1u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:9: 16:15
+ _31 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:9: 16:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:16:13: 16:14
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
StorageLive(_32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:17: 16:23
- _32 = (const 0u32, const 2u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:17: 16:23
+ _32 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:17: 16:23
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:16:21: 16:22
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
StorageLive(_33); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:25: 16:31
- _33 = (const 0u32, const 3u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:25: 16:31
+ _33 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:25: 16:31
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:16:29: 16:30
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_34); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:9: 17:15
- _34 = (const 0u32, const 1u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:9: 17:15
+ _34 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:9: 17:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:17:13: 17:14
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
StorageLive(_35); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:17: 17:23
- _35 = (const 0u32, const 2u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:17: 17:23
+ _35 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:17: 17:23
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:17:21: 17:22
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
StorageLive(_36); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:25: 17:31
- _36 = (const 0u32, const 3u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:25: 17:31
+ _36 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:25: 17:31
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:17:29: 17:30
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_37); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:9: 18:15
- _37 = (const 0u32, const 1u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:9: 18:15
+ _37 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:9: 18:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:18:13: 18:14
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
StorageLive(_38); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:17: 18:23
- _38 = (const 0u32, const 2u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:17: 18:23
+ _38 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:17: 18:23
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:18:21: 18:22
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
StorageLive(_39); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:25: 18:31
- _39 = (const 0u32, const 3u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:25: 18:31
+ _39 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:25: 18:31
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:18:29: 18:30
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_40); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:9: 19:15
- _40 = (const 0u32, const 1u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:9: 19:15
+ _40 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:9: 19:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:19:13: 19:14
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
StorageLive(_41); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:17: 19:23
- _41 = (const 0u32, const 2u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:17: 19:23
+ _41 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:17: 19:23
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:19:21: 19:22
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
StorageLive(_42); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:25: 19:31
- _42 = (const 0u32, const 3u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:25: 19:31
+ _42 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:25: 19:31
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:19:29: 19:30
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_43); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:9: 20:15
- _43 = (const 0u32, const 1u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:9: 20:15
+ _43 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:9: 20:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:20:13: 20:14
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
StorageLive(_44); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:17: 20:23
- _44 = (const 0u32, const 2u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:17: 20:23
+ _44 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:17: 20:23
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:20:21: 20:22
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
StorageLive(_45); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:25: 20:31
- _45 = (const 0u32, const 3u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:25: 20:31
+ _45 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:25: 20:31
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:20:29: 20:30
// + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
StorageLive(_46); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:9: 21:15
- _46 = (const 0u32, const 1u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:9: 21:15
+ _46 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:9: 21:15
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:21:13: 21:14
// + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
StorageLive(_47); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:17: 21:23
- _47 = (const 0u32, const 2u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:17: 21:23
+ _47 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:17: 21:23
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
// + span: $DIR/storage_live_dead_in_statics.rs:21:21: 21:22
// + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
StorageLive(_48); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:25: 21:31
- _48 = (const 0u32, const 3u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:25: 21:31
+ _48 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:25: 21:31
// ty::Const
// + ty: u32
// + val: Value(Scalar(0x00000000))
bb0: {
StorageLive(_1); // scope 0 at $DIR/storage_ranges.rs:4:9: 4:10
- _1 = const 0i32; // scope 0 at $DIR/storage_ranges.rs:4:13: 4:14
+ _1 = const 0_i32; // scope 0 at $DIR/storage_ranges.rs:4:13: 4:14
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
StorageDead(_3); // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6
StorageDead(_2); // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6
StorageLive(_6); // scope 1 at $DIR/storage_ranges.rs:8:9: 8:10
- _6 = const 1i32; // scope 1 at $DIR/storage_ranges.rs:8:13: 8:14
+ _6 = const 1_i32; // scope 1 at $DIR/storage_ranges.rs:8:13: 8:14
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
_1 = &(*_2); // scope 1 at $DIR/tls-access.rs:8:17: 8:21
StorageLive(_3); // scope 2 at $DIR/tls-access.rs:9:9: 9:12
_3 = &/*tls*/ mut FOO; // scope 2 at $DIR/tls-access.rs:9:9: 9:12
- (*_3) = const 42u8; // scope 2 at $DIR/tls-access.rs:9:9: 9:17
+ (*_3) = const 42_u8; // scope 2 at $DIR/tls-access.rs:9:9: 9:17
// ty::Const
// + ty: u8
// + val: Value(Scalar(0x2a))
StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
StorageLive(_3); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
_3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
- (*_3) = const 1i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
+ (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
_5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
- (*_5) = const 2i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
+ (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000002))
StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
StorageLive(_3); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
_3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
- (*_3) = const 1i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
+ (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
_5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
- (*_5) = const 2i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
+ (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000002))
StorageLive(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
_7 = Test2::D; // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
_8 = discriminant(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
- switchInt(move _8) -> [4isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
+ switchInt(move _8) -> [4_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
}
bb1: {
StorageLive(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
_2 = Test1::C; // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
_3 = discriminant(_2); // scope 0 at $DIR/uninhabited_enum_branching.rs:21:9: 21:20
-- switchInt(move _3) -> [0isize: bb2, 1isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:21:9: 21:20
+- switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:21:9: 21:20
+ switchInt(move _3) -> bb1; // scope 0 at $DIR/uninhabited_enum_branching.rs:21:9: 21:20
}
StorageLive(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
_7 = Test2::D; // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
_8 = discriminant(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
- switchInt(move _8) -> [4isize: bb6, otherwise: bb5]; // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
+ switchInt(move _8) -> [4_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
}
bb5: {
bb1: {
_2 = discriminant(_1); // scope 0 at $DIR/unreachable.rs:9:12: 9:20
-- switchInt(move _2) -> [1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/unreachable.rs:9:12: 9:20
+- switchInt(move _2) -> [1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/unreachable.rs:9:12: 9:20
+ goto -> bb2; // scope 0 at $DIR/unreachable.rs:9:12: 9:20
}
- }
-
- bb4: {
-- _4 = const 42i32; // scope 2 at $DIR/unreachable.rs:15:13: 15:20
+- _4 = const 42_i32; // scope 2 at $DIR/unreachable.rs:15:13: 15:20
- // ty::Const
- // + ty: i32
- // + val: Value(Scalar(0x0000002a))
- }
-
- bb5: {
-- _4 = const 21i32; // scope 2 at $DIR/unreachable.rs:13:13: 13:20
+- _4 = const 21_i32; // scope 2 at $DIR/unreachable.rs:13:13: 13:20
- // ty::Const
- // + ty: i32
- // + val: Value(Scalar(0x00000015))
bb1: {
_2 = discriminant(_1); // scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
- switchInt(move _2) -> [1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
+ switchInt(move _2) -> [1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
}
bb2: {
}
bb4: {
- _4 = const 42i32; // scope 2 at $DIR/unreachable_asm.rs:17:13: 17:20
+ _4 = const 42_i32; // scope 2 at $DIR/unreachable_asm.rs:17:13: 17:20
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002a))
}
bb5: {
- _4 = const 21i32; // scope 2 at $DIR/unreachable_asm.rs:15:13: 15:20
+ _4 = const 21_i32; // scope 2 at $DIR/unreachable_asm.rs:15:13: 15:20
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000015))
bb1: {
_2 = discriminant(_1); // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
- switchInt(move _2) -> [1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
+ switchInt(move _2) -> [1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
}
bb2: {
// + span: $DIR/unreachable_asm_2.rs:20:13: 20:41
// + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
StorageDead(_8); // scope 2 at $DIR/unreachable_asm_2.rs:20:40: 20:41
- _4 = const 42i32; // scope 2 at $DIR/unreachable_asm_2.rs:21:13: 21:20
+ _4 = const 42_i32; // scope 2 at $DIR/unreachable_asm_2.rs:21:13: 21:20
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002a))
// + span: $DIR/unreachable_asm_2.rs:16:13: 16:41
// + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
StorageDead(_7); // scope 2 at $DIR/unreachable_asm_2.rs:16:40: 16:41
- _4 = const 21i32; // scope 2 at $DIR/unreachable_asm_2.rs:17:13: 17:20
+ _4 = const 21_i32; // scope 2 at $DIR/unreachable_asm_2.rs:17:13: 17:20
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000015))
bb1: {
_3 = discriminant(_2); // scope 1 at $DIR/unreachable_diverging.rs:14:12: 14:22
- switchInt(move _3) -> [1isize: bb3, otherwise: bb2]; // scope 1 at $DIR/unreachable_diverging.rs:14:12: 14:22
+ switchInt(move _3) -> [1_isize: bb3, otherwise: bb2]; // scope 1 at $DIR/unreachable_diverging.rs:14:12: 14:22
}
bb2: {
let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
bb0: {
- _0 = const 5isize; // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
+ _0 = const 5_isize; // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
// ty::Const
// + ty: isize
// + val: Value(Scalar(0x00000005))
let mut _0: i32; // return place in scope 0 at $DIR/unusual-item-types.rs:10:32: 10:35
bb0: {
- _0 = const 2i32; // scope 0 at $DIR/unusual-item-types.rs:10:38: 10:39
+ _0 = const 2_i32; // scope 0 at $DIR/unusual-item-types.rs:10:38: 10:39
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000002))
let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
bb0: {
- _0 = const 5isize; // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
+ _0 = const 5_isize; // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
// ty::Const
// + ty: isize
// + val: Value(Scalar(0x0000000000000005))
let mut _0: i32; // return place in scope 0 at $DIR/unusual-item-types.rs:10:32: 10:35
bb0: {
- _0 = const 2i32; // scope 0 at $DIR/unusual-item-types.rs:10:38: 10:39
+ _0 = const 2_i32; // scope 0 at $DIR/unusual-item-types.rs:10:38: 10:39
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000002))
asm!("{0}", inout(reg) b);
asm!("{0} {1}", out(reg) _, inlateout(reg) b => _);
asm!("", out("al") _, lateout("rbx") _);
+ asm!("inst1\ninst2");
+ asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b);
+ asm!("inst2 {1}, 24\ninst1 {0}, 42", in(reg) a, out(reg) b);
+ asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b);
+ asm!("inst1\ninst2");
+ asm!("inst1\ninst2");
+ asm!("inst1\n\tinst2");
+ asm!("inst1\ninst2\ninst3\ninst4");
}
}
asm!("{name}", name = inout(reg) b);
asm!("{} {}", out(reg) _, inlateout(reg) b => _);
asm!("", out("al") _, lateout("rbx") _);
+ asm!("inst1", "inst2");
+ asm!("inst1 {}, 42", "inst2 {}, 24", in(reg) a, out(reg) b);
+ asm!("inst2 {1}, 24", "inst1 {0}, 42", in(reg) a, out(reg) b);
+ asm!("inst1 {}, 42", "inst2 {name}, 24", in(reg) a, name = out(reg) b);
+ asm!("inst1
+inst2");
+ asm!("inst1\ninst2");
+ asm!("inst1\n\tinst2");
+ asm!("inst1\ninst2", "inst3\ninst4");
}
}
# needs-sanitizer-support
-# only-x86_64
+# needs-sanitizer-address
# only-linux
-include ../tools.mk
# needs-sanitizer-support
-# only-x86_64
+# needs-sanitizer-address
# only-linux
-include ../tools.mk
# needs-sanitizer-support
-# only-x86_64
+# needs-sanitizer-address
# only-linux
-include ../tools.mk
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+all:
+ EXISTING_ENV=1 EXISTING_OPT_ENV=1 $(RUSTC) --emit dep-info main.rs
+ $(CGREP) "# env-dep:EXISTING_ENV=1" < $(TMPDIR)/main.d
+ $(CGREP) "# env-dep:EXISTING_OPT_ENV=1" < $(TMPDIR)/main.d
+ $(CGREP) "# env-dep:NONEXISTENT_OPT_ENV" < $(TMPDIR)/main.d
+ $(CGREP) "# env-dep:ESCAPE\nESCAPE\\" < $(TMPDIR)/main.d
--- /dev/null
+fn main() {
+ env!("EXISTING_ENV");
+ option_env!("EXISTING_OPT_ENV");
+ option_env!("NONEXISTENT_OPT_ENV");
+ option_env!("ESCAPE\nESCAPE\\");
+}
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+# only-x86_64-unknown-linux-musl
+
+# How to manually run this
+# $ ./x.py test --target x86_64-unknown-linux-musl src/test/run-make/static-pie
+
+all:
+ $(RUSTC) --target $(TARGET) -C target-feature=+crt-static test-aslr.rs
+ # Check that no dynamic interpreter is set
+ ! readelf -l $(call RUN_BINFILE,test-aslr) | $(CGREP) INTERP
+ # Check that we have a dynamic executable
+ readelf -l $(call RUN_BINFILE,test-aslr) | $(CGREP) DYNAMIC
+ # Check for address space layout randomization
+ $(call RUN,test-aslr) --test-aslr
--- /dev/null
+const NUM_RUNS: usize = 10;
+
+fn run_self(exe: &str) -> usize {
+ use std::process::Command;
+ let mut set = std::collections::HashSet::new();
+
+ let mut cmd = Command::new(exe);
+ cmd.arg("--report");
+ (0..NUM_RUNS).for_each(|_| {
+ set.insert(cmd.output().expect("failed to execute process").stdout);
+ });
+ set.len()
+}
+
+fn main() {
+ let mut args = std::env::args();
+ let arg0 = args.next().unwrap();
+ match args.next() {
+ Some(s) if s.eq("--report") => {
+ println!("main = {:#?}", &main as *const _);
+ }
+ Some(s) if s.eq("--test-no-aslr") => {
+ let cnt = run_self(&arg0);
+ if cnt != 1 {
+ eprintln!("FAIL: {} most likely ASLR", arg0);
+ std::process::exit(1);
+ }
+ println!("PASS: {} does no ASLR", arg0);
+ }
+ Some(s) if s.eq("--test-aslr") => {
+ let cnt = run_self(&arg0);
+ if cnt != NUM_RUNS {
+ eprintln!("FAIL: {} most likely no ASLR", arg0);
+ std::process::exit(1);
+ }
+ println!("PASS: {} does ASLR", arg0);
+ }
+ Some(_) | None => {
+ println!("Usage: {} --test-no-aslr | --test-aslr", arg0);
+ std::process::exit(1);
+ }
+ }
+}
--- /dev/null
+// exact-check
+
+const QUERY = 'true';
+
+const FILTER_CRATE = 'some_other_crate';
+
+const EXPECTED = {
+ 'others': [],
+};
--- /dev/null
+#![feature(doc_alias)]
+
+#[doc(alias = "true")]
+pub struct Foo;
--- /dev/null
+// exact-check
+
+const QUERY = 'true';
+
+const FILTER_CRATE = 'doc_alias_filter';
+
+const EXPECTED = {
+ 'others': [
+ {
+ 'path': 'doc_alias_filter',
+ 'name': 'Foo',
+ 'alias': 'true',
+ 'href': '../doc_alias_filter/struct.Foo.html',
+ 'is_alias': true
+ },
+ ],
+};
--- /dev/null
+#![feature(doc_alias)]
+
+#[doc(alias = "true")]
+pub struct Foo;
+
+#[doc(alias = "false")]
+pub struct Bar;
--- /dev/null
+#![feature(doc_alias)]
+
+#[doc(alias = "foo")] // ok!
+pub struct Bar;
+
+#[doc(alias)] //~ ERROR
+#[doc(alias = 0)] //~ ERROR
+#[doc(alias("bar"))] //~ ERROR
+pub struct Foo;
--- /dev/null
+error: doc alias attribute expects a string: #[doc(alias = "0")]
+ --> $DIR/check-doc-alias-attr.rs:6:7
+ |
+LL | #[doc(alias)]
+ | ^^^^^
+
+error: doc alias attribute expects a string: #[doc(alias = "0")]
+ --> $DIR/check-doc-alias-attr.rs:7:7
+ |
+LL | #[doc(alias = 0)]
+ | ^^^^^^^^^
+
+error: doc alias attribute expects a string: #[doc(alias = "0")]
+ --> $DIR/check-doc-alias-attr.rs:8:7
+ |
+LL | #[doc(alias("bar"))]
+ | ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+warning: `[DontDocMe]` public documentation for `DocMe` links to a private item
+ --> $DIR/intra-links-private.rs:6:11
+ |
+LL | /// docs [DontDocMe]
+ | ^^^^^^^^^ this item is private
+ |
+ = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+
+warning: 1 warning emitted
+
--- /dev/null
+// check-pass
+// revisions: public private
+// [private]compile-flags: --document-private-items
+#![cfg_attr(private, deny(intra_doc_resolution_failure))]
+
+/// docs [DontDocMe]
+//[public]~^ WARNING `[DontDocMe]` public documentation for `DocMe` links to a private item
+// FIXME: for [private] we should also make sure the link was actually generated
+pub struct DocMe;
+struct DontDocMe;
--- /dev/null
+// ignore-test
+// check-pass
+
+/// docs [label][with#anchor#error]
+//~^ WARNING has an issue with the link anchor
+pub struct S;
--- /dev/null
+warning: `[with#anchor#error]` has an issue with the link anchor.
+ --> $DIR/reference-link-has-one-warning.rs:3:18
+ |
+LL | /// docs [label][with#anchor#error]
+ | ^^^^^^^^^^^^^^^^^ only one `#` is allowed in a link
+ |
+ = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+
+warning: 1 warning emitted
+
-error: unterminated double quote string
+error[E0765]: unterminated double quote string
--> $DIR/test-compile-fail3.rs:3:1
|
3 | "fail
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0765`.
failures:
---- $DIR/unparseable-doc-test.rs - foo (line 6) stdout ----
-error: unterminated double quote string
+error[E0765]: unterminated double quote string
--> $DIR/unparseable-doc-test.rs:8:1
|
LL | "unterminated
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0765`.
Couldn't compile the test.
failures:
// @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]/span' "This example deliberately fails to compile"
// @has foo/fn.bar.html '//*[@class="tooltip ignore"]/span' "This example is not tested"
+// @has foo/fn.bar.html '//*[@class="tooltip should_panic"]/span' "This example panics"
/// foo
///
/// goo();
/// ```
///
+/// ```should_panic
+/// hoo();
+/// ```
+///
/// ```
/// let x = 0;
/// ```
// ignore-tidy-linelength
#![feature(const_generics)]
-
#![crate_name = "foo"]
use std::ops::Add;
inner: T,
}
-// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]/h3/code' 'impl Add<Simd<u8, 16usize>> for Simd<u8, 16>'
+// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]/h3/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
impl Add for Simd<u8, 16> {
type Output = Self;
// needs-sanitizer-support
+// needs-sanitizer-address
// compile-flags: --test -Z sanitizer=address
//
// #43031: Verify that rustdoc passes `-Z` options to rustc. Use an extern
--- /dev/null
+// Tests that we don't fail with an overflow error for certain
+// strange types
+// See https://github.com/rust-lang/rust/pull/72936#issuecomment-643676915
+
+pub trait Interner {
+ type InternedType;
+}
+
+struct RustInterner<'tcx> {
+ foo: &'tcx ()
+}
+
+impl<'tcx> Interner for RustInterner<'tcx> {
+ type InternedType = Box<TyData<Self>>;
+}
+
+enum TyData<I: Interner> {
+ FnDef(I::InternedType)
+}
+
+struct VariableKind<I: Interner>(I::InternedType);
+
+// @has overflow/struct.BoundVarsCollector.html
+// @has - '//code' "impl<'tcx> Send for BoundVarsCollector<'tcx>"
+pub struct BoundVarsCollector<'tcx> {
+ val: VariableKind<RustInterner<'tcx>>
+}
+
+fn is_send<T: Send>() {}
+
+struct MyInterner<'tcx> {
+ val: &'tcx ()
+}
+
+fn main() {}
TyKind::Bound(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Placeholder(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Infer(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
- TyKind::Error => (), //~ ERROR usage of `ty::TyKind::<kind>`
+ TyKind::Error(_) => (), //~ ERROR usage of `ty::TyKind::<kind>`
}
if let ty::Int(int_ty) = kind {}
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:40:9
|
-LL | TyKind::Error => (),
+LL | TyKind::Error(_) => (),
| ^^^^^^ help: try using ty::<kind> directly: `ty`
error: usage of `ty::TyKind::<kind>`
#[cfg(target_arch = "x86_64")]
#[inline(never)]
+#[allow(improper_ctypes_definitions)]
pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct {
foo.0 *= 1;
foo.1 *= 2;
#[repr(align(16))]
pub struct A(i64);
+#[allow(improper_ctypes_definitions)]
pub extern "C" fn foo(x: A) {}
fn main() {
--> $DIR/match_arr_unknown_len.rs:6:9
|
LL | [1, 2] => true,
- | ^^^^^^ expected `2usize`, found `N`
+ | ^^^^^^ expected `2_usize`, found `N`
|
= note: expected array `[u32; 2]`
found array `[u32; N]`
// run-pass
-#![feature(const_fn, const_if_match)]
+#![feature(const_fn)]
+
#[derive(PartialEq, Debug, Clone)]
struct N(u8);
--- /dev/null
+// only-x86_64
+// run-rustfix
+
+#![feature(asm)]
+
+fn main() {
+ unsafe {
+ asm!("", options(nomem, ));
+ //~^ ERROR the `nomem` option was already provided
+ asm!("", options(att_syntax, ));
+ //~^ ERROR the `att_syntax` option was already provided
+ asm!("", options(nostack, att_syntax), options());
+ //~^ ERROR the `nostack` option was already provided
+ asm!("", options(nostack, ), options(), options());
+ //~^ ERROR the `nostack` option was already provided
+ //~| ERROR the `nostack` option was already provided
+ //~| ERROR the `nostack` option was already provided
+ asm!(
+ "",
+ options(nomem, noreturn),
+ options(att_syntax, ), //~ ERROR the `noreturn` option was already provided
+ options( nostack), //~ ERROR the `nomem` option was already provided
+ options(), //~ ERROR the `noreturn` option was already provided
+ );
+ }
+}
--- /dev/null
+// only-x86_64
+// run-rustfix
+
+#![feature(asm)]
+
+fn main() {
+ unsafe {
+ asm!("", options(nomem, nomem));
+ //~^ ERROR the `nomem` option was already provided
+ asm!("", options(att_syntax, att_syntax));
+ //~^ ERROR the `att_syntax` option was already provided
+ asm!("", options(nostack, att_syntax), options(nostack));
+ //~^ ERROR the `nostack` option was already provided
+ asm!("", options(nostack, nostack), options(nostack), options(nostack));
+ //~^ ERROR the `nostack` option was already provided
+ //~| ERROR the `nostack` option was already provided
+ //~| ERROR the `nostack` option was already provided
+ asm!(
+ "",
+ options(nomem, noreturn),
+ options(att_syntax, noreturn), //~ ERROR the `noreturn` option was already provided
+ options(nomem, nostack), //~ ERROR the `nomem` option was already provided
+ options(noreturn), //~ ERROR the `noreturn` option was already provided
+ );
+ }
+}
--- /dev/null
+error: the `nomem` option was already provided
+ --> $DIR/duplicate-options.rs:8:33
+ |
+LL | asm!("", options(nomem, nomem));
+ | ^^^^^ this option was already provided
+
+error: the `att_syntax` option was already provided
+ --> $DIR/duplicate-options.rs:10:38
+ |
+LL | asm!("", options(att_syntax, att_syntax));
+ | ^^^^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+ --> $DIR/duplicate-options.rs:12:56
+ |
+LL | asm!("", options(nostack, att_syntax), options(nostack));
+ | ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+ --> $DIR/duplicate-options.rs:14:35
+ |
+LL | asm!("", options(nostack, nostack), options(nostack), options(nostack));
+ | ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+ --> $DIR/duplicate-options.rs:14:53
+ |
+LL | asm!("", options(nostack, nostack), options(nostack), options(nostack));
+ | ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+ --> $DIR/duplicate-options.rs:14:71
+ |
+LL | asm!("", options(nostack, nostack), options(nostack), options(nostack));
+ | ^^^^^^^ this option was already provided
+
+error: the `noreturn` option was already provided
+ --> $DIR/duplicate-options.rs:21:33
+ |
+LL | options(att_syntax, noreturn),
+ | ^^^^^^^^ this option was already provided
+
+error: the `nomem` option was already provided
+ --> $DIR/duplicate-options.rs:22:21
+ |
+LL | options(nomem, nostack),
+ | ^^^^^ this option was already provided
+
+error: the `noreturn` option was already provided
+ --> $DIR/duplicate-options.rs:23:21
+ |
+LL | options(noreturn),
+ | ^^^^^^^^ this option was already provided
+
+error: aborting due to 9 previous errors
+
asm!("{}" foo);
//~^ ERROR expected token: `,`
asm!("{}", foo);
- //~^ ERROR expected one of
+ //~^ ERROR expected operand, options, or additional template string
asm!("{}", in foo);
//~^ ERROR expected `(`, found `foo`
asm!("{}", in(reg foo));
//~^ ERROR expected one of
asm!("", options(nomem, foo));
//~^ ERROR expected one of
- asm!("", options(), options());
- //~^ ERROR asm options cannot be specified multiple times
- asm!("", options(), options(), options());
- //~^ ERROR asm options cannot be specified multiple times
- //~^^ ERROR asm options cannot be specified multiple times
asm!("{}", options(), const foo);
//~^ ERROR arguments are not allowed after options
asm!("{a}", a = const foo, a = const bar);
//~^ ERROR named arguments cannot follow explicit register arguments
asm!("{1}", in("eax") foo, const bar);
//~^ ERROR positional arguments cannot follow named arguments or explicit register arguments
+ asm!("", options(), "");
+ //~^ ERROR expected one of
+ asm!("{}", in(reg) foo, "{}", out(reg) foo);
+ //~^ ERROR expected one of
+ asm!(format!("{{{}}}", 0), in(reg) foo);
+ //~^ ERROR asm template must be a string literal
+ asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
+ //~^ ERROR asm template must be a string literal
}
}
LL | asm!("{}" foo);
| ^^^ expected `,`
-error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `foo`
+error: expected operand, options, or additional template string
--> $DIR/parse-error.rs:15:20
|
LL | asm!("{}", foo);
- | ^^^ expected one of 8 possible tokens
+ | ^^^ expected operand, options, or additional template string
error: expected `(`, found `foo`
--> $DIR/parse-error.rs:17:23
LL | asm!("", options(nomem, foo));
| ^^^ expected one of 8 possible tokens
-error: asm options cannot be specified multiple times
- --> $DIR/parse-error.rs:37:29
- |
-LL | asm!("", options(), options());
- | --------- ^^^^^^^^^ duplicate options
- | |
- | previously here
-
-error: asm options cannot be specified multiple times
- --> $DIR/parse-error.rs:39:29
- |
-LL | asm!("", options(), options(), options());
- | --------- ^^^^^^^^^ duplicate options
- | |
- | previously here
-
-error: asm options cannot be specified multiple times
- --> $DIR/parse-error.rs:39:40
- |
-LL | asm!("", options(), options(), options());
- | --------- ^^^^^^^^^ duplicate options
- | |
- | previously here
-
error: arguments are not allowed after options
- --> $DIR/parse-error.rs:42:31
+ --> $DIR/parse-error.rs:37:31
|
LL | asm!("{}", options(), const foo);
| --------- ^^^^^^^^^ argument
| previous options
error: duplicate argument named `a`
- --> $DIR/parse-error.rs:44:36
+ --> $DIR/parse-error.rs:39:36
|
LL | asm!("{a}", a = const foo, a = const bar);
| ------------- ^^^^^^^^^^^^^ duplicate argument
| previously here
error: argument never used
- --> $DIR/parse-error.rs:44:36
+ --> $DIR/parse-error.rs:39:36
|
LL | asm!("{a}", a = const foo, a = const bar);
| ^^^^^^^^^^^^^ argument never used
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
error: explicit register arguments cannot have names
- --> $DIR/parse-error.rs:47:18
+ --> $DIR/parse-error.rs:42:18
|
LL | asm!("", a = in("eax") foo);
| ^^^^^^^^^^^^^^^^^
error: named arguments cannot follow explicit register arguments
- --> $DIR/parse-error.rs:49:36
+ --> $DIR/parse-error.rs:44:36
|
LL | asm!("{a}", in("eax") foo, a = const bar);
| ------------- ^^^^^^^^^^^^^ named argument
| explicit register argument
error: named arguments cannot follow explicit register arguments
- --> $DIR/parse-error.rs:51:36
+ --> $DIR/parse-error.rs:46:36
|
LL | asm!("{a}", in("eax") foo, a = const bar);
| ------------- ^^^^^^^^^^^^^ named argument
| explicit register argument
error: positional arguments cannot follow named arguments or explicit register arguments
- --> $DIR/parse-error.rs:53:36
+ --> $DIR/parse-error.rs:48:36
|
LL | asm!("{1}", in("eax") foo, const bar);
| ------------- ^^^^^^^^^ positional argument
| |
| explicit register argument
-error: aborting due to 24 previous errors
+error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
+ --> $DIR/parse-error.rs:50:29
+ |
+LL | asm!("", options(), "");
+ | ^^ expected one of 8 possible tokens
+
+error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
+ --> $DIR/parse-error.rs:52:33
+ |
+LL | asm!("{}", in(reg) foo, "{}", out(reg) foo);
+ | ^^^^ expected one of 8 possible tokens
+
+error: asm template must be a string literal
+ --> $DIR/parse-error.rs:54:14
+ |
+LL | asm!(format!("{{{}}}", 0), in(reg) foo);
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm template must be a string literal
+ --> $DIR/parse-error.rs:56:21
+ |
+LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 25 previous errors
asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
//~^ WARN: scale factor without index register is ignored
+
+ asm!(
+ "invalid_instruction",
+ );
+ //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ asm!(
+ "mov eax, eax",
+ "invalid_instruction",
+ "mov eax, eax",
+ );
+ //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ asm!(
+ "mov eax, eax\n",
+ "invalid_instruction",
+ "mov eax, eax",
+ );
+ //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ asm!(
+ "mov eax, eax",
+ concat!("invalid", "_", "instruction"),
+ "mov eax, eax",
+ );
+ //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ asm!(
+ concat!("mov eax", ", ", "eax"),
+ concat!("invalid", "_", "instruction"),
+ concat!("mov eax", ", ", "eax"),
+ );
+ //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ // Make sure template strings get separated
+ asm!(
+ "invalid_instruction1",
+ "invalid_instruction2",
+ );
+ //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+ //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+
+ asm!(
+ concat!(
+ "invalid", "_", "instruction1", "\n",
+ "invalid", "_", "instruction2",
+ ),
+ );
+ //~^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+ //~^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+
+ asm!(
+ concat!(
+ "invalid", "_", "instruction1", "\n",
+ "invalid", "_", "instruction2",
+ ),
+ concat!(
+ "invalid", "_", "instruction3", "\n",
+ "invalid", "_", "instruction4",
+ ),
+ );
+ //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+ //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+ //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
+ //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
+
+ asm!(
+ concat!(
+ "invalid", "_", "instruction1", "\n",
+ "invalid", "_", "instruction2", "\n",
+ ),
+ concat!(
+ "invalid", "_", "instruction3", "\n",
+ "invalid", "_", "instruction4", "\n",
+ ),
+ );
+ //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+ //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+ //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
+ //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
}
}
LL | movaps %xmm3, (%esi, 2)
| ^
-error: aborting due to 6 previous errors; 1 warning emitted
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:45:14
+ |
+LL | "invalid_instruction",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:2
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:51:14
+ |
+LL | "invalid_instruction",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:58:14
+ |
+LL | "invalid_instruction",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:4:1
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:65:13
+ |
+LL | concat!("invalid", "_", "instruction"),
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:72:13
+ |
+LL | concat!("invalid", "_", "instruction"),
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+ --> $DIR/srcloc.rs:79:14
+ |
+LL | "invalid_instruction1",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:2
+ |
+LL | invalid_instruction1
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+ --> $DIR/srcloc.rs:80:14
+ |
+LL | "invalid_instruction2",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction2
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+ --> $DIR/srcloc.rs:86:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:2
+ |
+LL | invalid_instruction1
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+ --> $DIR/srcloc.rs:86:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction2
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+ --> $DIR/srcloc.rs:95:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:2
+ |
+LL | invalid_instruction1
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+ --> $DIR/srcloc.rs:95:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction2
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction3'
+ --> $DIR/srcloc.rs:99:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:4:1
+ |
+LL | invalid_instruction3
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction4'
+ --> $DIR/srcloc.rs:99:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:5:1
+ |
+LL | invalid_instruction4
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+ --> $DIR/srcloc.rs:110:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:2
+ |
+LL | invalid_instruction1
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+ --> $DIR/srcloc.rs:110:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction2
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction3'
+ --> $DIR/srcloc.rs:114:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:5:1
+ |
+LL | invalid_instruction3
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction4'
+ --> $DIR/srcloc.rs:114:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:6:1
+ |
+LL | invalid_instruction4
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 23 previous errors; 1 warning emitted
--- /dev/null
+#![feature(lang_items)]
+
+trait Foo {
+ #[lang = "dummy_lang_item_1"] //~ ERROR definition
+ fn foo() {}
+
+ #[lang = "dummy_lang_item_2"] //~ ERROR definition
+ fn bar();
+
+ #[lang = "dummy_lang_item_3"] //~ ERROR definition
+ type MyType;
+}
+
+struct Bar;
+
+impl Bar {
+ #[lang = "dummy_lang_item_4"] //~ ERROR definition
+ fn test() {}
+}
+
+fn main() {}
--- /dev/null
+error[E0522]: definition of an unknown language item: `dummy_lang_item_1`
+ --> $DIR/assoc-lang-items.rs:4:5
+ |
+LL | #[lang = "dummy_lang_item_1"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_1`
+
+error[E0522]: definition of an unknown language item: `dummy_lang_item_2`
+ --> $DIR/assoc-lang-items.rs:7:5
+ |
+LL | #[lang = "dummy_lang_item_2"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_2`
+
+error[E0522]: definition of an unknown language item: `dummy_lang_item_3`
+ --> $DIR/assoc-lang-items.rs:10:5
+ |
+LL | #[lang = "dummy_lang_item_3"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_3`
+
+error[E0522]: definition of an unknown language item: `dummy_lang_item_4`
+ --> $DIR/assoc-lang-items.rs:17:5
+ |
+LL | #[lang = "dummy_lang_item_4"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_4`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0522`.
LL | const B: u8 = Self::A + 1;
| --------------^^^^^^^^^^^-
| |
- | attempt to add with overflow
+ | attempt to compute `u8::MAX + 1_u8` which would overflow
|
= note: `#[deny(const_err)]` on by default
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22
|
LL | const NEG: i32 = -i32::MIN + T::NEG;
- | ^^^^^^^^^ attempt to negate with overflow
+ | ^^^^^^^^^ attempt to negate i32::MIN which would overflow
|
= note: `#[deny(arithmetic_overflow)]` on by default
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35
|
LL | const NEG_REV: i32 = T::NEG + (-i32::MIN);
- | ^^^^^^^^^^^ attempt to negate with overflow
+ | ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22
|
LL | const ADD: i32 = (i32::MAX+1) + T::ADD;
- | ^^^^^^^^^^^^ attempt to add with overflow
+ | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36
|
LL | const ADD_REV: i32 = T::ADD + (i32::MAX+1);
- | ^^^^^^^^^^^^ attempt to add with overflow
+ | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
error: this operation will panic at runtime
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22
|
LL | const DIV: i32 = (1/0) + T::DIV;
- | ^^^^^ attempt to divide by zero
+ | ^^^^^ attempt to divide 1_i32 by zero
|
= note: `#[deny(unconditional_panic)]` on by default
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35
|
LL | const DIV_REV: i32 = T::DIV + (1/0);
- | ^^^^^ attempt to divide by zero
+ | ^^^^^ attempt to divide 1_i32 by zero
error: this operation will panic at runtime
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22
|
LL | const NEG: i32 = -i32::MIN + T::NEG;
- | ^^^^^^^^^ attempt to negate with overflow
+ | ^^^^^^^^^ attempt to negate i32::MIN which would overflow
|
= note: `#[deny(arithmetic_overflow)]` on by default
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35
|
LL | const NEG_REV: i32 = T::NEG + (-i32::MIN);
- | ^^^^^^^^^^^ attempt to negate with overflow
+ | ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22
|
LL | const ADD: i32 = (i32::MAX+1) + T::ADD;
- | ^^^^^^^^^^^^ attempt to add with overflow
+ | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36
|
LL | const ADD_REV: i32 = T::ADD + (i32::MAX+1);
- | ^^^^^^^^^^^^ attempt to add with overflow
+ | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
error: this operation will panic at runtime
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22
|
LL | const DIV: i32 = (1/0) + T::DIV;
- | ^^^^^ attempt to divide by zero
+ | ^^^^^ attempt to divide 1_i32 by zero
|
= note: `#[deny(unconditional_panic)]` on by default
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35
|
LL | const DIV_REV: i32 = T::DIV + (1/0);
- | ^^^^^ attempt to divide by zero
+ | ^^^^^ attempt to divide 1_i32 by zero
error: this operation will panic at runtime
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22
|
LL | const NEG: i32 = -i32::MIN + T::NEG;
- | ^^^^^^^^^ attempt to negate with overflow
+ | ^^^^^^^^^ attempt to negate i32::MIN which would overflow
|
= note: `#[deny(arithmetic_overflow)]` on by default
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35
|
LL | const NEG_REV: i32 = T::NEG + (-i32::MIN);
- | ^^^^^^^^^^^ attempt to negate with overflow
+ | ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22
|
LL | const ADD: i32 = (i32::MAX+1) + T::ADD;
- | ^^^^^^^^^^^^ attempt to add with overflow
+ | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36
|
LL | const ADD_REV: i32 = T::ADD + (i32::MAX+1);
- | ^^^^^^^^^^^^ attempt to add with overflow
+ | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
error: this operation will panic at runtime
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22
|
LL | const DIV: i32 = (1/0) + T::DIV;
- | ^^^^^ attempt to divide by zero
+ | ^^^^^ attempt to divide 1_i32 by zero
|
= note: `#[deny(unconditional_panic)]` on by default
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35
|
LL | const DIV_REV: i32 = T::DIV + (1/0);
- | ^^^^^ attempt to divide by zero
+ | ^^^^^ attempt to divide 1_i32 by zero
error: this operation will panic at runtime
--> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22
LL | fn foo2<I: Foo>(x: I) {
| - similarly named type parameter `I` defined here
LL | let _: A = x.boo();
- | ^ help: a type parameter with a similar name exists: `I`
+ | ^
+ |
+help: a type parameter with a similar name exists
+ |
+LL | let _: I = x.boo();
+ | ^
+help: you might be missing a type parameter
+ |
+LL | fn foo2<I: Foo, A>(x: I) {
+ | ^^^
error: aborting due to previous error
--- /dev/null
+error[E0271]: type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize>>::A == &'x isize`
+ --> $DIR/associated-types-eq-hr.rs:87:5
+ |
+LL | fn foo<T>()
+ | --- required by a bound in this
+LL | where
+LL | T: for<'x> TheTrait<&'x isize, A = &'x isize>,
+ | ------------- required by this bound in `foo`
+...
+LL | foo::<UintStruct>();
+ | ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize`
+ |
+ = note: expected reference `&isize`
+ found reference `&usize`
+
+error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
+ --> $DIR/associated-types-eq-hr.rs:91:5
+ |
+LL | fn bar<T>()
+ | --- required by a bound in this
+LL | where
+LL | T: for<'x> TheTrait<&'x isize, A = &'x usize>,
+ | ------------- required by this bound in `bar`
+...
+LL | bar::<IntStruct>();
+ | ^^^^^^^^^^^^^^^^ expected `usize`, found `isize`
+ |
+ = note: expected reference `&usize`
+ found reference `&isize`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
}
struct IntStruct {
- x: isize
+ x: isize,
}
impl<'a> TheTrait<&'a isize> for IntStruct {
}
struct UintStruct {
- x: isize
+ x: isize,
}
impl<'a> TheTrait<&'a isize> for UintStruct {
}
}
-struct Tuple {
-}
+struct Tuple {}
impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple {
type A = &'a isize;
}
fn foo<T>()
- where T : for<'x> TheTrait<&'x isize, A = &'x isize>
+where
+ T: for<'x> TheTrait<&'x isize, A = &'x isize>,
{
// ok for IntStruct, but not UintStruct
}
fn bar<T>()
- where T : for<'x> TheTrait<&'x isize, A = &'x usize>
+where
+ T: for<'x> TheTrait<&'x isize, A = &'x usize>,
{
// ok for UintStruct, but not IntStruct
}
fn tuple_one<T>()
- where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
+where
+ T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>,
{
// not ok for tuple, two lifetimes and we pick first
}
fn tuple_two<T>()
- where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
+where
+ T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>,
{
// not ok for tuple, two lifetimes and we pick second
}
fn tuple_three<T>()
- where T : for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>
+where
+ T: for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>,
{
// ok for tuple
}
fn tuple_four<T>()
- where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
+where
+ T: for<'x, 'y> TheTrait<(&'x isize, &'y isize)>,
{
// not ok for tuple, two lifetimes, and lifetime matching is invariant
}
pub fn call_tuple_one() {
tuple_one::<Tuple>();
- //~^ ERROR not satisfied
- //~| ERROR type mismatch
+ //~^ ERROR implementation of `TheTrait` is not general enough
+ //~| ERROR implementation of `TheTrait` is not general enough
}
pub fn call_tuple_two() {
tuple_two::<Tuple>();
- //~^ ERROR not satisfied
- //~| ERROR type mismatch
+ //~^ ERROR implementation of `TheTrait` is not general enough
+ //~| ERROR implementation of `TheTrait` is not general enough
}
pub fn call_tuple_three() {
pub fn call_tuple_four() {
tuple_four::<Tuple>();
- //~^ ERROR not satisfied
+ //~^ ERROR implementation of `TheTrait` is not general enough
}
-fn main() { }
+fn main() {}
error[E0271]: type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize>>::A == &'x isize`
- --> $DIR/associated-types-eq-hr.rs:82:5
+ --> $DIR/associated-types-eq-hr.rs:87:5
|
LL | fn foo<T>()
| --- required by a bound in this
-LL | where T : for<'x> TheTrait<&'x isize, A = &'x isize>
- | ------------- required by this bound in `foo`
+LL | where
+LL | T: for<'x> TheTrait<&'x isize, A = &'x isize>,
+ | ------------- required by this bound in `foo`
...
LL | foo::<UintStruct>();
| ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize`
found reference `&usize`
error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
- --> $DIR/associated-types-eq-hr.rs:86:5
+ --> $DIR/associated-types-eq-hr.rs:91:5
|
LL | fn bar<T>()
| --- required by a bound in this
-LL | where T : for<'x> TheTrait<&'x isize, A = &'x usize>
- | ------------- required by this bound in `bar`
+LL | where
+LL | T: for<'x> TheTrait<&'x isize, A = &'x usize>,
+ | ------------- required by this bound in `bar`
...
LL | bar::<IntStruct>();
| ^^^^^^^^^^^^^^^^ expected `usize`, found `isize`
= note: expected reference `&usize`
found reference `&isize`
-error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
- --> $DIR/associated-types-eq-hr.rs:91:17
+error: implementation of `TheTrait` is not general enough
+ --> $DIR/associated-types-eq-hr.rs:96:5
|
-LL | fn tuple_one<T>()
- | --------- required by a bound in this
-LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
- | ---------------------------------------------------------- required by this bound in `tuple_one`
+LL | / pub trait TheTrait<T> {
+LL | | type A;
+LL | |
+LL | | fn get(&self, t: T) -> Self::A;
+LL | | }
+ | |_- trait `TheTrait` defined here
...
-LL | tuple_one::<Tuple>();
- | ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+LL | tuple_one::<Tuple>();
+ | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
|
- = help: the following implementations were found:
- <Tuple as TheTrait<(&'a isize, &'a isize)>>
+ = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+ = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
-error[E0271]: type mismatch resolving `for<'x, 'y> <Tuple as TheTrait<(&'x isize, &'y isize)>>::A == &'x isize`
- --> $DIR/associated-types-eq-hr.rs:91:5
+error: implementation of `TheTrait` is not general enough
+ --> $DIR/associated-types-eq-hr.rs:96:5
|
-LL | fn tuple_one<T>()
- | --------- required by a bound in this
-LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
- | ------------- required by this bound in `tuple_one`
+LL | / pub trait TheTrait<T> {
+LL | | type A;
+LL | |
+LL | | fn get(&self, t: T) -> Self::A;
+LL | | }
+ | |_- trait `TheTrait` defined here
...
-LL | tuple_one::<Tuple>();
- | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+LL | tuple_one::<Tuple>();
+ | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+ |
+ = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+ = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
-error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
- --> $DIR/associated-types-eq-hr.rs:97:17
+error: implementation of `TheTrait` is not general enough
+ --> $DIR/associated-types-eq-hr.rs:102:5
|
-LL | fn tuple_two<T>()
- | --------- required by a bound in this
-LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
- | ---------------------------------------------------------- required by this bound in `tuple_two`
+LL | / pub trait TheTrait<T> {
+LL | | type A;
+LL | |
+LL | | fn get(&self, t: T) -> Self::A;
+LL | | }
+ | |_- trait `TheTrait` defined here
...
-LL | tuple_two::<Tuple>();
- | ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+LL | tuple_two::<Tuple>();
+ | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
|
- = help: the following implementations were found:
- <Tuple as TheTrait<(&'a isize, &'a isize)>>
+ = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+ = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
-error[E0271]: type mismatch resolving `for<'x, 'y> <Tuple as TheTrait<(&'x isize, &'y isize)>>::A == &'y isize`
- --> $DIR/associated-types-eq-hr.rs:97:5
+error: implementation of `TheTrait` is not general enough
+ --> $DIR/associated-types-eq-hr.rs:102:5
|
-LL | fn tuple_two<T>()
- | --------- required by a bound in this
-LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
- | ------------- required by this bound in `tuple_two`
+LL | / pub trait TheTrait<T> {
+LL | | type A;
+LL | |
+LL | | fn get(&self, t: T) -> Self::A;
+LL | | }
+ | |_- trait `TheTrait` defined here
...
-LL | tuple_two::<Tuple>();
- | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+LL | tuple_two::<Tuple>();
+ | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+ |
+ = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+ = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
-error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
- --> $DIR/associated-types-eq-hr.rs:107:18
+error: implementation of `TheTrait` is not general enough
+ --> $DIR/associated-types-eq-hr.rs:112:5
|
-LL | fn tuple_four<T>()
- | ---------- required by a bound in this
-LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
- | ------------------------------------------- required by this bound in `tuple_four`
+LL | / pub trait TheTrait<T> {
+LL | | type A;
+LL | |
+LL | | fn get(&self, t: T) -> Self::A;
+LL | | }
+ | |_- trait `TheTrait` defined here
...
-LL | tuple_four::<Tuple>();
- | ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+LL | tuple_four::<Tuple>();
+ | ^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
|
- = help: the following implementations were found:
- <Tuple as TheTrait<(&'a isize, &'a isize)>>
+ = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+ = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error: aborting due to 7 previous errors
-Some errors have detailed explanations: E0271, E0277.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0271`.
error: lifetime may not live long enough
- --> $DIR/project-fn-ret-invariant.rs:55:4
+ --> $DIR/project-fn-ret-invariant.rs:56:5
|
-LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
- | -- -- lifetime `'b` defined here
+LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+ | -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
-LL | (a, b)
- | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+LL | (a, b)
+ | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
|
= help: consider adding the following bound: `'a: 'b`
error: lifetime may not live long enough
- --> $DIR/project-fn-ret-invariant.rs:55:4
+ --> $DIR/project-fn-ret-invariant.rs:56:5
|
-LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
- | -- -- lifetime `'b` defined here
+LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+ | -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
-LL | (a, b)
- | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+LL | (a, b)
+ | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
= help: consider adding the following bound: `'b: 'a`
error[E0623]: lifetime mismatch
- --> $DIR/project-fn-ret-invariant.rs:53:21
+ --> $DIR/project-fn-ret-invariant.rs:54:22
|
-LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
- | -------- --------------------
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | let a = bar(foo, y);
- | ^ ...but data from `x` is returned here
+LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+ | -------- --------------------
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | let a = bar(foo, y);
+ | ^ ...but data from `x` is returned here
error[E0623]: lifetime mismatch
- --> $DIR/project-fn-ret-invariant.rs:54:21
+ --> $DIR/project-fn-ret-invariant.rs:56:9
|
-LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
- | -------- --------------------
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | let a = bar(foo, y);
-LL | let b = bar(foo, x);
- | ^ ...but data from `y` is returned here
+LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+ | -------- --------------------
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+...
+LL | (a, b)
+ | ^ ...but data from `x` is returned here
error: aborting due to 2 previous errors
error: fatal error triggered by #[rustc_error]
- --> $DIR/project-fn-ret-invariant.rs:59:1
+ --> $DIR/project-fn-ret-invariant.rs:60:1
|
-LL | fn main() { }
- | ^^^^^^^^^^^^^
+LL | fn main() {}
+ | ^^^^^^^^^^^^
error: aborting due to previous error
error: lifetime may not live long enough
- --> $DIR/project-fn-ret-invariant.rs:38:12
+ --> $DIR/project-fn-ret-invariant.rs:39:13
|
-LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
- | -- -- lifetime `'b` defined here
+LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+ | -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
-LL | let f = foo; // <-- No consistent type can be inferred for `f` here.
-LL | let a = bar(f, x);
- | ^^^^^^^^^ argument requires that `'a` must outlive `'b`
+LL | let f = foo; // <-- No consistent type can be inferred for `f` here.
+LL | let a = bar(f, x);
+ | ^^^^^^^^^ argument requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
error: lifetime may not live long enough
- --> $DIR/project-fn-ret-invariant.rs:39:12
+ --> $DIR/project-fn-ret-invariant.rs:40:13
|
-LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
- | -- -- lifetime `'b` defined here
+LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+ | -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
-LL | let b = bar(f, y);
- | ^^^^^^^^^ argument requires that `'b` must outlive `'a`
+LL | let b = bar(f, y);
+ | ^^^^^^^^^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
error[E0623]: lifetime mismatch
- --> $DIR/project-fn-ret-invariant.rs:39:19
+ --> $DIR/project-fn-ret-invariant.rs:40:20
|
-LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
- | -------- --------------------
- | |
- | this parameter and the return type are declared with different lifetimes...
+LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+ | -------- --------------------
+ | |
+ | this parameter and the return type are declared with different lifetimes...
...
-LL | let b = bar(f, y);
- | ^ ...but data from `x` is returned here
+LL | let b = bar(f, y);
+ | ^ ...but data from `x` is returned here
error: aborting due to previous error
#![feature(unboxed_closures)]
#![feature(rustc_attrs)]
-
// Test for projection cache. We should be able to project distinct
// lifetimes from `foo` as we reinstantiate it multiple times, but not
// if we do it just once. In this variant, the region `'a` is used in
// an invariant position, which affects the results.
// revisions: ok oneuse transmute krisskross
-
#![allow(dead_code, unused_variables)]
use std::marker::PhantomData;
struct Type<'a> {
// Invariant
- data: PhantomData<fn(&'a u32) -> &'a u32>
+ data: PhantomData<fn(&'a u32) -> &'a u32>,
}
-fn foo<'a>() -> Type<'a> { loop { } }
+fn foo<'a>() -> Type<'a> {
+ loop {}
+}
fn bar<T>(t: T, x: T::Output) -> T::Output
- where T: FnOnce<()>
+where
+ T: FnOnce<()>,
{
t()
}
#[cfg(ok)] // two instantiations: OK
-fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
let a = bar(foo, x);
let b = bar(foo, y);
(a, b)
}
#[cfg(oneuse)] // one instantiation: BAD
-fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
- let f = foo; // <-- No consistent type can be inferred for `f` here.
- let a = bar(f, x);
- let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623]
- (a, b)
+fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+ let f = foo; // <-- No consistent type can be inferred for `f` here.
+ let a = bar(f, x);
+ let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623]
+ (a, b)
}
#[cfg(transmute)] // one instantiations: BAD
-fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
- // Cannot instantiate `foo` with any lifetime other than `'a`,
- // since it is provided as input.
+fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
+ // Cannot instantiate `foo` with any lifetime other than `'a`,
+ // since it is provided as input.
- bar(foo, x) //[transmute]~ ERROR E0495
+ bar(foo, x) //[transmute]~ ERROR E0495
}
#[cfg(krisskross)] // two instantiations, mixing and matching: BAD
-fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
- let a = bar(foo, y); //[krisskross]~ ERROR E0623
- let b = bar(foo, x); //[krisskross]~ ERROR E0623
- (a, b)
+fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+ let a = bar(foo, y); //[krisskross]~ ERROR E0623
+ let b = bar(foo, x);
+ (a, b) //[krisskross]~ ERROR E0623
}
#[rustc_error]
-fn main() { }
+fn main() {}
//[ok]~^ ERROR fatal error triggered by #[rustc_error]
error: lifetime may not live long enough
- --> $DIR/project-fn-ret-invariant.rs:48:4
+ --> $DIR/project-fn-ret-invariant.rs:49:5
|
-LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
+LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
| -- lifetime `'a` defined here
...
-LL | bar(foo, x)
- | ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+LL | bar(foo, x)
+ | ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
|
= help: consider replacing `'a` with `'static`
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
- --> $DIR/project-fn-ret-invariant.rs:48:8
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+ --> $DIR/project-fn-ret-invariant.rs:49:9
|
-LL | bar(foo, x)
- | ^^^
+LL | bar(foo, x)
+ | ^^^
|
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 44:8...
- --> $DIR/project-fn-ret-invariant.rs:44:8
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 45:8...
+ --> $DIR/project-fn-ret-invariant.rs:45:8
|
-LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
+LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
| ^^
note: ...so that the expression is assignable
- --> $DIR/project-fn-ret-invariant.rs:48:13
+ --> $DIR/project-fn-ret-invariant.rs:49:14
|
-LL | bar(foo, x)
- | ^
+LL | bar(foo, x)
+ | ^
= note: expected `Type<'_>`
found `Type<'a>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
- --> $DIR/project-fn-ret-invariant.rs:48:4
+ --> $DIR/project-fn-ret-invariant.rs:49:5
|
-LL | bar(foo, x)
- | ^^^^^^^^^^^
+LL | bar(foo, x)
+ | ^^^^^^^^^^^
= note: expected `Type<'static>`
found `Type<'_>`
//! Tests the interaction of associated type defaults and specialization.
#![feature(associated_type_defaults, specialization)]
+//~^ WARN the feature `specialization` is incomplete
trait Tr {
type Ty = u8;
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/defaults-specialization.rs:3:38
+ |
+LL | #![feature(associated_type_defaults, specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0053]: method `make` has an incompatible type for trait
- --> $DIR/defaults-specialization.rs:18:18
+ --> $DIR/defaults-specialization.rs:19:18
|
LL | fn make() -> Self::Ty {
| -------- type in trait
found fn pointer `fn() -> u8`
error[E0053]: method `make` has an incompatible type for trait
- --> $DIR/defaults-specialization.rs:34:18
+ --> $DIR/defaults-specialization.rs:35:18
|
LL | fn make() -> Self::Ty {
| -------- type in trait
found fn pointer `fn() -> bool`
error[E0308]: mismatched types
- --> $DIR/defaults-specialization.rs:9:9
+ --> $DIR/defaults-specialization.rs:10:9
|
LL | type Ty = u8;
| ------------- associated type defaults can't be assumed inside the trait defining them
found type `u8`
error[E0308]: mismatched types
- --> $DIR/defaults-specialization.rs:25:29
+ --> $DIR/defaults-specialization.rs:26:29
|
LL | fn make() -> Self::Ty { 0u8 }
| -------- ^^^ expected associated type, found `u8`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0308]: mismatched types
- --> $DIR/defaults-specialization.rs:43:29
+ --> $DIR/defaults-specialization.rs:44:29
|
LL | default type Ty = bool;
| ----------------------- expected this associated type
found type `bool`
error[E0308]: mismatched types
- --> $DIR/defaults-specialization.rs:86:32
+ --> $DIR/defaults-specialization.rs:87:32
|
LL | let _: <B<()> as Tr>::Ty = 0u8;
| ----------------- ^^^ expected associated type, found `u8`
= note: expected associated type `<B<()> as Tr>::Ty`
found type `u8`
help: a method is available that returns `<B<()> as Tr>::Ty`
- --> $DIR/defaults-specialization.rs:8:5
+ --> $DIR/defaults-specialization.rs:9:5
|
LL | fn make() -> Self::Ty {
| ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
error[E0308]: mismatched types
- --> $DIR/defaults-specialization.rs:87:32
+ --> $DIR/defaults-specialization.rs:88:32
|
LL | let _: <B<()> as Tr>::Ty = true;
| ----------------- ^^^^ expected associated type, found `bool`
= note: expected associated type `<B<()> as Tr>::Ty`
found type `bool`
help: a method is available that returns `<B<()> as Tr>::Ty`
- --> $DIR/defaults-specialization.rs:8:5
+ --> $DIR/defaults-specialization.rs:9:5
|
LL | fn make() -> Self::Ty {
| ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
error[E0308]: mismatched types
- --> $DIR/defaults-specialization.rs:88:33
+ --> $DIR/defaults-specialization.rs:89:33
|
LL | let _: <B2<()> as Tr>::Ty = 0u8;
| ------------------ ^^^ expected associated type, found `u8`
= note: expected associated type `<B2<()> as Tr>::Ty`
found type `u8`
help: a method is available that returns `<B2<()> as Tr>::Ty`
- --> $DIR/defaults-specialization.rs:8:5
+ --> $DIR/defaults-specialization.rs:9:5
|
LL | fn make() -> Self::Ty {
| ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
error[E0308]: mismatched types
- --> $DIR/defaults-specialization.rs:89:33
+ --> $DIR/defaults-specialization.rs:90:33
|
LL | let _: <B2<()> as Tr>::Ty = true;
| ------------------ ^^^^ expected associated type, found `bool`
= note: expected associated type `<B2<()> as Tr>::Ty`
found type `bool`
help: a method is available that returns `<B2<()> as Tr>::Ty`
- --> $DIR/defaults-specialization.rs:8:5
+ --> $DIR/defaults-specialization.rs:9:5
|
LL | fn make() -> Self::Ty {
| ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
-error: aborting due to 9 previous errors
+error: aborting due to 9 previous errors; 1 warning emitted
Some errors have detailed explanations: E0053, E0308.
For more information about an error, try `rustc --explain E0053`.
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/higher-ranked-projection.rs:25:5
+ |
+LL | foo(());
+ | ^^^^^^^
+
+error: aborting due to previous error
+
-error[E0271]: type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
+error[E0308]: mismatched types
--> $DIR/higher-ranked-projection.rs:25:5
|
-LL | fn foo<U, T>(_t: T)
- | --- required by a bound in this
-LL | where for<'a> &'a T: Mirror<Image=U>
- | ------- required by this bound in `foo`
-...
LL | foo(());
- | ^^^ expected bound lifetime parameter 'a, found concrete lifetime
+ | ^^^ one type is more general than the other
+ |
+ = note: expected type `&'a ()`
+ found type `&()`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
#[rustc_error]
fn main() { //[good]~ ERROR fatal error triggered by #[rustc_error]
foo(());
- //[bad]~^ ERROR type mismatch
+ //[bad]~^ ERROR mismatched types
}
--- /dev/null
+trait X<'a>
+where
+ for<'b> <Self as X<'b>>::U: Clone,
+{
+ type U: ?Sized;
+ fn f(&self, x: &Self::U) {
+ <Self::U>::clone(x);
+ }
+}
+
+impl X<'_> for i32 {
+ type U = str;
+ //~^ ERROR the trait bound `for<'b> <i32 as X<'b>>::U: std::clone::Clone`
+}
+
+fn main() {
+ 1i32.f("abc");
+}
--- /dev/null
+error[E0277]: the trait bound `for<'b> <i32 as X<'b>>::U: std::clone::Clone` is not satisfied
+ --> $DIR/hr-associated-type-bound-1.rs:12:14
+ |
+LL | trait X<'a>
+ | - required by a bound in this
+LL | where
+LL | for<'b> <Self as X<'b>>::U: Clone,
+ | ----- required by this bound in `X`
+...
+LL | type U = str;
+ | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<i32 as X<'b>>::U`
+ |
+ = help: the following implementations were found:
+ <&T as std::clone::Clone>
+ <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+trait X<'a>
+where
+ for<'b> <Self as X<'b>>::U: Clone,
+{
+ type U: ?Sized;
+ fn f(&self, x: &Self::U) {
+ <Self::U>::clone(x);
+ }
+}
+
+impl X<'_> for u32
+where
+ for<'b> <Self as X<'b>>::U: Clone,
+{
+ type U = str;
+}
+
+fn main() {
+ 1u32.f("abc");
+ //~^ ERROR no method named `f` found for type `u32` in the current scope
+}
--- /dev/null
+error[E0599]: no method named `f` found for type `u32` in the current scope
+ --> $DIR/hr-associated-type-bound-2.rs:19:10
+ |
+LL | 1u32.f("abc");
+ | ^ method not found in `u32`
+ |
+ = note: the method `f` exists but the following trait bounds were not satisfied:
+ `<u32 as X<'b>>::U: std::clone::Clone`
+ which is required by `u32: X`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
--- /dev/null
+trait X<'a>
+where
+ for<'b> <Self as X<'b>>::U: Clone,
+{
+ type U: ?Sized;
+}
+fn f<'a, T: X<'a> + ?Sized>(x: &<T as X<'a>>::U) {
+ //~^ ERROR the trait bound `for<'b> <T as X<'b>>::U: std::clone::Clone` is not satisfied
+ <<T as X<'_>>::U>::clone(x);
+}
+
+pub fn main() {
+ f::<dyn X<'_, U = str>>("abc");
+}
--- /dev/null
+error[E0277]: the trait bound `for<'b> <T as X<'b>>::U: std::clone::Clone` is not satisfied
+ --> $DIR/hr-associated-type-bound-object.rs:7:13
+ |
+LL | trait X<'a>
+ | - required by a bound in this
+LL | where
+LL | for<'b> <Self as X<'b>>::U: Clone,
+ | ----- required by this bound in `X`
+...
+LL | fn f<'a, T: X<'a> + ?Sized>(x: &<T as X<'a>>::U) {
+ | ^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<T as X<'b>>::U`
+ |
+ = help: the following implementations were found:
+ <&T as std::clone::Clone>
+ <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+trait Y<'a, T: ?Sized>
+where
+ T: Y<'a, Self>,
+ for<'b> <Self as Y<'b, T>>::V: Clone,
+ for<'b> <T as Y<'b, Self>>::V: Clone,
+{
+ type V: ?Sized;
+ fn g(&self, x: &Self::V) {
+ <Self::V>::clone(x);
+ }
+}
+
+impl<'a> Y<'a, u8> for u8 {
+ type V = str;
+ //~^ ERROR the trait bound `for<'b> <u8 as Y<'b, u8>>::V: std::clone::Clone` is not satisfied
+}
+
+fn main() {
+ 1u8.g("abc");
+}
--- /dev/null
+error[E0277]: the trait bound `for<'b> <u8 as Y<'b, u8>>::V: std::clone::Clone` is not satisfied
+ --> $DIR/hr-associated-type-bound-param-1.rs:14:14
+ |
+LL | trait Y<'a, T: ?Sized>
+ | - required by a bound in this
+...
+LL | for<'b> <Self as Y<'b, T>>::V: Clone,
+ | ----- required by this bound in `Y`
+...
+LL | type V = str;
+ | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<u8 as Y<'b, u8>>::V`
+ |
+ = help: the following implementations were found:
+ <&T as std::clone::Clone>
+ <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+trait Z<'a, T: ?Sized>
+where
+ T: Z<'a, u16>,
+ //~^ the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+ //~| the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+ for<'b> <T as Z<'b, u16>>::W: Clone,
+{
+ type W: ?Sized;
+ fn h(&self, x: &T::W) {
+ <T::W>::clone(x);
+ }
+}
+
+impl<'a> Z<'a, u16> for u16 {
+ type W = str;
+ //~^ ERROR the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone
+}
+
+fn main() {
+ 1u16.h("abc");
+}
--- /dev/null
+error[E0277]: the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+ --> $DIR/hr-associated-type-bound-param-2.rs:3:8
+ |
+LL | trait Z<'a, T: ?Sized>
+ | - required by a bound in this
+LL | where
+LL | T: Z<'a, u16>,
+ | ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<u16 as Z<'b, u16>>::W`
+...
+LL | for<'b> <T as Z<'b, u16>>::W: Clone,
+ | ----- required by this bound in `Z`
+ |
+ = help: the following implementations were found:
+ <&T as std::clone::Clone>
+ <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+ --> $DIR/hr-associated-type-bound-param-2.rs:15:14
+ |
+LL | trait Z<'a, T: ?Sized>
+ | - required by a bound in this
+...
+LL | for<'b> <T as Z<'b, u16>>::W: Clone,
+ | ----- required by this bound in `Z`
+...
+LL | type W = str;
+ | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<u16 as Z<'b, u16>>::W`
+ |
+ = help: the following implementations were found:
+ <&T as std::clone::Clone>
+ <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+ --> $DIR/hr-associated-type-bound-param-2.rs:3:8
+ |
+LL | trait Z<'a, T: ?Sized>
+ | - required by a bound in this
+LL | where
+LL | T: Z<'a, u16>,
+ | ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<u16 as Z<'b, u16>>::W`
+...
+LL | for<'b> <T as Z<'b, u16>>::W: Clone,
+ | ----- required by this bound in `Z`
+ |
+ = help: the following implementations were found:
+ <&T as std::clone::Clone>
+ <&mut T as std::clone::Clone>
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// ignore-tidy-linelength
+
+trait X<'a, T>
+where
+ for<'b> T: X<'b, T>,
+ for<'b> <T as X<'b, T>>::U: Clone,
+{
+ type U: ?Sized;
+ fn f(x: &<T as X<'_, T>>::U) {
+ <<T as X<'_, T>>::U>::clone(x);
+ }
+}
+
+impl<S, T> X<'_, (T,)> for (S,) {
+ type U = str;
+ //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+ <(i32,) as X<(i32,)>>::f("abc");
+}
--- /dev/null
+error[E0277]: the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied
+ --> $DIR/hr-associated-type-bound-param-3.rs:15:14
+ |
+LL | trait X<'a, T>
+ | - required by a bound in this
+...
+LL | for<'b> <T as X<'b, T>>::U: Clone,
+ | ----- required by this bound in `X`
+...
+LL | type U = str;
+ | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, (T,)>>::U`
+ |
+ = help: the following implementations were found:
+ <&T as std::clone::Clone>
+ <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+trait X<'a, T>
+where
+ for<'b> (T,): X<'b, T>,
+ for<'b> <(T,) as X<'b, T>>::U: Clone,
+{
+ type U: ?Sized;
+ fn f(x: &<(T,) as X<'_, T>>::U) {
+ <<(T,) as X<'_, T>>::U>::clone(x);
+ }
+}
+
+impl<S, T> X<'_, T> for (S,) {
+ type U = str;
+ //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+ <(i32,) as X<i32>>::f("abc");
+}
--- /dev/null
+error[E0277]: the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied
+ --> $DIR/hr-associated-type-bound-param-4.rs:13:14
+ |
+LL | trait X<'a, T>
+ | - required by a bound in this
+...
+LL | for<'b> <(T,) as X<'b, T>>::U: Clone,
+ | ----- required by this bound in `X`
+...
+LL | type U = str;
+ | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, T>>::U`
+ |
+ = help: the following implementations were found:
+ <&T as std::clone::Clone>
+ <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// ignore-tidy-linelength
+
+trait Cycle: Sized {
+ type Next: Cycle<Next = Self>;
+}
+
+impl<T> Cycle for Box<T> {
+ type Next = Vec<T>;
+}
+
+impl<T> Cycle for Vec<T> {
+ type Next = Box<T>;
+}
+
+trait X<'a, T: Cycle + for<'b> X<'b, T>>
+where
+ for<'b> <T as X<'b, T>>::U: Clone,
+ for<'b> T::Next: X<'b, T::Next>,
+ for<'b> <T::Next as X<'b, T::Next>>::U: Clone,
+{
+ type U: ?Sized;
+ fn f(x: &<T as X<'_, T>>::U) {
+ <<T as X<'_, T>>::U>::clone(x);
+ }
+}
+
+impl<S, T> X<'_, Vec<T>> for S {
+ type U = str;
+ //~^ ERROR the trait bound `for<'b> <std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U: std::clone::Clone` is not satisfied
+ //~| ERROR the trait bound `for<'b> <std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U: std::clone::Clone` is not satisfied
+}
+
+impl<S, T> X<'_, Box<T>> for S {
+ type U = str;
+ //~^ ERROR the trait bound `for<'b> <std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U: std::clone::Clone` is not satisfied
+ //~| ERROR the trait bound `for<'b> <std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+ <i32 as X<Box<i32>>>::f("abc");
+}
--- /dev/null
+error[E0277]: the trait bound `for<'b> <std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U: std::clone::Clone` is not satisfied
+ --> $DIR/hr-associated-type-bound-param-5.rs:28:14
+ |
+LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
+ | - required by a bound in this
+...
+LL | for<'b> <T::Next as X<'b, T::Next>>::U: Clone,
+ | ----- required by this bound in `X`
+...
+LL | type U = str;
+ | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U`
+ |
+ = help: the following implementations were found:
+ <&T as std::clone::Clone>
+ <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U: std::clone::Clone` is not satisfied
+ --> $DIR/hr-associated-type-bound-param-5.rs:28:14
+ |
+LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
+ | - required by a bound in this
+LL | where
+LL | for<'b> <T as X<'b, T>>::U: Clone,
+ | ----- required by this bound in `X`
+...
+LL | type U = str;
+ | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U`
+ |
+ = help: the following implementations were found:
+ <&T as std::clone::Clone>
+ <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U: std::clone::Clone` is not satisfied
+ --> $DIR/hr-associated-type-bound-param-5.rs:34:14
+ |
+LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
+ | - required by a bound in this
+...
+LL | for<'b> <T::Next as X<'b, T::Next>>::U: Clone,
+ | ----- required by this bound in `X`
+...
+LL | type U = str;
+ | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U`
+ |
+ = help: the following implementations were found:
+ <&T as std::clone::Clone>
+ <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U: std::clone::Clone` is not satisfied
+ --> $DIR/hr-associated-type-bound-param-5.rs:34:14
+ |
+LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
+ | - required by a bound in this
+LL | where
+LL | for<'b> <T as X<'b, T>>::U: Clone,
+ | ----- required by this bound in `X`
+...
+LL | type U = str;
+ | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U`
+ |
+ = help: the following implementations were found:
+ <&T as std::clone::Clone>
+ <&mut T as std::clone::Clone>
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+trait X<'a, T>
+where
+ for<'b> T: X<'b, T>,
+ for<'b> <T as X<'b, T>>::U: Clone,
+{
+ type U: ?Sized;
+ fn f(x: &<T as X<'_, T>>::U) {
+ <<T as X<'_, T>>::U>::clone(x);
+ }
+}
+
+impl<S, T> X<'_, T> for (S,) {
+ //~^ ERROR the trait bound `for<'b> T: X<'b, T>` is not satisfied
+ type U = str;
+ //~^ ERROR the trait bound `for<'b> <T as X<'b, T>>::U: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+ <(i32,) as X<i32>>::f("abc");
+}
--- /dev/null
+error[E0277]: the trait bound `for<'b> <T as X<'b, T>>::U: std::clone::Clone` is not satisfied
+ --> $DIR/hr-associated-type-bound-param-6.rs:14:14
+ |
+LL | trait X<'a, T>
+ | - required by a bound in this
+...
+LL | for<'b> <T as X<'b, T>>::U: Clone,
+ | ----- required by this bound in `X`
+...
+LL | type U = str;
+ | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<T as X<'b, T>>::U`
+ |
+ = help: the following implementations were found:
+ <&T as std::clone::Clone>
+ <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> T: X<'b, T>` is not satisfied
+ --> $DIR/hr-associated-type-bound-param-6.rs:12:12
+ |
+LL | trait X<'a, T>
+ | - required by a bound in this
+LL | where
+LL | for<'b> T: X<'b, T>,
+ | -------- required by this bound in `X`
+...
+LL | impl<S, T> X<'_, T> for (S,) {
+ | ^^^^^^^^ the trait `for<'b> X<'b, T>` is not implemented for `T`
+ |
+help: consider restricting type parameter `T`
+ |
+LL | impl<S, T: for<'b> X<'b, T>> X<'_, T> for (S,) {
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+trait UnsafeCopy<'a, T: Copy>
+where
+ for<'b> <Self as UnsafeCopy<'b, T>>::Item: std::ops::Deref<Target = T>,
+{
+ type Item;
+
+ fn bug(item: &Self::Item) -> () {
+ let x: T = **item;
+ &x as *const _;
+ }
+}
+
+impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
+ //~^ ERROR the trait bound `<T as UnsafeCopy<'b, T>>::Item: std::ops::Deref` is not satisfied
+ type Item = T;
+ //~^ ERROR the trait bound `for<'b> <T as UnsafeCopy<'b, T>>::Item: std::ops::Deref
+}
+
+pub fn main() {
+ <&'static str>::bug(&"");
+}
--- /dev/null
+error[E0277]: the trait bound `for<'b> <T as UnsafeCopy<'b, T>>::Item: std::ops::Deref` is not satisfied
+ --> $DIR/hr-associated-type-projection-1.rs:15:17
+ |
+LL | trait UnsafeCopy<'a, T: Copy>
+ | ---------- required by a bound in this
+LL | where
+LL | for<'b> <Self as UnsafeCopy<'b, T>>::Item: std::ops::Deref<Target = T>,
+ | --------------------------- required by this bound in `UnsafeCopy`
+...
+LL | type Item = T;
+ | ^ the trait `for<'b> std::ops::Deref` is not implemented for `<T as UnsafeCopy<'b, T>>::Item`
+ |
+ = help: the following implementations were found:
+ <&T as std::ops::Deref>
+ <&mut T as std::ops::Deref>
+
+error[E0277]: the trait bound `<T as UnsafeCopy<'b, T>>::Item: std::ops::Deref` is not satisfied
+ --> $DIR/hr-associated-type-projection-1.rs:13:33
+ |
+LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
+ | ^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `<T as UnsafeCopy<'b, T>>::Item`
+ |
+help: consider further restricting the associated type
+ |
+LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T where <T as UnsafeCopy<'b, T>>::Item: std::ops::Deref {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
use std::future::Future;
fn get_future() -> impl Future<Output = ()> {
-//~^ ERROR the trait bound `(): std::future::Future` is not satisfied
+//~^ ERROR `()` is not a future
panic!()
}
-error[E0277]: the trait bound `(): std::future::Future` is not satisfied
+error[E0277]: `()` is not a future
--> $DIR/async-error-span.rs:7:20
|
LL | fn get_future() -> impl Future<Output = ()> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
LL |
LL | panic!()
| -------- this returned value is of type `!`
|
+ = help: the trait `std::future::Future` is not implemented for `()`
= note: the return type of a function must have a statically known size
error[E0698]: type inside `async fn` body must be known in this context
[1; ().await];
//~^ error: `await` is only allowed inside `async` functions and blocks
//~| error: `.await` is not allowed in a `const`
- //~| error: `loop` is not allowed in a `const`
//~| error: `.await` is not allowed in a `const`
- //~| error: the trait bound `(): std::future::Future` is not satisfied
+ //~| error: `()` is not a future
}
fn main() {}
LL | [1; ().await];
| ^^^^^^^^
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/issue-70594.rs:4:9
- |
-LL | [1; ().await];
- | ^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
error[E0744]: `.await` is not allowed in a `const`
--> $DIR/issue-70594.rs:4:9
|
LL | [1; ().await];
| ^^^^^^^^
-error[E0277]: the trait bound `(): std::future::Future` is not satisfied
+error[E0277]: `()` is not a future
--> $DIR/issue-70594.rs:4:9
|
LL | [1; ().await];
- | ^^^^^^^^ the trait `std::future::Future` is not implemented for `()`
+ | ^^^^^^^^ `()` is not a future
|
+ = help: the trait `std::future::Future` is not implemented for `()`
= note: required by `std::future::Future::poll`
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0277, E0658, E0728, E0744.
+Some errors have detailed explanations: E0277, E0728, E0744.
For more information about an error, try `rustc --explain E0277`.
LL | (|_| 2333).await;
| ^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
-error[E0277]: the trait bound `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]: std::future::Future` is not satisfied
+error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
--> $DIR/issue-62009-1.rs:12:5
|
LL | (|_| 2333).await;
- | ^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
+ | ^^^^^^^^^^^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
|
+ = help: the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
= note: required by `std::future::Future::poll`
error: aborting due to 4 previous errors
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
--> $DIR/issue-62097.rs:12:31
|
LL | pub async fn run_dummy_fn(&self) {
| ^^^^^
| |
- | data with this lifetime...
+ | this data with an anonymous lifetime `'_`...
| ...is captured here...
LL | foo(|| self.bar()).await;
- | --- ...and required to be `'static` by this
+ | --- ...and is required to live as long as `'static` here
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0759`.
+++ /dev/null
-// run-pass
-
-#![allow(path_statements)]
-#![allow(dead_code)]
-macro_rules! auto {
- () => (struct S;)
-}
-
-auto!();
-
-fn auto() {}
-
-fn main() {
- auto();
- let auto = 10;
- auto;
- auto as u8;
-}
+++ /dev/null
-#![feature(optin_builtin_traits)]
-
-auto trait Generic<T> {}
-//~^ auto traits cannot have generic parameters [E0567]
-auto trait Bound : Copy {}
-//~^ auto traits cannot have super traits [E0568]
-auto trait MyTrait { fn foo() {} }
-//~^ auto traits cannot have methods or associated items [E0380]
-fn main() {}
+++ /dev/null
-error[E0567]: auto traits cannot have generic parameters
- --> $DIR/auto-trait-validation.rs:3:19
- |
-LL | auto trait Generic<T> {}
- | -------^^^ help: remove the parameters
- | |
- | auto trait cannot have generic parameters
-
-error[E0568]: auto traits cannot have super traits
- --> $DIR/auto-trait-validation.rs:5:20
- |
-LL | auto trait Bound : Copy {}
- | ----- ^^^^ help: remove the super traits
- | |
- | auto trait cannot have super traits
-
-error[E0380]: auto traits cannot have methods or associated items
- --> $DIR/auto-trait-validation.rs:7:25
- |
-LL | auto trait MyTrait { fn foo() {} }
- | ------- ^^^
- | |
- | auto trait cannot have items
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0380, E0567, E0568.
-For more information about an error, try `rustc --explain E0380`.
--- /dev/null
+// run-pass
+
+#![allow(path_statements)]
+#![allow(dead_code)]
+macro_rules! auto {
+ () => (struct S;)
+}
+
+auto!();
+
+fn auto() {}
+
+fn main() {
+ auto();
+ let auto = 10;
+ auto;
+ auto as u8;
+}
--- /dev/null
+// Checking the `Send` bound in `main` requires:
+//
+// checking <C<'static> as Y>::P: Send
+// which normalizes to Box<X<C<'?1>>>: Send
+// which needs X<C<'?1>>: Send
+// which needs <C<'?1> as Y>::P: Send
+//
+// At this point we used to normalize the predicate to `Box<X<C<'?2>>>: Send`
+// and continue in a loop where we created new region variables to the
+// recursion limit. To avoid this we now "canonicalize" region variables to
+// lowest unified region vid. This means we instead have to prove
+// `Box<X<C<'?1>>>: Send`, which we can because auto traits are coinductive.
+
+// check-pass
+
+// Avoid a really long error message if this regresses.
+#![recursion_limit="20"]
+
+trait Y {
+ type P;
+}
+
+impl<'a> Y for C<'a> {
+ type P = Box<X<C<'a>>>;
+}
+
+struct C<'a>(&'a ());
+struct X<T: Y>(T::P);
+
+fn is_send<S: Send>() {}
+
+fn main() {
+ is_send::<X<C<'static>>>();
+}
--- /dev/null
+#![feature(optin_builtin_traits)]
+
+auto trait Generic<T> {}
+//~^ auto traits cannot have generic parameters [E0567]
+auto trait Bound : Copy {}
+//~^ auto traits cannot have super traits [E0568]
+auto trait MyTrait { fn foo() {} }
+//~^ auto traits cannot have methods or associated items [E0380]
+fn main() {}
--- /dev/null
+error[E0567]: auto traits cannot have generic parameters
+ --> $DIR/auto-trait-validation.rs:3:19
+ |
+LL | auto trait Generic<T> {}
+ | -------^^^ help: remove the parameters
+ | |
+ | auto trait cannot have generic parameters
+
+error[E0568]: auto traits cannot have super traits
+ --> $DIR/auto-trait-validation.rs:5:20
+ |
+LL | auto trait Bound : Copy {}
+ | ----- ^^^^ help: remove the super traits
+ | |
+ | auto trait cannot have super traits
+
+error[E0380]: auto traits cannot have methods or associated items
+ --> $DIR/auto-trait-validation.rs:7:25
+ |
+LL | auto trait MyTrait { fn foo() {} }
+ | ------- ^^^
+ | |
+ | auto trait cannot have items
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0380, E0567, E0568.
+For more information about an error, try `rustc --explain E0380`.
--- /dev/null
+// run-pass
+#![allow(unused_doc_comments)]
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+auto trait Auto {}
+unsafe auto trait AutoUnsafe {}
+
+impl !Auto for bool {}
+impl !AutoUnsafe for bool {}
+
+struct AutoBool(bool);
+
+impl Auto for AutoBool {}
+unsafe impl AutoUnsafe for AutoBool {}
+
+fn take_auto<T: Auto>(_: T) {}
+fn take_auto_unsafe<T: AutoUnsafe>(_: T) {}
+
+fn main() {
+ // Parse inside functions.
+ auto trait AutoInner {}
+ unsafe auto trait AutoUnsafeInner {}
+
+ take_auto(0);
+ take_auto(AutoBool(true));
+ take_auto_unsafe(0);
+ take_auto_unsafe(AutoBool(true));
+
+ /// Auto traits are allowed in trait object bounds.
+ let _: &(dyn Send + Auto) = &0;
+}
--- /dev/null
+//~ ERROR
+
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+unsafe auto trait Trait {
+ type Output; //~ ERROR E0380
+}
+
+fn call_method<T: Trait>(x: T) {}
+
+fn main() {
+ // ICE
+ call_method(());
+}
--- /dev/null
+error[E0380]: auto traits cannot have methods or associated items
+ --> $DIR/issue-23080-2.rs:7:10
+ |
+LL | unsafe auto trait Trait {
+ | ----- auto trait cannot have items
+LL | type Output;
+ | ^^^^^^
+
+error[E0275]: overflow evaluating the requirement `<() as Trait>::Output`
+ |
+ = note: required because of the requirements on the impl of `Trait` for `()`
+ = note: required because of the requirements on the impl of `Trait` for `()`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0275, E0380.
+For more information about an error, try `rustc --explain E0275`.
--- /dev/null
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+unsafe auto trait Trait {
+ fn method(&self) { //~ ERROR E0380
+ println!("Hello");
+ }
+}
+
+fn call_method<T: Trait>(x: T) {
+ x.method();
+}
+
+fn main() {
+ // ICE
+ call_method(());
+}
--- /dev/null
+error[E0380]: auto traits cannot have methods or associated items
+ --> $DIR/issue-23080.rs:5:8
+ |
+LL | unsafe auto trait Trait {
+ | ----- auto trait cannot have items
+LL | fn method(&self) {
+ | ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0380`.
--- /dev/null
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+auto trait Magic : Sized where Option<Self> : Magic {} //~ ERROR E0568
+impl<T:Magic> Magic for T {}
+
+fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
+
+#[derive(Debug)]
+struct NoClone;
+
+fn main() {
+ let (a, b) = copy(NoClone);
+ println!("{:?} {:?}", a, b);
+}
--- /dev/null
+error[E0568]: auto traits cannot have super traits
+ --> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:20
+ |
+LL | auto trait Magic : Sized where Option<Self> : Magic {}
+ | ----- ^^^^^ help: remove the super traits
+ | |
+ | auto trait cannot have super traits
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0568`.
--- /dev/null
+// This test is for #29859, we need to ensure auto traits,
+// (also known previously as default traits), do not have
+// supertraits. Since the compiler synthesizes these
+// instances on demand, we are essentially enabling
+// users to write axioms if we view trait selection,
+// as a proof system.
+//
+// For example the below test allows us to add the rule:
+// forall (T : Type), T : Copy
+//
+// Providing a copy instance for *any* type, which
+// is most definitely unsound. Imagine copying a
+// type that contains a mutable reference, enabling
+// mutable aliasing.
+//
+// You can imagine an even more dangerous test,
+// which currently compiles on nightly.
+//
+// fn main() {
+// let mut i = 10;
+// let (a, b) = copy(&mut i);
+// println!("{:?} {:?}", a, b);
+// }
+
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+auto trait Magic: Copy {} //~ ERROR E0568
+impl<T:Magic> Magic for T {}
+
+fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
+
+#[derive(Debug)]
+struct NoClone;
+
+fn main() {
+ let (a, b) = copy(NoClone);
+ println!("{:?} {:?}", a, b);
+}
--- /dev/null
+error[E0568]: auto traits cannot have super traits
+ --> $DIR/typeck-auto-trait-no-supertraits.rs:28:19
+ |
+LL | auto trait Magic: Copy {}
+ | ----- ^^^^ help: remove the super traits
+ | |
+ | auto trait cannot have super traits
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0568`.
--- /dev/null
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+auto trait MyTrait {}
+
+struct MyS;
+
+struct MyS2;
+
+impl !MyTrait for MyS2 {}
+
+fn is_mytrait<T: MyTrait>() {}
+
+fn main() {
+ is_mytrait::<MyS>();
+
+ is_mytrait::<(MyS2, MyS)>();
+ //~^ ERROR `MyS2: MyTrait` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied in `(MyS2, MyS)`
+ --> $DIR/typeck-default-trait-impl-constituent-types-2.rs:17:5
+ |
+LL | fn is_mytrait<T: MyTrait>() {}
+ | ------- required by this bound in `is_mytrait`
+...
+LL | is_mytrait::<(MyS2, MyS)>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ within `(MyS2, MyS)`, the trait `MyTrait` is not implemented for `MyS2`
+ |
+ = help: the following implementations were found:
+ <MyS2 as MyTrait>
+ = note: required because it appears within the type `(MyS2, MyS)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+auto trait MyTrait {}
+
+impl<T> !MyTrait for *mut T {}
+
+struct MyS;
+
+struct MyS2;
+
+impl !MyTrait for MyS2 {}
+
+struct MyS3;
+
+fn is_mytrait<T: MyTrait>() {}
+
+fn main() {
+ is_mytrait::<MyS>();
+
+ is_mytrait::<MyS2>();
+ //~^ ERROR `MyS2: MyTrait` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied
+ --> $DIR/typeck-default-trait-impl-constituent-types.rs:21:18
+ |
+LL | fn is_mytrait<T: MyTrait>() {}
+ | ------- required by this bound in `is_mytrait`
+...
+LL | is_mytrait::<MyS2>();
+ | ^^^^ the trait `MyTrait` is not implemented for `MyS2`
+ |
+ = help: the following implementations were found:
+ <MyS2 as MyTrait>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+auto trait MyTrait {}
+
+unsafe auto trait MyUnsafeTrait {}
+
+struct ThisImplsTrait;
+
+impl !MyUnsafeTrait for ThisImplsTrait {}
+
+
+struct ThisImplsUnsafeTrait;
+
+impl !MyTrait for ThisImplsUnsafeTrait {}
+
+fn is_my_trait<T: MyTrait>() {}
+fn is_my_unsafe_trait<T: MyUnsafeTrait>() {}
+
+fn main() {
+ is_my_trait::<ThisImplsTrait>();
+ is_my_trait::<ThisImplsUnsafeTrait>();
+ //~^ ERROR `ThisImplsUnsafeTrait: MyTrait` is not satisfied
+
+ is_my_unsafe_trait::<ThisImplsTrait>();
+ //~^ ERROR `ThisImplsTrait: MyUnsafeTrait` is not satisfied
+
+ is_my_unsafe_trait::<ThisImplsUnsafeTrait>();
+}
--- /dev/null
+error[E0277]: the trait bound `ThisImplsUnsafeTrait: MyTrait` is not satisfied
+ --> $DIR/typeck-default-trait-impl-negation.rs:22:19
+ |
+LL | fn is_my_trait<T: MyTrait>() {}
+ | ------- required by this bound in `is_my_trait`
+...
+LL | is_my_trait::<ThisImplsUnsafeTrait>();
+ | ^^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `ThisImplsUnsafeTrait`
+ |
+ = help: the following implementations were found:
+ <ThisImplsUnsafeTrait as MyTrait>
+
+error[E0277]: the trait bound `ThisImplsTrait: MyUnsafeTrait` is not satisfied
+ --> $DIR/typeck-default-trait-impl-negation.rs:25:26
+ |
+LL | fn is_my_unsafe_trait<T: MyUnsafeTrait>() {}
+ | ------------- required by this bound in `is_my_unsafe_trait`
+...
+LL | is_my_unsafe_trait::<ThisImplsTrait>();
+ | ^^^^^^^^^^^^^^ the trait `MyUnsafeTrait` is not implemented for `ThisImplsTrait`
+ |
+ = help: the following implementations were found:
+ <ThisImplsTrait as MyUnsafeTrait>
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// Test that declaring that `&T` is `Defaulted` if `T:Signed` implies
+// that other `&T` is NOT `Defaulted` if `T:Signed` does not hold. In
+// other words, the auto impl only applies if there are no existing
+// impls whose types unify.
+
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+auto trait Defaulted { }
+impl<'a,T:Signed> Defaulted for &'a T { }
+impl<'a,T:Signed> Defaulted for &'a mut T { }
+fn is_defaulted<T:Defaulted>() { }
+
+trait Signed { }
+impl Signed for i32 { }
+
+fn main() {
+ is_defaulted::<&'static i32>();
+ is_defaulted::<&'static u32>();
+ //~^ ERROR `u32: Signed` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `u32: Signed` is not satisfied
+ --> $DIR/typeck-default-trait-impl-precedence.rs:19:5
+ |
+LL | fn is_defaulted<T:Defaulted>() { }
+ | --------- required by this bound in `is_defaulted`
+...
+LL | is_defaulted::<&'static u32>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`
+ |
+ = note: required because of the requirements on the impl of `Defaulted` for `&'static u32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// run-rustfix
+fn main() {
+ let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
+ let vr = v.iter().filter(|x| {
+ *x % 2 == 0
+ //~^ ERROR cannot mod `&&{integer}` by `{integer}`
+ });
+ println!("{:?}", vr);
+}
+// run-rustfix
fn main() {
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let vr = v.iter().filter(|x| {
error[E0369]: cannot mod `&&{integer}` by `{integer}`
- --> $DIR/binary-op-on-double-ref.rs:4:11
+ --> $DIR/binary-op-on-double-ref.rs:5:11
|
LL | x % 2 == 0
| - ^ - {integer}
| |
| &&{integer}
|
- = help: `%` can be used on '{integer}', you can dereference `x`: `*x`
+help: `%` can be used on `{integer}`, you can dereference `x`
+ |
+LL | *x % 2 == 0
+ | ^
error: aborting due to previous error
| ^^^^^ value moved here, in previous iteration of loop
|
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `maybe.0`
+ |
+LL | if let Some(ref thing) = maybe {
+ | ^^^
error: aborting due to previous error
struct Value;
static settings_dir: String = format!("");
-//~^ ERROR `match` is not allowed in a `static`
+//~^ ERROR calls in statics are limited to constant functions
+//~| ERROR calls in statics are limited to constant functions
fn from_string(_: String) -> Value {
Value
fn main() {
let settings_data = from_string(settings_dir);
+ //~^ ERROR cannot move out of static item
let args: i32 = 0;
match args {
-error[E0658]: `match` is not allowed in a `static`
+error[E0507]: cannot move out of static item `settings_dir`
+ --> $DIR/issue-64453.rs:14:37
+ |
+LL | let settings_data = from_string(settings_dir);
+ | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/issue-64453.rs:4:31
+ |
+LL | static settings_dir: String = format!("");
+ | ^^^^^^^^^^^
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
--> $DIR/issue-64453.rs:4:31
|
LL | static settings_dir: String = format!("");
| ^^^^^^^^^^^
|
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to previous error
+error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0015, E0507.
+For more information about an error, try `rustc --explain E0015`.
--- /dev/null
+// Issue #63988
+#[derive(Debug)]
+struct S;
+fn foo(_: Option<S>) {}
+
+enum E {
+ V {
+ s: S,
+ }
+}
+fn bar(_: E) {}
+
+fn main() {
+ let s = Some(S);
+ if let Some(mut x) = s {
+ x = S;
+ }
+ foo(s); //~ ERROR use of moved value: `s`
+ let mut e = E::V { s: S };
+ let E::V { s: mut x } = e;
+ x = S;
+ bar(e); //~ ERROR use of moved value: `e`
+}
--- /dev/null
+error[E0382]: use of moved value: `s`
+ --> $DIR/move-in-pattern-mut.rs:18:9
+ |
+LL | if let Some(mut x) = s {
+ | ----- value moved here
+...
+LL | foo(s);
+ | ^ value used here after partial move
+ |
+ = note: move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `s.0`
+ |
+LL | if let Some(ref mut x) = s {
+ | ^^^
+
+error[E0382]: use of moved value: `e`
+ --> $DIR/move-in-pattern-mut.rs:22:9
+ |
+LL | let E::V { s: mut x } = e;
+ | ----- value moved here
+LL | x = S;
+LL | bar(e);
+ | ^ value used here after partial move
+ |
+ = note: move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `e.s`
+ |
+LL | let E::V { s: ref mut x } = e;
+ | ^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+// run-rustfix
+// Issue #63988
+#[derive(Debug)]
+struct S;
+fn foo(_: Option<S>) {}
+
+enum E {
+ V {
+ s: S,
+ }
+}
+fn bar(_: E) {}
+
+fn main() {
+ let s = Some(S);
+ if let Some(ref x) = s {
+ let _ = x;
+ }
+ foo(s); //~ ERROR use of moved value: `s`
+ let e = E::V { s: S };
+ let E::V { s: ref x } = e;
+ let _ = x;
+ bar(e); //~ ERROR use of moved value: `e`
+}
--- /dev/null
+// run-rustfix
+// Issue #63988
+#[derive(Debug)]
+struct S;
+fn foo(_: Option<S>) {}
+
+enum E {
+ V {
+ s: S,
+ }
+}
+fn bar(_: E) {}
+
+fn main() {
+ let s = Some(S);
+ if let Some(x) = s {
+ let _ = x;
+ }
+ foo(s); //~ ERROR use of moved value: `s`
+ let e = E::V { s: S };
+ let E::V { s: x } = e;
+ let _ = x;
+ bar(e); //~ ERROR use of moved value: `e`
+}
--- /dev/null
+error[E0382]: use of moved value: `s`
+ --> $DIR/move-in-pattern.rs:19:9
+ |
+LL | if let Some(x) = s {
+ | - value moved here
+...
+LL | foo(s);
+ | ^ value used here after partial move
+ |
+ = note: move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `s.0`
+ |
+LL | if let Some(ref x) = s {
+ | ^^^
+
+error[E0382]: use of moved value: `e`
+ --> $DIR/move-in-pattern.rs:23:9
+ |
+LL | let E::V { s: x } = e;
+ | - value moved here
+LL | let _ = x;
+LL | bar(e);
+ | ^ value used here after partial move
+ |
+ = note: move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `e.s`
+ |
+LL | let E::V { s: ref x } = e;
+ | ^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+
+struct Events<R>(R);
+
+struct Other;
+
+pub trait Trait<T> {
+ fn handle(value: T) -> Self;
+}
+
+// Blanket impl. (If you comment this out, compiler figures out that it
+// is passing an `&mut` to a method that must be expecting an `&mut`,
+// and injects an auto-reborrow.)
+impl<T, U> Trait<U> for T where T: From<U> {
+ fn handle(_: U) -> Self { unimplemented!() }
+}
+
+impl<'a, R> Trait<&'a mut Events<R>> for Other {
+ fn handle(_: &'a mut Events<R>) -> Self { unimplemented!() }
+}
+
+fn this_compiles<'a, R>(value: &'a mut Events<R>) {
+ for _ in 0..3 {
+ Other::handle(&mut *value);
+ }
+}
+
+fn this_does_not<'a, R>(value: &'a mut Events<R>) {
+ for _ in 0..3 {
+ Other::handle(&mut *value); //~ ERROR use of moved value: `value`
+ }
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+
+struct Events<R>(R);
+
+struct Other;
+
+pub trait Trait<T> {
+ fn handle(value: T) -> Self;
+}
+
+// Blanket impl. (If you comment this out, compiler figures out that it
+// is passing an `&mut` to a method that must be expecting an `&mut`,
+// and injects an auto-reborrow.)
+impl<T, U> Trait<U> for T where T: From<U> {
+ fn handle(_: U) -> Self { unimplemented!() }
+}
+
+impl<'a, R> Trait<&'a mut Events<R>> for Other {
+ fn handle(_: &'a mut Events<R>) -> Self { unimplemented!() }
+}
+
+fn this_compiles<'a, R>(value: &'a mut Events<R>) {
+ for _ in 0..3 {
+ Other::handle(&mut *value);
+ }
+}
+
+fn this_does_not<'a, R>(value: &'a mut Events<R>) {
+ for _ in 0..3 {
+ Other::handle(value); //~ ERROR use of moved value: `value`
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0382]: use of moved value: `value`
+ --> $DIR/mut-borrow-in-loop-2.rs:31:23
+ |
+LL | fn this_does_not<'a, R>(value: &'a mut Events<R>) {
+ | ----- move occurs because `value` has type `&mut Events<R>`, which does not implement the `Copy` trait
+LL | for _ in 0..3 {
+LL | Other::handle(value);
+ | ^^^^^ value moved here, in previous iteration of loop
+ |
+help: consider creating a fresh reborrow of `value` here
+ |
+LL | Other::handle(&mut *value);
+ | ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
--> $DIR/cast-from-nil.rs:2:21
|
LL | fn main() { let u = (assert!(true) as u32); }
- | ^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to previous error
--> $DIR/cast-to-bare-fn.rs:5:13
|
LL | let x = foo as extern "C" fn() -> isize;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
error[E0605]: non-primitive cast: `u64` as `fn(isize) -> (isize, isize)`
--> $DIR/cast-to-bare-fn.rs:7:13
|
LL | let y = v as extern "Rust" fn(isize) -> (isize, isize);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
error: aborting due to 2 previous errors
--> $DIR/cast-to-nil.rs:2:21
|
LL | fn main() { let u = 0u32 as (); }
- | ^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to previous error
LL | Box::new(1) as dyn Send;
| ^^^^^^^^^^^^^^^--------
| |
- | help: try casting to a `Box` instead: `Box<dyn Send>`
+ | help: you can cast to a `Box` instead: `Box<dyn Send>`
error: aborting due to 2 previous errors
--- /dev/null
+#![deny(cenum_impl_drop_cast)]
+
+enum E {
+ A = 0,
+}
+
+impl Drop for E {
+ fn drop(&mut self) {
+ println!("Drop");
+ }
+}
+
+fn main() {
+ let e = E::A;
+ let i = e as u32;
+ //~^ ERROR cannot cast enum `E` into integer `u32` because it implements `Drop`
+ //~| WARN this was previously accepted
+}
--- /dev/null
+error: cannot cast enum `E` into integer `u32` because it implements `Drop`
+ --> $DIR/cenum_impl_drop_cast.rs:15:13
+ |
+LL | let i = e as u32;
+ | ^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/cenum_impl_drop_cast.rs:1:9
+ |
+LL | #![deny(cenum_impl_drop_cast)]
+ | ^^^^^^^^^^^^^^^^^^^^
+ = 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 #73333 <https://github.com/rust-lang/rust/issues/73333>
+
+error: aborting due to previous error
+
--- /dev/null
+// check-fail
+// compile-flags: -Z chalk
+
+fn main() -> () {
+ let t = || {};
+ t();
+
+ let mut a = 0;
+ let mut b = move || {
+ a = 1;
+ };
+ b();
+
+ let mut c = b;
+
+ c();
+ b();
+
+ let mut a = 0;
+ let mut b = || {
+ a = 1;
+ };
+ b();
+
+ let mut c = b;
+
+ c();
+ b(); //~ ERROR
+
+ // FIXME(chalk): this doesn't quite work
+ /*
+ let b = |c| {
+ c
+ };
+
+ let a = &32;
+ b(a);
+ */
+}
--- /dev/null
+error[E0382]: borrow of moved value: `b`
+ --> $DIR/closure.rs:28:5
+ |
+LL | let mut c = b;
+ | - value moved here
+...
+LL | b();
+ | ^ value borrowed here after move
+ |
+note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `a` out of its environment
+ --> $DIR/closure.rs:21:9
+ |
+LL | a = 1;
+ | ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
impl Foo for i32 { }
-// FIXME(chalk): blocked on better handling of builtin traits for non-struct
-// application types (or a workaround)
-/*
impl Foo for str { }
-//^ ERROR the size for values of type `str` cannot be known at compilation time
-*/
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+
// Implicit `T: Sized` bound.
impl<T> Foo for Option<T> { }
type Item = Option<T>;
}
-// FIXME(chalk): the ordering of these two errors differs between CI and local
-// We need to figure out why its non-deterministic
-/*
impl Bar for f32 {
-//^ ERROR the trait bound `f32: Foo` is not satisfied
type Item = f32;
- //^ ERROR the trait bound `f32: Foo` is not satisfied
+ //~^ ERROR the trait bound `f32: Foo` is not satisfied
}
-*/
trait Baz<U: ?Sized> where U: Foo { }
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+ --> $DIR/impl_wf.rs:11:6
+ |
+LL | trait Foo: Sized { }
+ | ----- required by this bound in `Foo`
+...
+LL | impl Foo for str { }
+ | ^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `str`
+ = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+
+error[E0277]: the trait bound `f32: Foo` is not satisfied
+ --> $DIR/impl_wf.rs:27:17
+ |
+LL | trait Bar {
+ | --- required by a bound in this
+LL | type Item: Foo;
+ | --- required by this bound in `Bar`
+...
+LL | type Item = f32;
+ | ^^^ the trait `Foo` is not implemented for `f32`
+
error[E0277]: the trait bound `f32: Foo` is not satisfied
- --> $DIR/impl_wf.rs:43:6
+ --> $DIR/impl_wf.rs:35:6
|
LL | trait Baz<U: ?Sized> where U: Foo { }
| --- required by this bound in `Baz`
LL | impl Baz<f32> for f32 { }
| ^^^^^^^^ the trait `Foo` is not implemented for `f32`
-error: aborting due to previous error
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.
x: 5,
};
- s.dummy_foo();
s.dummy_bar::<u32>();
+ s.dummy_foo();
}
// FIXME(chalk): should fail, see comments
-// check-pass
+// check-fail
// compile-flags: -Z chalk
#![feature(trivial_bounds)]
trait Foo: Bar { }
struct S where S: Foo;
-//~^ WARN Trait bound S: Foo does not depend on any type or lifetime parameters
impl Foo for S {
}
fn main() {
// For some reason, the error is duplicated...
- // FIXME(chalk): this order of this duplicate error seems non-determistic
- // and causes test to fail
- /*
- foo::<S>() // ERROR the type `S` is not well-formed (chalk)
- //^ ERROR the type `S` is not well-formed (chalk)
- */
+ foo::<S>() //~ ERROR the type `S` is not well-formed (chalk)
+ //~^ ERROR the type `S` is not well-formed (chalk)
}
-warning: Trait bound S: Foo does not depend on any type or lifetime parameters
- --> $DIR/recursive_where_clause_on_type.rs:12:19
+error: the type `S` is not well-formed (chalk)
+ --> $DIR/recursive_where_clause_on_type.rs:28:11
|
-LL | struct S where S: Foo;
- | ^^^
+LL | foo::<S>()
+ | ^
+
+error: the type `S` is not well-formed (chalk)
+ --> $DIR/recursive_where_clause_on_type.rs:28:5
|
- = note: `#[warn(trivial_bounds)]` on by default
+LL | foo::<S>()
+ | ^^^^^^^^
-warning: 1 warning emitted
+error: aborting due to 2 previous errors
// is expecting a variable of type `i32`. This behavior differs from the
// old-style trait solver. I guess this will change, that's why I'm
// adding that test.
- // FIXME(chalk): partially blocked on float/int special casing
- only_foo(x); //~ ERROR the trait bound `f64: Foo` is not satisfied
+ // FIXME(chalk): order of these two errors is non-deterministic,
+ // so let's just hide one for now
+ //only_foo(x); // ERROR the trait bound `f64: Foo` is not satisfied
// Here we have two solutions so we get back the behavior of the old-style
// trait solver.
- // FIXME(chalk): blocked on float/int special casing
- //only_bar(x); // ERROR the trait bound `{float}: Bar` is not satisfied
+ only_bar(x); //~ ERROR the trait bound `f64: Bar` is not satisfied
}
-error[E0277]: the trait bound `f64: Foo` is not satisfied
- --> $DIR/type_inference.rs:22:5
+error[E0277]: the trait bound `f64: Bar` is not satisfied
+ --> $DIR/type_inference.rs:27:5
|
-LL | fn only_foo<T: Foo>(_x: T) { }
- | --- required by this bound in `only_foo`
+LL | fn only_bar<T: Bar>(_x: T) { }
+ | --- required by this bound in `only_bar`
...
-LL | only_foo(x);
- | ^^^^^^^^ the trait `Foo` is not implemented for `f64`
+LL | only_bar(x);
+ | ^^^^^^^^ the trait `Bar` is not implemented for `f64`
error: aborting due to previous error
-// FIXME(chalk): should have an error, see below
-// check-pass
+// check-fail
// compile-flags: -Z chalk
trait Foo { }
x: 5,
};
- // FIXME(chalk): blocked on float/int special handling. Needs to know that {float}: !i32
- /*
- let s = S { // ERROR the trait bound `{float}: Foo` is not satisfied
+ let s = S { //~ ERROR the trait bound `f64: Foo` is not satisfied
x: 5.0,
};
- */
- // FIXME(chalk): blocked on float/int special handling. Needs to know that {float}: Sized
- /*
let s = S {
x: Some(5.0),
};
- */
}
--- /dev/null
+error[E0277]: the trait bound `f64: Foo` is not satisfied
+ --> $DIR/type_wf.rs:18:13
+ |
+LL | struct S<T: Foo> {
+ | ---------------- required by `S`
+...
+LL | let s = S {
+ | ^ the trait `Foo` is not implemented for `f64`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
// Checks that immutable static items can't have mutable slices
static TEST: &'static mut [isize] = &mut [];
-//~^ ERROR references in statics may only refer to immutable values
+//~^ ERROR mutable references are not allowed in statics
pub fn main() { }
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
--> $DIR/check-static-immutable-mut-slices.rs:3:37
|
LL | static TEST: &'static mut [isize] = &mut [];
- | ^^^^^^^ statics require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^^ `&mut` is only allowed in `const fn`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0764`.
| ___________________________________________^
LL | |
LL | | field2: SafeEnum::Variant1}};
- | |________________________________________________________________________________^ statics cannot evaluate destructors
+ | | ^- value is dropped here
+ | |________________________________________________________________________________|
+ | statics cannot evaluate destructors
error[E0010]: allocations are not allowed in statics
--> $DIR/check-static-values-constraints.rs:79:33
-error[E0631]: type mismatch in closure arguments
- --> $DIR/expect-fn-supply-fn.rs:30:5
+error: lifetime may not live long enough
+ --> $DIR/expect-fn-supply-fn.rs:16:49
|
-LL | fn with_closure_expecting_fn_with_free_region<F>(_: F)
- | ------------------------------------------ required by a bound in this
-LL | where F: for<'a> FnOnce(fn(&'a u32), &i32)
- | ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region`
+LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
+ | -- lifetime `'x` defined here
...
-LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _`
- | |
- | expected signature of `fn(fn(&'a u32), &i32) -> _`
+LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
+ | ^
+ | |
+ | has type `fn(&'1 u32)`
+ | requires that `'1` must outlive `'x`
-error[E0631]: type mismatch in closure arguments
- --> $DIR/expect-fn-supply-fn.rs:37:5
+error: lifetime may not live long enough
+ --> $DIR/expect-fn-supply-fn.rs:16:49
|
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
- | ------------------------------------------- required by a bound in this
-LL | where F: FnOnce(fn(&u32), &i32)
- | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
+LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
+ | -- lifetime `'x` defined here
...
+LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
+ | ^ requires that `'x` must outlive `'static`
+ |
+ = help: consider replacing `'x` with `'static`
+
+error: higher-ranked subtype error
+ --> $DIR/expect-fn-supply-fn.rs:32:49
+ |
+LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
+ | ^
+
+error: higher-ranked subtype error
+ --> $DIR/expect-fn-supply-fn.rs:39:50
+ |
LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _`
- | |
- | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+ | ^
-error[E0631]: type mismatch in closure arguments
- --> $DIR/expect-fn-supply-fn.rs:46:5
+error: higher-ranked subtype error
+ --> $DIR/expect-fn-supply-fn.rs:48:50
|
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
- | ------------------------------------------- required by a bound in this
-LL | where F: FnOnce(fn(&u32), &i32)
- | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
-...
LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _`
- | |
- | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+ | ^
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
-For more information about this error, try `rustc --explain E0631`.
fn with_closure_expecting_fn_with_free_region<F>(_: F)
- where F: for<'a> FnOnce(fn(&'a u32), &i32)
+where
+ F: for<'a> FnOnce(fn(&'a u32), &i32),
{
}
fn with_closure_expecting_fn_with_bound_region<F>(_: F)
- where F: FnOnce(fn(&u32), &i32)
+where
+ F: FnOnce(fn(&u32), &i32),
{
}
// Here, we are given a function whose region is bound at closure level,
// but we expect one bound in the argument. Error results.
with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
- //~^ ERROR type mismatch
+ //~^ ERROR mismatched types
}
fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) {
// Here, we are given a `fn(&u32)` but we expect a `fn(&'x
// u32)`. In principle, this could be ok, but we demand equality.
with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
- //~^ ERROR type mismatch
+ //~^ ERROR mismatched types
}
fn expect_bound_supply_free_from_closure() {
// the argument level.
type Foo<'a> = fn(&'a u32);
with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
- //~^ ERROR type mismatch
+ //~^ ERROR mismatched types
});
}
// No error in this case. The supplied type supplies the bound
// regions, and hence we are able to figure out the type of `y`
// from the expected type
- with_closure_expecting_fn_with_bound_region(|x: for<'z> fn(&'z u32), y| {
- });
+ with_closure_expecting_fn_with_bound_region(|x: for<'z> fn(&'z u32), y| {});
}
-fn main() { }
+fn main() {}
error[E0308]: mismatched types
- --> $DIR/expect-fn-supply-fn.rs:14:52
+ --> $DIR/expect-fn-supply-fn.rs:16:52
|
LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
| ^^^^^^^^^^^ lifetime mismatch
|
= note: expected fn pointer `fn(&u32)`
found fn pointer `fn(&'x u32)`
-note: the anonymous lifetime #2 defined on the body at 14:48...
- --> $DIR/expect-fn-supply-fn.rs:14:48
+note: the anonymous lifetime #2 defined on the body at 16:48...
+ --> $DIR/expect-fn-supply-fn.rs:16:48
|
LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
| ^^^^^^^^^^^^^^^^^^^^^^
-note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 11:36
- --> $DIR/expect-fn-supply-fn.rs:11:36
+note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 13:36
+ --> $DIR/expect-fn-supply-fn.rs:13:36
|
LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
| ^^
error[E0308]: mismatched types
- --> $DIR/expect-fn-supply-fn.rs:14:52
+ --> $DIR/expect-fn-supply-fn.rs:16:52
|
LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
| ^^^^^^^^^^^ lifetime mismatch
|
= note: expected fn pointer `fn(&u32)`
found fn pointer `fn(&'x u32)`
-note: the lifetime `'x` as defined on the function body at 11:36...
- --> $DIR/expect-fn-supply-fn.rs:11:36
+note: the lifetime `'x` as defined on the function body at 13:36...
+ --> $DIR/expect-fn-supply-fn.rs:13:36
|
LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
| ^^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 14:48
- --> $DIR/expect-fn-supply-fn.rs:14:48
+note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 16:48
+ --> $DIR/expect-fn-supply-fn.rs:16:48
|
LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
| ^^^^^^^^^^^^^^^^^^^^^^
-error[E0631]: type mismatch in closure arguments
- --> $DIR/expect-fn-supply-fn.rs:30:5
+error[E0308]: mismatched types
+ --> $DIR/expect-fn-supply-fn.rs:32:52
|
-LL | fn with_closure_expecting_fn_with_free_region<F>(_: F)
- | ------------------------------------------ required by a bound in this
-LL | where F: for<'a> FnOnce(fn(&'a u32), &i32)
- | ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region`
-...
LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _`
- | |
- | expected signature of `fn(fn(&'a u32), &i32) -> _`
+ | ^^^^^^^^ one type is more general than the other
+ |
+ = note: expected fn pointer `fn(&u32)`
+ found fn pointer `for<'r> fn(&'r u32)`
-error[E0631]: type mismatch in closure arguments
- --> $DIR/expect-fn-supply-fn.rs:37:5
+error[E0308]: mismatched types
+ --> $DIR/expect-fn-supply-fn.rs:39:53
|
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
- | ------------------------------------------- required by a bound in this
-LL | where F: FnOnce(fn(&u32), &i32)
- | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
-...
LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _`
- | |
- | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+ | ^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected fn pointer `for<'r> fn(&'r u32)`
+ found fn pointer `fn(&'x u32)`
-error[E0631]: type mismatch in closure arguments
- --> $DIR/expect-fn-supply-fn.rs:46:5
+error[E0308]: mismatched types
+ --> $DIR/expect-fn-supply-fn.rs:48:53
|
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
- | ------------------------------------------- required by a bound in this
-LL | where F: FnOnce(fn(&u32), &i32)
- | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
-...
LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _`
- | |
- | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+ | ^^^^^^^ one type is more general than the other
+ |
+ = note: expected fn pointer `for<'r> fn(&'r u32)`
+ found fn pointer `fn(&u32)`
error: aborting due to 5 previous errors
-Some errors have detailed explanations: E0308, E0631.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0308`.
error[E0282]: type annotations needed
- --> $DIR/expect-two-infer-vars-supply-ty-with-bound-region.rs:8:27
+ --> $DIR/expect-two-infer-vars-supply-ty-with-bound-region.rs:8:5
|
LL | with_closure(|x: u32, y| {});
- | ^ consider giving this closure parameter a type
+ | ^^^^^^^^^^^^ cannot infer type for type parameter `B` declared on the function `with_closure`
error: aborting due to previous error
--> $DIR/closure-no-fn-3.rs:6:27
|
LL | let baz: fn() -> u8 = (|| { b }) as fn() -> u8;
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
error: aborting due to previous error
}
fn main() {
- (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
+ (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
//~^ ERROR: type mismatch in closure arguments
- //~| ERROR: type mismatch resolving
}
error[E0631]: type mismatch in closure arguments
--> $DIR/issue-41366.rs:10:5
|
-LL | (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
- | ^^-----^
+LL | (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
+ | ^^------^
| | |
- | | found signature of `fn(_) -> _`
- | expected signature of `for<'x> fn(<u32 as T<'x>>::V) -> _`
+ | | found signature of `fn(u16) -> _`
+ | expected signature of `fn(<u32 as T<'x>>::V) -> _`
|
= note: required for the cast to the object type `dyn for<'x> std::ops::Fn(<u32 as T<'x>>::V)`
-error[E0271]: type mismatch resolving `for<'x> <[closure@$DIR/issue-41366.rs:10:7: 10:12] as std::ops::FnOnce<(<u32 as T<'x>>::V,)>>::Output == ()`
- --> $DIR/issue-41366.rs:10:5
- |
-LL | (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
- | ^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
- |
- = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(<u32 as T<'x>>::V)`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0631`.
fn main() {
[(); &(&'static: loop { |x| {}; }) as *const _ as usize]
//~^ ERROR: invalid label name `'static`
- //~| ERROR: `loop` is not allowed in a `const`
//~| ERROR: type annotations needed
//~| ERROR mismatched types
}
LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
| ^^^^^^^
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/issue-52437.rs:2:13
- |
-LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
error[E0282]: type annotations needed
--> $DIR/issue-52437.rs:2:30
|
LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[(); _]`
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0282, E0308, E0658.
+Some errors have detailed explanations: E0282, E0308.
For more information about an error, try `rustc --explain E0282`.
-error: unterminated double quote string
+error[E0765]: unterminated double quote string
--> $DIR/tab_2.rs:4:7
|
LL | """;
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0765`.
+++ /dev/null
-// run-pass
-#![allow(unused_braces)]
-#![feature(box_syntax)]
-
-use std::cell::RefCell;
-use std::fmt::Debug;
-use std::rc::Rc;
-
-// Check that coercions apply at the pointer level and don't cause
-// rvalue expressions to be unsized. See #20169 for more information.
-
-pub fn main() {
- let _: Box<[isize]> = Box::new({ [1, 2, 3] });
- let _: Box<[isize]> = Box::new(if true { [1, 2, 3] } else { [1, 3, 4] });
- let _: Box<[isize]> = Box::new(match true { true => [1, 2, 3], false => [1, 3, 4] });
- let _: Box<dyn Fn(isize) -> _> = Box::new({ |x| (x as u8) });
- let _: Box<dyn Debug> = Box::new(if true { false } else { true });
- let _: Box<dyn Debug> = Box::new(match true { true => 'a', false => 'b' });
-
- let _: &[isize] = &{ [1, 2, 3] };
- let _: &[isize] = &if true { [1, 2, 3] } else { [1, 3, 4] };
- let _: &[isize] = &match true { true => [1, 2, 3], false => [1, 3, 4] };
- let _: &dyn Fn(isize) -> _ = &{ |x| (x as u8) };
- let _: &dyn Debug = &if true { false } else { true };
- let _: &dyn Debug = &match true { true => 'a', false => 'b' };
-
- let _: &str = &{ String::new() };
- let _: &str = &if true { String::from("...") } else { 5.to_string() };
- let _: &str = &match true {
- true => format!("{}", false),
- false => ["x", "y"].join("+")
- };
-
- let _: Box<[isize]> = Box::new([1, 2, 3]);
- let _: Box<dyn Fn(isize) -> _> = Box::new(|x| (x as u8));
-
- let _: Rc<RefCell<[isize]>> = Rc::new(RefCell::new([1, 2, 3]));
- let _: Rc<RefCell<dyn FnMut(isize) -> _>> = Rc::new(RefCell::new(|x| (x as u8)));
-
- let _: Vec<Box<dyn Fn(isize) -> _>> = vec![
- Box::new(|x| (x as u8)),
- Box::new(|x| (x as i16 as u8)),
- ];
-}
+++ /dev/null
-// run-pass
-#![allow(unused_braces)]
-#![allow(dead_code)]
-// pretty-expanded FIXME #23616
-
-use std::rc::Rc;
-
-// Examples from the "deref coercions" RFC, at rust-lang/rfcs#241.
-
-fn use_ref<T>(_: &T) {}
-fn use_mut<T>(_: &mut T) {}
-
-fn use_rc<T>(t: Rc<T>) {
- use_ref(&*t); // what you have to write today
- use_ref(&t); // what you'd be able to write
- use_ref(&&&&&&t);
- use_ref(&mut &&&&&t);
- use_ref(&&&mut &&&t);
-}
-
-fn use_mut_box<T>(mut t: &mut Box<T>) {
- use_mut(&mut *t); // what you have to write today
- use_mut(t); // what you'd be able to write
- use_mut(&mut &mut &mut t);
-
- use_ref(&*t); // what you have to write today
- use_ref(t); // what you'd be able to write
- use_ref(&&&&&&t);
- use_ref(&mut &&&&&t);
- use_ref(&&&mut &&&t);
-}
-
-fn use_nested<T>(t: &Box<T>) {
- use_ref(&**t); // what you have to write today
- use_ref(t); // what you'd be able to write (note: recursive deref)
- use_ref(&&&&&&t);
- use_ref(&mut &&&&&t);
- use_ref(&&&mut &&&t);
-}
-
-fn use_slice(_: &[u8]) {}
-fn use_slice_mut(_: &mut [u8]) {}
-
-fn use_vec(mut v: Vec<u8>) {
- use_slice_mut(&mut v[..]); // what you have to write today
- use_slice_mut(&mut v); // what you'd be able to write
- use_slice_mut(&mut &mut &mut v);
-
- use_slice(&v[..]); // what you have to write today
- use_slice(&v); // what you'd be able to write
- use_slice(&&&&&&v);
- use_slice(&mut &&&&&v);
- use_slice(&&&mut &&&v);
-}
-
-fn use_vec_ref(v: &Vec<u8>) {
- use_slice(&v[..]); // what you have to write today
- use_slice(v); // what you'd be able to write
- use_slice(&&&&&&v);
- use_slice(&mut &&&&&v);
- use_slice(&&&mut &&&v);
-}
-
-fn use_op_rhs(s: &mut String) {
- *s += {&String::from(" ")};
-}
-
-pub fn main() {}
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-// pretty-expanded FIXME #23616
-
-fn negate(x: &isize) -> isize {
- -*x
-}
-
-fn negate_mut(y: &mut isize) -> isize {
- negate(y)
-}
-
-fn negate_imm(y: &isize) -> isize {
- negate(y)
-}
-
-pub fn main() {}
+++ /dev/null
-// run-pass
-
-struct SpeechMaker {
- speeches: usize
-}
-
-impl SpeechMaker {
- pub fn how_many(&self) -> usize { self.speeches }
-}
-
-fn foo(speaker: &SpeechMaker) -> usize {
- speaker.how_many() + 33
-}
-
-pub fn main() {
- let lincoln = SpeechMaker {speeches: 22};
- assert_eq!(foo(&lincoln), 55);
-}
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-// pretty-expanded FIXME #23616
-
-fn sum(x: &[isize]) -> isize {
- let mut sum = 0;
- for y in x { sum += *y; }
- return sum;
-}
-
-fn sum_mut(y: &mut [isize]) -> isize {
- sum(y)
-}
-
-fn sum_imm(y: &[isize]) -> isize {
- sum(y)
-}
-
-pub fn main() {}
+++ /dev/null
-// run-pass
-
-
-fn bar(v: &mut [usize]) -> Vec<usize> {
- v.to_vec()
-}
-
-fn bip(v: &[usize]) -> Vec<usize> {
- v.to_vec()
-}
-
-pub fn main() {
- let mut the_vec = vec![1, 2, 3, 100];
- assert_eq!(the_vec.clone(), bar(&mut the_vec));
- assert_eq!(the_vec.clone(), bip(&the_vec));
-}
+++ /dev/null
-// run-pass
-// pretty-expanded FIXME #23616
-
-struct SpeechMaker {
- speeches: usize
-}
-
-fn talk(x: &mut SpeechMaker) {
- x.speeches += 1;
-}
-
-fn give_a_few_speeches(speaker: &mut SpeechMaker) {
-
- // Here speaker is reborrowed for each call, so we don't get errors
- // about speaker being moved.
-
- talk(speaker);
- talk(speaker);
- talk(speaker);
-}
-
-pub fn main() {
- let mut lincoln = SpeechMaker {speeches: 22};
- give_a_few_speeches(&mut lincoln);
-}
+++ /dev/null
-// run-pass
-// pretty-expanded FIXME #23616
-
-struct SpeechMaker {
- speeches: usize
-}
-
-impl SpeechMaker {
- pub fn talk(&mut self) {
- self.speeches += 1;
- }
-}
-
-fn give_a_few_speeches(speaker: &mut SpeechMaker) {
-
- // Here speaker is reborrowed for each call, so we don't get errors
- // about speaker being moved.
-
- speaker.talk();
- speaker.talk();
- speaker.talk();
-}
-
-pub fn main() {
- let mut lincoln = SpeechMaker {speeches: 22};
- give_a_few_speeches(&mut lincoln);
-}
+++ /dev/null
-// run-pass
-
-
-fn reverse(v: &mut [usize]) {
- v.reverse();
-}
-
-fn bar(v: &mut [usize]) {
- reverse(v);
- reverse(v);
- reverse(v);
-}
-
-pub fn main() {
- let mut the_vec = vec![1, 2, 3, 100];
- bar(&mut the_vec);
- assert_eq!(the_vec, [100, 3, 2, 1]);
-}
+++ /dev/null
-// run-pass
-
-
-fn bar(v: &mut [usize]) {
- v.reverse();
- v.reverse();
- v.reverse();
-}
-
-pub fn main() {
- let mut the_vec = vec![1, 2, 3, 100];
- bar(&mut the_vec);
- assert_eq!(the_vec, [100, 3, 2, 1]);
-}
+++ /dev/null
-// run-pass
-// Check that coercions unify the expected return type of a polymorphic
-// function call, instead of leaving the type variables as they were.
-
-// pretty-expanded FIXME #23616
-
-struct Foo;
-impl Foo {
- fn foo<T>(self, x: T) -> Option<T> { Some(x) }
-}
-
-pub fn main() {
- let _: Option<fn()> = Some(main);
- let _: Option<fn()> = Foo.foo(main);
-
- // The same two cases, with implicit type variables made explicit.
- let _: Option<fn()> = Some::<_>(main);
- let _: Option<fn()> = Foo.foo::<_>(main);
-}
+++ /dev/null
-// run-pass
-// Check that coercions can unify if-else, match arms and array elements.
-
-// Try to construct if-else chains, matches and arrays out of given expressions.
-macro_rules! check {
- ($last:expr $(, $rest:expr)+) => {
- // Last expression comes first because of whacky ifs and matches.
- let _ = $(if false { $rest })else+ else { $last };
-
- let _ = match 0 { $(_ if false => $rest,)+ _ => $last };
-
- let _ = [$($rest,)+ $last];
- }
-}
-
-// Check all non-uniform cases of 2 and 3 expressions of 2 types.
-macro_rules! check2 {
- ($a:expr, $b:expr) => {
- check!($a, $b);
- check!($b, $a);
-
- check!($a, $a, $b);
- check!($a, $b, $a);
- check!($a, $b, $b);
-
- check!($b, $a, $a);
- check!($b, $a, $b);
- check!($b, $b, $a);
- }
-}
-
-// Check all non-uniform cases of 2 and 3 expressions of 3 types.
-macro_rules! check3 {
- ($a:expr, $b:expr, $c:expr) => {
- // Delegate to check2 for cases where a type repeats.
- check2!($a, $b);
- check2!($b, $c);
- check2!($a, $c);
-
- // Check the remaining cases, i.e., permutations of ($a, $b, $c).
- check!($a, $b, $c);
- check!($a, $c, $b);
- check!($b, $a, $c);
- check!($b, $c, $a);
- check!($c, $a, $b);
- check!($c, $b, $a);
- }
-}
-
-use std::mem::size_of;
-
-fn foo() {}
-fn bar() {}
-
-pub fn main() {
- check3!(foo, bar, foo as fn());
- check3!(size_of::<u8>, size_of::<u16>, size_of::<usize> as fn() -> usize);
-
- let s = String::from("bar");
- check2!("foo", &s);
-
- let a = [1, 2, 3];
- let v = vec![1, 2, 3];
- check2!(&a[..], &v);
-
- // Make sure in-array coercion still works.
- let _ = [("a", Default::default()), (Default::default(), "b"), (&s, &s)];
-}
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-// pretty-expanded FIXME #23616
-
-use std::rc::Rc;
-
-fn lub_short<'a, T>(_: &[&'a T], _: &[&'a T]) {}
-
-// The two arguments are a subtype of their LUB, after coercion.
-fn long_and_short<'a, T>(xs: &[&'static T; 1], ys: &[&'a T; 1]) {
- lub_short(xs, ys);
-}
-
-// The argument coerces to a subtype of the return type.
-fn long_to_short<'a, 'b, T>(xs: &'b [&'static T; 1]) -> &'b [&'a T] {
- xs
-}
-
-// Rc<T> is covariant over T just like &T.
-fn long_to_short_rc<'a, T>(xs: Rc<[&'static T; 1]>) -> Rc<[&'a T]> {
- xs
-}
-
-// LUB-coercion (if-else/match/array) coerces `xs: &'b [&'static T: N]`
-// to a subtype of the LUB of `xs` and `ys` (i.e., `&'b [&'a T]`),
-// regardless of the order they appear (in if-else/match/array).
-fn long_and_short_lub1<'a, 'b, T>(xs: &'b [&'static T; 1], ys: &'b [&'a T]) {
- let _order1 = [xs, ys];
- let _order2 = [ys, xs];
-}
-
-// LUB-coercion should also have the exact same effect when `&'b [&'a T; N]`
-// needs to be coerced, i.e., the resulting type is not &'b [&'static T], but
-// rather the `&'b [&'a T]` LUB.
-fn long_and_short_lub2<'a, 'b, T>(xs: &'b [&'static T], ys: &'b [&'a T; 1]) {
- let _order1 = [xs, ys];
- let _order2 = [ys, xs];
-}
-
-fn main() {}
--- /dev/null
+// run-pass
+#![allow(unused_braces)]
+#![feature(box_syntax)]
+
+use std::cell::RefCell;
+use std::fmt::Debug;
+use std::rc::Rc;
+
+// Check that coercions apply at the pointer level and don't cause
+// rvalue expressions to be unsized. See #20169 for more information.
+
+pub fn main() {
+ let _: Box<[isize]> = Box::new({ [1, 2, 3] });
+ let _: Box<[isize]> = Box::new(if true { [1, 2, 3] } else { [1, 3, 4] });
+ let _: Box<[isize]> = Box::new(match true { true => [1, 2, 3], false => [1, 3, 4] });
+ let _: Box<dyn Fn(isize) -> _> = Box::new({ |x| (x as u8) });
+ let _: Box<dyn Debug> = Box::new(if true { false } else { true });
+ let _: Box<dyn Debug> = Box::new(match true { true => 'a', false => 'b' });
+
+ let _: &[isize] = &{ [1, 2, 3] };
+ let _: &[isize] = &if true { [1, 2, 3] } else { [1, 3, 4] };
+ let _: &[isize] = &match true { true => [1, 2, 3], false => [1, 3, 4] };
+ let _: &dyn Fn(isize) -> _ = &{ |x| (x as u8) };
+ let _: &dyn Debug = &if true { false } else { true };
+ let _: &dyn Debug = &match true { true => 'a', false => 'b' };
+
+ let _: &str = &{ String::new() };
+ let _: &str = &if true { String::from("...") } else { 5.to_string() };
+ let _: &str = &match true {
+ true => format!("{}", false),
+ false => ["x", "y"].join("+")
+ };
+
+ let _: Box<[isize]> = Box::new([1, 2, 3]);
+ let _: Box<dyn Fn(isize) -> _> = Box::new(|x| (x as u8));
+
+ let _: Rc<RefCell<[isize]>> = Rc::new(RefCell::new([1, 2, 3]));
+ let _: Rc<RefCell<dyn FnMut(isize) -> _>> = Rc::new(RefCell::new(|x| (x as u8)));
+
+ let _: Vec<Box<dyn Fn(isize) -> _>> = vec![
+ Box::new(|x| (x as u8)),
+ Box::new(|x| (x as i16 as u8)),
+ ];
+}
--- /dev/null
+fn borrow_mut<T>(x: &mut T) -> &mut T { x }
+fn borrow<T>(x: &T) -> &T { x }
+
+fn borrow_mut2<T>(_: &mut T, _: &mut T) {}
+fn borrow2<T>(_: &mut T, _: &T) {}
+
+fn double_mut_borrow<T>(x: &mut Box<T>) {
+ let y = borrow_mut(x);
+ let z = borrow_mut(x);
+ //~^ ERROR cannot borrow `*x` as mutable more than once at a time
+ drop((y, z));
+}
+
+fn double_imm_borrow(x: &mut Box<i32>) {
+ let y = borrow(x);
+ let z = borrow(x);
+ **x += 1;
+ //~^ ERROR cannot assign to `**x` because it is borrowed
+ drop((y, z));
+}
+
+fn double_mut_borrow2<T>(x: &mut Box<T>) {
+ borrow_mut2(x, x);
+ //~^ ERROR cannot borrow `*x` as mutable more than once at a time
+}
+
+fn double_borrow2<T>(x: &mut Box<T>) {
+ borrow2(x, x);
+ //~^ ERROR cannot borrow `*x` as mutable because it is also borrowed as immutable
+}
+
+pub fn main() {}
--- /dev/null
+error[E0499]: cannot borrow `*x` as mutable more than once at a time
+ --> $DIR/coerce-overloaded-autoderef-fail.rs:9:24
+ |
+LL | let y = borrow_mut(x);
+ | - first mutable borrow occurs here
+LL | let z = borrow_mut(x);
+ | ^ second mutable borrow occurs here
+LL |
+LL | drop((y, z));
+ | - first borrow later used here
+
+error[E0506]: cannot assign to `**x` because it is borrowed
+ --> $DIR/coerce-overloaded-autoderef-fail.rs:17:5
+ |
+LL | let y = borrow(x);
+ | - borrow of `**x` occurs here
+LL | let z = borrow(x);
+LL | **x += 1;
+ | ^^^^^^^^ assignment to borrowed `**x` occurs here
+LL |
+LL | drop((y, z));
+ | - borrow later used here
+
+error[E0499]: cannot borrow `*x` as mutable more than once at a time
+ --> $DIR/coerce-overloaded-autoderef-fail.rs:23:20
+ |
+LL | borrow_mut2(x, x);
+ | ----------- - ^ second mutable borrow occurs here
+ | | |
+ | | first mutable borrow occurs here
+ | first borrow later used by call
+
+error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
+ --> $DIR/coerce-overloaded-autoderef-fail.rs:28:5
+ |
+LL | borrow2(x, x);
+ | -------^^^^-^
+ | | |
+ | | immutable borrow occurs here
+ | mutable borrow occurs here
+ | immutable borrow later used by call
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0499, E0502, E0506.
+For more information about an error, try `rustc --explain E0499`.
-fn borrow_mut<T>(x: &mut T) -> &mut T { x }
-fn borrow<T>(x: &T) -> &T { x }
+// run-pass
+#![allow(unused_braces)]
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
-fn borrow_mut2<T>(_: &mut T, _: &mut T) {}
-fn borrow2<T>(_: &mut T, _: &T) {}
+use std::rc::Rc;
-fn double_mut_borrow<T>(x: &mut Box<T>) {
- let y = borrow_mut(x);
- let z = borrow_mut(x);
- //~^ ERROR cannot borrow `*x` as mutable more than once at a time
- drop((y, z));
+// Examples from the "deref coercions" RFC, at rust-lang/rfcs#241.
+
+fn use_ref<T>(_: &T) {}
+fn use_mut<T>(_: &mut T) {}
+
+fn use_rc<T>(t: Rc<T>) {
+ use_ref(&*t); // what you have to write today
+ use_ref(&t); // what you'd be able to write
+ use_ref(&&&&&&t);
+ use_ref(&mut &&&&&t);
+ use_ref(&&&mut &&&t);
+}
+
+fn use_mut_box<T>(mut t: &mut Box<T>) {
+ use_mut(&mut *t); // what you have to write today
+ use_mut(t); // what you'd be able to write
+ use_mut(&mut &mut &mut t);
+
+ use_ref(&*t); // what you have to write today
+ use_ref(t); // what you'd be able to write
+ use_ref(&&&&&&t);
+ use_ref(&mut &&&&&t);
+ use_ref(&&&mut &&&t);
}
-fn double_imm_borrow(x: &mut Box<i32>) {
- let y = borrow(x);
- let z = borrow(x);
- **x += 1;
- //~^ ERROR cannot assign to `**x` because it is borrowed
- drop((y, z));
+fn use_nested<T>(t: &Box<T>) {
+ use_ref(&**t); // what you have to write today
+ use_ref(t); // what you'd be able to write (note: recursive deref)
+ use_ref(&&&&&&t);
+ use_ref(&mut &&&&&t);
+ use_ref(&&&mut &&&t);
+}
+
+fn use_slice(_: &[u8]) {}
+fn use_slice_mut(_: &mut [u8]) {}
+
+fn use_vec(mut v: Vec<u8>) {
+ use_slice_mut(&mut v[..]); // what you have to write today
+ use_slice_mut(&mut v); // what you'd be able to write
+ use_slice_mut(&mut &mut &mut v);
+
+ use_slice(&v[..]); // what you have to write today
+ use_slice(&v); // what you'd be able to write
+ use_slice(&&&&&&v);
+ use_slice(&mut &&&&&v);
+ use_slice(&&&mut &&&v);
}
-fn double_mut_borrow2<T>(x: &mut Box<T>) {
- borrow_mut2(x, x);
- //~^ ERROR cannot borrow `*x` as mutable more than once at a time
+fn use_vec_ref(v: &Vec<u8>) {
+ use_slice(&v[..]); // what you have to write today
+ use_slice(v); // what you'd be able to write
+ use_slice(&&&&&&v);
+ use_slice(&mut &&&&&v);
+ use_slice(&&&mut &&&v);
}
-fn double_borrow2<T>(x: &mut Box<T>) {
- borrow2(x, x);
- //~^ ERROR cannot borrow `*x` as mutable because it is also borrowed as immutable
+fn use_op_rhs(s: &mut String) {
+ *s += {&String::from(" ")};
}
pub fn main() {}
+++ /dev/null
-error[E0499]: cannot borrow `*x` as mutable more than once at a time
- --> $DIR/coerce-overloaded-autoderef.rs:9:24
- |
-LL | let y = borrow_mut(x);
- | - first mutable borrow occurs here
-LL | let z = borrow_mut(x);
- | ^ second mutable borrow occurs here
-LL |
-LL | drop((y, z));
- | - first borrow later used here
-
-error[E0506]: cannot assign to `**x` because it is borrowed
- --> $DIR/coerce-overloaded-autoderef.rs:17:5
- |
-LL | let y = borrow(x);
- | - borrow of `**x` occurs here
-LL | let z = borrow(x);
-LL | **x += 1;
- | ^^^^^^^^ assignment to borrowed `**x` occurs here
-LL |
-LL | drop((y, z));
- | - borrow later used here
-
-error[E0499]: cannot borrow `*x` as mutable more than once at a time
- --> $DIR/coerce-overloaded-autoderef.rs:23:20
- |
-LL | borrow_mut2(x, x);
- | ----------- - ^ second mutable borrow occurs here
- | | |
- | | first mutable borrow occurs here
- | first borrow later used by call
-
-error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
- --> $DIR/coerce-overloaded-autoderef.rs:28:5
- |
-LL | borrow2(x, x);
- | -------^^^^-^
- | | |
- | | immutable borrow occurs here
- | mutable borrow occurs here
- | immutable borrow later used by call
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0499, E0502, E0506.
-For more information about an error, try `rustc --explain E0499`.
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+fn negate(x: &isize) -> isize {
+ -*x
+}
+
+fn negate_mut(y: &mut isize) -> isize {
+ negate(y)
+}
+
+fn negate_imm(y: &isize) -> isize {
+ negate(y)
+}
+
+pub fn main() {}
--- /dev/null
+// run-pass
+
+struct SpeechMaker {
+ speeches: usize
+}
+
+impl SpeechMaker {
+ pub fn how_many(&self) -> usize { self.speeches }
+}
+
+fn foo(speaker: &SpeechMaker) -> usize {
+ speaker.how_many() + 33
+}
+
+pub fn main() {
+ let lincoln = SpeechMaker {speeches: 22};
+ assert_eq!(foo(&lincoln), 55);
+}
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+fn sum(x: &[isize]) -> isize {
+ let mut sum = 0;
+ for y in x { sum += *y; }
+ return sum;
+}
+
+fn sum_mut(y: &mut [isize]) -> isize {
+ sum(y)
+}
+
+fn sum_imm(y: &[isize]) -> isize {
+ sum(y)
+}
+
+pub fn main() {}
--- /dev/null
+// run-pass
+
+
+fn bar(v: &mut [usize]) -> Vec<usize> {
+ v.to_vec()
+}
+
+fn bip(v: &[usize]) -> Vec<usize> {
+ v.to_vec()
+}
+
+pub fn main() {
+ let mut the_vec = vec![1, 2, 3, 100];
+ assert_eq!(the_vec.clone(), bar(&mut the_vec));
+ assert_eq!(the_vec.clone(), bip(&the_vec));
+}
--- /dev/null
+fn test<T>(_a: T, _b: T) {}
+
+fn main() {
+ test(&mut 7, &7);
+ //~^ mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/coerce-reborrow-multi-arg-fail.rs:4:18
+ |
+LL | test(&mut 7, &7);
+ | ^^ types differ in mutability
+ |
+ = note: expected mutable reference `&mut {integer}`
+ found reference `&{integer}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// build-pass
+fn test<T>(_a: T, _b: T) {}
+
+fn main() {
+ test(&7, &7);
+ test(&7, &mut 7);
+ test::<&i32>(&mut 7, &7);
+ test::<&i32>(&mut 7, &mut 7);
+}
--- /dev/null
+// run-pass
+// pretty-expanded FIXME #23616
+
+struct SpeechMaker {
+ speeches: usize
+}
+
+fn talk(x: &mut SpeechMaker) {
+ x.speeches += 1;
+}
+
+fn give_a_few_speeches(speaker: &mut SpeechMaker) {
+
+ // Here speaker is reborrowed for each call, so we don't get errors
+ // about speaker being moved.
+
+ talk(speaker);
+ talk(speaker);
+ talk(speaker);
+}
+
+pub fn main() {
+ let mut lincoln = SpeechMaker {speeches: 22};
+ give_a_few_speeches(&mut lincoln);
+}
--- /dev/null
+// run-pass
+// pretty-expanded FIXME #23616
+
+struct SpeechMaker {
+ speeches: usize
+}
+
+impl SpeechMaker {
+ pub fn talk(&mut self) {
+ self.speeches += 1;
+ }
+}
+
+fn give_a_few_speeches(speaker: &mut SpeechMaker) {
+
+ // Here speaker is reborrowed for each call, so we don't get errors
+ // about speaker being moved.
+
+ speaker.talk();
+ speaker.talk();
+ speaker.talk();
+}
+
+pub fn main() {
+ let mut lincoln = SpeechMaker {speeches: 22};
+ give_a_few_speeches(&mut lincoln);
+}
--- /dev/null
+// run-pass
+
+
+fn reverse(v: &mut [usize]) {
+ v.reverse();
+}
+
+fn bar(v: &mut [usize]) {
+ reverse(v);
+ reverse(v);
+ reverse(v);
+}
+
+pub fn main() {
+ let mut the_vec = vec![1, 2, 3, 100];
+ bar(&mut the_vec);
+ assert_eq!(the_vec, [100, 3, 2, 1]);
+}
--- /dev/null
+// run-pass
+
+
+fn bar(v: &mut [usize]) {
+ v.reverse();
+ v.reverse();
+ v.reverse();
+}
+
+pub fn main() {
+ let mut the_vec = vec![1, 2, 3, 100];
+ bar(&mut the_vec);
+ assert_eq!(the_vec, [100, 3, 2, 1]);
+}
#![feature(never_type)]
-fn foo(x: usize, y: !, z: usize) { }
-
fn cast_a() {
let y = {return; 22} as !;
//~^ ERROR non-primitive cast
error[E0605]: non-primitive cast: `i32` as `!`
- --> $DIR/coerce-to-bang-cast.rs:6:13
+ --> $DIR/coerce-to-bang-cast.rs:4:13
|
LL | let y = {return; 22} as !;
- | ^^^^^^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0605]: non-primitive cast: `i32` as `!`
- --> $DIR/coerce-to-bang-cast.rs:11:13
+ --> $DIR/coerce-to-bang-cast.rs:9:13
|
LL | let y = 22 as !;
- | ^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to 2 previous errors
--- /dev/null
+// run-pass
+// Check that coercions unify the expected return type of a polymorphic
+// function call, instead of leaving the type variables as they were.
+
+// pretty-expanded FIXME #23616
+
+struct Foo;
+impl Foo {
+ fn foo<T>(self, x: T) -> Option<T> { Some(x) }
+}
+
+pub fn main() {
+ let _: Option<fn()> = Some(main);
+ let _: Option<fn()> = Foo.foo(main);
+
+ // The same two cases, with implicit type variables made explicit.
+ let _: Option<fn()> = Some::<_>(main);
+ let _: Option<fn()> = Foo.foo::<_>(main);
+}
--- /dev/null
+// run-pass
+// Check that coercions can unify if-else, match arms and array elements.
+
+// Try to construct if-else chains, matches and arrays out of given expressions.
+macro_rules! check {
+ ($last:expr $(, $rest:expr)+) => {
+ // Last expression comes first because of whacky ifs and matches.
+ let _ = $(if false { $rest })else+ else { $last };
+
+ let _ = match 0 { $(_ if false => $rest,)+ _ => $last };
+
+ let _ = [$($rest,)+ $last];
+ }
+}
+
+// Check all non-uniform cases of 2 and 3 expressions of 2 types.
+macro_rules! check2 {
+ ($a:expr, $b:expr) => {
+ check!($a, $b);
+ check!($b, $a);
+
+ check!($a, $a, $b);
+ check!($a, $b, $a);
+ check!($a, $b, $b);
+
+ check!($b, $a, $a);
+ check!($b, $a, $b);
+ check!($b, $b, $a);
+ }
+}
+
+// Check all non-uniform cases of 2 and 3 expressions of 3 types.
+macro_rules! check3 {
+ ($a:expr, $b:expr, $c:expr) => {
+ // Delegate to check2 for cases where a type repeats.
+ check2!($a, $b);
+ check2!($b, $c);
+ check2!($a, $c);
+
+ // Check the remaining cases, i.e., permutations of ($a, $b, $c).
+ check!($a, $b, $c);
+ check!($a, $c, $b);
+ check!($b, $a, $c);
+ check!($b, $c, $a);
+ check!($c, $a, $b);
+ check!($c, $b, $a);
+ }
+}
+
+use std::mem::size_of;
+
+fn foo() {}
+fn bar() {}
+
+pub fn main() {
+ check3!(foo, bar, foo as fn());
+ check3!(size_of::<u8>, size_of::<u16>, size_of::<usize> as fn() -> usize);
+
+ let s = String::from("bar");
+ check2!("foo", &s);
+
+ let a = [1, 2, 3];
+ let v = vec![1, 2, 3];
+ check2!(&a[..], &v);
+
+ // Make sure in-array coercion still works.
+ let _ = [("a", Default::default()), (Default::default(), "b"), (&s, &s)];
+}
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+use std::rc::Rc;
+
+fn lub_short<'a, T>(_: &[&'a T], _: &[&'a T]) {}
+
+// The two arguments are a subtype of their LUB, after coercion.
+fn long_and_short<'a, T>(xs: &[&'static T; 1], ys: &[&'a T; 1]) {
+ lub_short(xs, ys);
+}
+
+// The argument coerces to a subtype of the return type.
+fn long_to_short<'a, 'b, T>(xs: &'b [&'static T; 1]) -> &'b [&'a T] {
+ xs
+}
+
+// Rc<T> is covariant over T just like &T.
+fn long_to_short_rc<'a, T>(xs: Rc<[&'static T; 1]>) -> Rc<[&'a T]> {
+ xs
+}
+
+// LUB-coercion (if-else/match/array) coerces `xs: &'b [&'static T: N]`
+// to a subtype of the LUB of `xs` and `ys` (i.e., `&'b [&'a T]`),
+// regardless of the order they appear (in if-else/match/array).
+fn long_and_short_lub1<'a, 'b, T>(xs: &'b [&'static T; 1], ys: &'b [&'a T]) {
+ let _order1 = [xs, ys];
+ let _order2 = [ys, xs];
+}
+
+// LUB-coercion should also have the exact same effect when `&'b [&'a T; N]`
+// needs to be coerced, i.e., the resulting type is not &'b [&'static T], but
+// rather the `&'b [&'a T]` LUB.
+fn long_and_short_lub2<'a, 'b, T>(xs: &'b [&'static T], ys: &'b [&'a T; 1]) {
+ let _order1 = [xs, ys];
+ let _order2 = [ys, xs];
+}
+
+fn main() {}
--- /dev/null
+// Test that impls for these two types are considered ovelapping:
+//
+// * `for<'r> fn(fn(&'r u32))`
+// * `fn(fn(&'a u32)` where `'a` is free
+//
+// This is because, for `'a = 'static`, the two types overlap.
+// Effectively for them to be equal to you get:
+//
+// * `for<'r> fn(fn(&'r u32)) <: fn(fn(&'static u32))`
+// * true if `exists<'r> { 'r: 'static }` (obviously true)
+// * `fn(fn(&'static u32)) <: for<'r> fn(fn(&'r u32))`
+// * true if `forall<'r> { 'static: 'r }` (also true)
+
+trait Trait {}
+
+impl Trait for for<'r> fn(fn(&'r ())) {}
+impl<'a> Trait for fn(fn(&'a ())) {}
+//~^ ERROR conflicting implementations
+//
+// Note in particular that we do NOT get a future-compatibility warning
+// here. This is because the new leak-check proposed in [MCP 295] does not
+// "error" when these two types are equated.
+//
+// [MCP 295]: https://github.com/rust-lang/compiler-team/issues/295
+
+fn main() {}
--- /dev/null
+error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))`:
+ --> $DIR/coherence-fn-covariant-bound-vs-static.rs:17:1
+ |
+LL | impl Trait for for<'r> fn(fn(&'r ())) {}
+ | ------------------------------------- first implementation here
+LL | impl<'a> Trait for fn(fn(&'a ())) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(fn(&'r ()))`
+ |
+ = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
--- /dev/null
+// Test that our leak-check is not smart enough to take implied bounds
+// into account (yet). Here we have two types that look like they
+// should not be equivalent, but because of the rules on implied
+// bounds we ought to know that, in fact, `'a = 'b` must always hold,
+// and hence they are.
+//
+// Rustc can't figure this out and hence it accepts the impls but
+// gives a future-compatibility warning (because we'd like to make
+// this an error someday).
+//
+// Note that while we would like to make this a hard error, we also
+// give the same warning for `coherence-wasm-bindgen.rs`, which ought
+// to be accepted.
+
+#![deny(coherence_leak_check)]
+
+trait Trait {}
+
+impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {}
+
+impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 {
+ //~^ ERROR conflicting implementations
+ //~| WARNING this was previously accepted by the compiler
+}
+
+fn main() {}
--- /dev/null
+error: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32`:
+ --> $DIR/coherence-fn-implied-bounds.rs:21:1
+ |
+LL | impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {}
+ | ------------------------------------------------------------------ first implementation here
+LL |
+LL | impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32`
+ |
+note: the lint level is defined here
+ --> $DIR/coherence-fn-implied-bounds.rs:15:9
+ |
+LL | #![deny(coherence_leak_check)]
+ | ^^^^^^^^^^^^^^^^^^^^
+ = 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 #56105 <https://github.com/rust-lang/rust/issues/56105>
+ = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
--- /dev/null
+// Test that we consider these two types completely equal:
+//
+// * `for<'a, 'b> fn(&'a u32, &'b u32)`
+// * `for<'c> fn(&'c u32, &'c u32)`
+//
+// For a long time we considered these to be distinct types. But in fact they
+// are equivalent, if you work through the implications of subtyping -- this is
+// because:
+//
+// * `'c` can be the intersection of `'a` and `'b` (and there is always an intersection)
+// * `'a` and `'b` can both be equal to `'c`
+
+trait Trait {}
+impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {}
+impl Trait for for<'c> fn(&'c u32, &'c u32) {
+ //~^ ERROR conflicting implementations
+ //
+ // Note in particular that we do NOT get a future-compatibility warning
+ // here. This is because the new leak-check proposed in [MCP 295] does not
+ // "error" when these two types are equated.
+ //
+ // [MCP 295]: https://github.com/rust-lang/compiler-team/issues/295
+}
+
+fn main() {}
--- /dev/null
+error[E0119]: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a u32, &'b u32)`:
+ --> $DIR/coherence-fn-inputs.rs:15:1
+ |
+LL | impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {}
+ | ----------------------------------------------- first implementation here
+LL | impl Trait for for<'c> fn(&'c u32, &'c u32) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u32, &'b u32)`
+ |
+ = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
--- /dev/null
+// Capture a coherence pattern from wasm-bindgen that we discovered as part of
+// future-compatibility warning #56105. This pattern currently receives a lint
+// warning but we probably want to support it long term.
+//
+// Key distinction: we are implementing once for `A` (take ownership) and one
+// for `&A` (borrow).
+//
+// c.f. #56105
+
+#![deny(coherence_leak_check)]
+
+trait TheTrait {}
+
+impl<'a> TheTrait for fn(&'a u8) {}
+
+impl TheTrait for fn(&u8) {
+ //~^ ERROR conflicting implementations of trait
+ //~| WARNING this was previously accepted by the compiler
+}
+
+fn main() {}
--- /dev/null
+error: conflicting implementations of trait `TheTrait` for type `fn(&u8)`:
+ --> $DIR/coherence-free-vs-bound-region.rs:16:1
+ |
+LL | impl<'a> TheTrait for fn(&'a u8) {}
+ | -------------------------------- first implementation here
+LL |
+LL | impl TheTrait for fn(&u8) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(&u8)`
+ |
+note: the lint level is defined here
+ --> $DIR/coherence-free-vs-bound-region.rs:10:9
+ |
+LL | #![deny(coherence_leak_check)]
+ | ^^^^^^^^^^^^^^^^^^^^
+ = 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 #56105 <https://github.com/rust-lang/rust/issues/56105>
+ = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
//
// No we expect to run into a more user-friendly cycle error instead.
#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
trait Trait<T> { type Assoc; }
//~^ ERROR E0391
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:6:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0391]: cycle detected when building specialization graph of trait `Trait`
- --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:8:1
+ --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:9:1
|
LL | trait Trait<T> { type Assoc; }
| ^^^^^^^^^^^^^^
|
= note: ...which again requires building specialization graph of trait `Trait`, completing the cycle
note: cycle used when coherence checking all impls of trait `Trait`
- --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:8:1
+ --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:9:1
|
LL | trait Trait<T> { type Assoc; }
| ^^^^^^^^^^^^^^
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0391`.
+++ /dev/null
-warning: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`:
- --> $DIR/coherence-subtyping.rs:16:1
- |
-LL | impl TheTrait for for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {}
- | ---------------------------------------------------------- first implementation here
-LL |
-LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
- |
- = note: `#[warn(coherence_leak_check)]` 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 #56105 <https://github.com/rust-lang/rust/issues/56105>
- = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
-
-warning: 1 warning emitted
-
+++ /dev/null
-warning: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`:
- --> $DIR/coherence-subtyping.rs:16:1
- |
-LL | impl TheTrait for for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {}
- | ---------------------------------------------------------- first implementation here
-LL |
-LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
- |
- = note: `#[warn(coherence_leak_check)]` 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 #56105 <https://github.com/rust-lang/rust/issues/56105>
- = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
-
-warning: 1 warning emitted
-
// Note: This scenario is currently accepted, but as part of the
// universe transition (#56105) may eventually become an error.
-// revisions: old re
// check-pass
trait TheTrait {
impl TheTrait for for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {}
impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
- //[re]~^ WARNING conflicting implementation
- //[re]~^^ WARNING this was previously accepted by the compiler but is being phased out
- //[old]~^^^ WARNING conflicting implementation
- //[old]~^^^^ WARNING this was previously accepted by the compiler but is being phased out
+ //~^ WARNING conflicting implementation
+ //~^^ WARNING this was previously accepted by the compiler but is being phased out
}
fn main() {}
--- /dev/null
+warning: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`:
+ --> $DIR/coherence-subtyping.rs:15:1
+ |
+LL | impl TheTrait for for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {}
+ | ---------------------------------------------------------- first implementation here
+LL |
+LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
+ |
+ = note: `#[warn(coherence_leak_check)]` 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 #56105 <https://github.com/rust-lang/rust/issues/56105>
+ = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+warning: 1 warning emitted
+
--- /dev/null
+// Capture a coherence pattern from wasm-bindgen that we discovered as part of
+// future-compatibility warning #56105. This pattern currently receives a lint
+// warning but we probably want to support it long term.
+//
+// Key distinction: we are implementing once for `A` (take ownership) and one
+// for `&A` (borrow).
+//
+// c.f. #56105
+
+#![deny(coherence_leak_check)]
+
+trait IntoWasmAbi {
+ fn some_method(&self) {}
+}
+
+trait FromWasmAbi {}
+trait RefFromWasmAbi {}
+trait ReturnWasmAbi {}
+
+impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b)
+where
+ A: FromWasmAbi,
+ R: ReturnWasmAbi,
+{
+}
+
+// Explicitly writing the bound lifetime.
+impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b)
+where
+ A: RefFromWasmAbi,
+ R: ReturnWasmAbi,
+{
+ //~^^^^^ ERROR conflicting implementation
+ //~| WARNING this was previously accepted
+}
+
+fn main() {}
--- /dev/null
+error: conflicting implementations of trait `IntoWasmAbi` for type `&dyn std::ops::Fn(&_) -> _`:
+ --> $DIR/coherence-wasm-bindgen.rs:28:1
+ |
+LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b)
+LL | | where
+LL | | A: FromWasmAbi,
+LL | | R: ReturnWasmAbi,
+LL | | {
+LL | | }
+ | |_- first implementation here
+...
+LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b)
+LL | | where
+LL | | A: RefFromWasmAbi,
+LL | | R: ReturnWasmAbi,
+... |
+LL | |
+LL | | }
+ | |_^ conflicting implementation for `&dyn std::ops::Fn(&_) -> _`
+ |
+note: the lint level is defined here
+ --> $DIR/coherence-wasm-bindgen.rs:10:9
+ |
+LL | #![deny(coherence_leak_check)]
+ | ^^^^^^^^^^^^^^^^^^^^
+ = 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 #56105 <https://github.com/rust-lang/rust/issues/56105>
+ = note: downstream crates may implement trait `FromWasmAbi` for type `&_`
+ = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
LL |
LL | IntoIter::new([0i32; 33])
- | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
+ | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
|
- = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::array::IntoIter<i32, 33usize>`
+ = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::array::IntoIter<i32, 33_usize>`
= note: the return type of a function must have a statically known size
error[E0277]: arrays only have std trait implementations for lengths 0..=32
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
LL |
LL | IntoIter::new([0i32; 33])
- | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
+ | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
|
- = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::array::IntoIter<i32, 33usize>`
+ = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::array::IntoIter<i32, 33_usize>`
= note: the return type of a function must have a statically known size
error[E0277]: arrays only have std trait implementations for lengths 0..=32
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
LL |
LL | IntoIter::new([0i32; 33])
- | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
+ | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
|
- = note: required because of the requirements on the impl of `std::iter::ExactSizeIterator` for `std::array::IntoIter<i32, 33usize>`
+ = note: required because of the requirements on the impl of `std::iter::ExactSizeIterator` for `std::array::IntoIter<i32, 33_usize>`
= note: the return type of a function must have a statically known size
error[E0277]: arrays only have std trait implementations for lengths 0..=32
| ^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
LL |
LL | IntoIter::new([0i32; 33])
- | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
+ | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
|
- = note: required because of the requirements on the impl of `std::iter::FusedIterator` for `std::array::IntoIter<i32, 33usize>`
+ = note: required because of the requirements on the impl of `std::iter::FusedIterator` for `std::array::IntoIter<i32, 33_usize>`
= note: the return type of a function must have a statically known size
error[E0277]: arrays only have std trait implementations for lengths 0..=32
| ^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
LL |
LL | IntoIter::new([0i32; 33])
- | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
+ | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
|
- = note: required because of the requirements on the impl of `std::iter::TrustedLen` for `std::array::IntoIter<i32, 33usize>`
+ = note: required because of the requirements on the impl of `std::iter::TrustedLen` for `std::array::IntoIter<i32, 33_usize>`
= note: the return type of a function must have a statically known size
error[E0277]: arrays only have std trait implementations for lengths 0..=32
| ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
LL |
LL | IntoIter::new([0i32; 33])
- | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
+ | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
|
- = note: required because of the requirements on the impl of `std::clone::Clone` for `std::array::IntoIter<i32, 33usize>`
+ = note: required because of the requirements on the impl of `std::clone::Clone` for `std::array::IntoIter<i32, 33_usize>`
= note: the return type of a function must have a statically known size
error[E0277]: arrays only have std trait implementations for lengths 0..=32
| ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
LL |
LL | IntoIter::new([0i32; 33])
- | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
+ | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
|
- = note: required because of the requirements on the impl of `std::fmt::Debug` for `std::array::IntoIter<i32, 33usize>`
+ = note: required because of the requirements on the impl of `std::fmt::Debug` for `std::array::IntoIter<i32, 33_usize>`
= note: the return type of a function must have a statically known size
error: aborting due to 14 previous errors
--- /dev/null
+#![feature(const_generics)]
+
+pub struct Num<const N: usize>;
+
+// Braces around const expression causes crash
+impl Num<{5}> {
+ pub fn five(&self) {
+ }
+}
| ^
|
= note: type arguments must be provided before constant arguments
+ = help: reorder the arguments: types, then consts: `<T, N>`
error: aborting due to previous error; 1 warning emitted
--> $DIR/different_byref.rs:8:9
|
LL | x = Const::<{ [4] }> {};
- | ^^^^^^^^^^^^^^^^^^^ expected `3usize`, found `4usize`
+ | ^^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
|
- = note: expected type `[3usize]`
- found type `[4usize]`
+ = note: expected type `[3_usize]`
+ found type `[4_usize]`
error: aborting due to previous error; 1 warning emitted
-// run-pass
-
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete
fn function() -> u32 {
17
}
-struct Wrapper<const F: fn() -> u32>;
+struct Wrapper<const F: fn() -> u32>; //~ ERROR: using function pointers as const generic parameters
impl<const F: fn() -> u32> Wrapper<F> {
+//~^ ERROR: using function pointers as const generic parameters
fn call() -> u32 {
F()
}
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/fn-const-param-call.rs:3:12
+ --> $DIR/fn-const-param-call.rs:1:12
|
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-warning: 1 warning emitted
+error: using function pointers as const generic parameters is forbidden
+ --> $DIR/fn-const-param-call.rs:8:25
+ |
+LL | struct Wrapper<const F: fn() -> u32>;
+ | ^^^^^^^^^^^
+
+error: using function pointers as const generic parameters is forbidden
+ --> $DIR/fn-const-param-call.rs:10:15
+ |
+LL | impl<const F: fn() -> u32> Wrapper<F> {
+ | ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete
struct Checked<const F: fn(usize) -> bool>;
+//~^ ERROR: using function pointers as const generic parameters
fn not_one(val: usize) -> bool { val != 1 }
fn not_two(val: usize) -> bool { val != 2 }
fn main() {
let _: Option<Checked<not_one>> = None;
let _: Checked<not_one> = Checked::<not_one>;
- let _: Checked<not_one> = Checked::<not_two>; //~ mismatched types
+ let _: Checked<not_one> = Checked::<not_two>;
let _ = Checked::<generic_arg>;
let _ = Checked::<{generic_arg::<usize>}>;
- let _ = Checked::<{generic_arg::<u32>}>; //~ mismatched types
+ let _ = Checked::<{generic_arg::<u32>}>;
- let _ = Checked::<generic>; //~ type annotations needed
+ let _ = Checked::<generic>;
let _ = Checked::<{generic::<u16>}>;
let _: Checked<{generic::<u16>}> = Checked::<{generic::<u16>}>;
- let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>; //~ mismatched types
+ let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
}
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/fn-const-param-infer.rs:1:12
|
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-error[E0308]: mismatched types
- --> $DIR/fn-const-param-infer.rs:16:31
+error: using function pointers as const generic parameters is forbidden
+ --> $DIR/fn-const-param-infer.rs:4:25
|
-LL | let _: Checked<not_one> = Checked::<not_two>;
- | ^^^^^^^^^^^^^^^^^^ expected `{not_one as fn(usize) -> bool}`, found `{not_two as fn(usize) -> bool}`
- |
- = note: expected type `{not_one as fn(usize) -> bool}`
- found type `{not_two as fn(usize) -> bool}`
-
-error[E0308]: mismatched types
- --> $DIR/fn-const-param-infer.rs:20:24
- |
-LL | let _ = Checked::<{generic_arg::<u32>}>;
- | ^^^^^^^^^^^^^^^^^^ expected `usize`, found `u32`
- |
- = note: expected fn pointer `fn(usize) -> _`
- found fn item `fn(u32) -> _ {generic_arg::<u32>}`
-
-error[E0282]: type annotations needed
- --> $DIR/fn-const-param-infer.rs:22:23
- |
-LL | let _ = Checked::<generic>;
- | ^^^^^^^ cannot infer type for type parameter `T` declared on the function `generic`
-
-error[E0308]: mismatched types
- --> $DIR/fn-const-param-infer.rs:25:40
- |
-LL | let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic::<u32> as fn(usize) -> bool}`, found `{generic::<u16> as fn(usize) -> bool}`
- |
- = note: expected type `{generic::<u32> as fn(usize) -> bool}`
- found type `{generic::<u16> as fn(usize) -> bool}`
+LL | struct Checked<const F: fn(usize) -> bool>;
+ | ^^^^^^^^^^^^^^^^^
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to previous error; 1 warning emitted
-Some errors have detailed explanations: E0282, E0308.
-For more information about an error, try `rustc --explain E0282`.
--- /dev/null
+// aux-build:impl-const.rs
+// run-pass
+
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+extern crate impl_const;
+
+use impl_const::*;
+
+pub fn main() {
+ let n = Num::<5>;
+ n.five();
+}
--- /dev/null
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct Test(*const usize);
+
+type PassArg = ();
+
+unsafe extern "C" fn pass(args: PassArg) {
+ println!("Hello, world!");
+}
+
+impl Test {
+ pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
+ //~^ ERROR: using function pointers as const generic parameters is forbidden
+ self.0 = Self::trampiline::<Args, IDX, FN> as _
+ }
+
+ unsafe extern "C" fn trampiline<
+ Args: Sized,
+ const IDX: usize,
+ const FN: unsafe extern "C" fn(Args),
+ //~^ ERROR: using function pointers as const generic parameters is forbidden
+ >(
+ args: Args,
+ ) {
+ FN(args)
+ }
+}
+
+fn main() {
+ let x = Test();
+ x.call_me::<PassArg, 30, pass>()
+}
--- /dev/null
+error: using function pointers as const generic parameters is forbidden
+ --> $DIR/issue-71381.rs:13:61
+ |
+LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: using function pointers as const generic parameters is forbidden
+ --> $DIR/issue-71381.rs:21:19
+ |
+LL | const FN: unsafe extern "C" fn(Args),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct Test();
+
+fn pass() {
+ println!("Hello, world!");
+}
+
+impl Test {
+ pub fn call_me(&self) {
+ self.test::<pass>();
+ }
+
+ fn test<const FN: fn()>(&self) {
+ //~^ ERROR: using function pointers as const generic parameters is forbidden
+ FN();
+ }
+}
+
+fn main() {
+ let x = Test();
+ x.call_me()
+}
--- /dev/null
+error: using function pointers as const generic parameters is forbidden
+ --> $DIR/issue-71382.rs:15:23
+ |
+LL | fn test<const FN: fn()>(&self) {
+ | ^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+fn func<A, const F: fn(inner: A)>(outer: A) {
+ //~^ ERROR: using function pointers as const generic parameters is forbidden
+ F(outer);
+}
+
+fn main() {}
--- /dev/null
+error: using function pointers as const generic parameters is forbidden
+ --> $DIR/issue-71611.rs:4:21
+ |
+LL | fn func<A, const F: fn(inner: A)>(outer: A) {
+ | ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+use std::ffi::{CStr, CString};
+
+unsafe fn unsafely_do_the_thing<const F: fn(&CStr) -> usize>(ptr: *const i8) -> usize {
+ //~^ ERROR: using function pointers as const generic parameters is forbidden
+ F(CStr::from_ptr(ptr))
+}
+
+fn safely_do_the_thing(s: &CStr) -> usize {
+ s.to_bytes().len()
+}
+
+fn main() {
+ let baguette = CString::new("baguette").unwrap();
+ let ptr = baguette.as_ptr();
+ println!("{}", unsafe {
+ unsafely_do_the_thing::<safely_do_the_thing>(ptr)
+ });
+}
--- /dev/null
+error: using function pointers as const generic parameters is forbidden
+ --> $DIR/issue-72352.rs:6:42
+ |
+LL | unsafe fn unsafely_do_the_thing<const F: fn(&CStr) -> usize>(ptr: *const i8) -> usize {
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
-// run-pass
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete
const A: u32 = 3;
-struct Const<const P: *const u32>;
+struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
-impl<const P: *const u32> Const<P> {
+impl<const P: *const u32> Const<P> { //~ ERROR: using raw pointers as const generic parameters
fn get() -> u32 {
unsafe {
*P
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/raw-ptr-const-param-deref.rs:2:12
+ --> $DIR/raw-ptr-const-param-deref.rs:1:12
|
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-warning: 1 warning emitted
+error: using raw pointers as const generic parameters is forbidden
+ --> $DIR/raw-ptr-const-param-deref.rs:6:23
+ |
+LL | struct Const<const P: *const u32>;
+ | ^^^^^^^^^^
+
+error: using raw pointers as const generic parameters is forbidden
+ --> $DIR/raw-ptr-const-param-deref.rs:8:15
+ |
+LL | impl<const P: *const u32> Const<P> {
+ | ^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete
-struct Const<const P: *const u32>;
+struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
fn main() {
- let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; //~ mismatched types
+ let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
let _: Const<{ 10 as *const _ }> = Const::<{ 10 as *const _ }>;
}
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/raw-ptr-const-param.rs:1:12
|
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-error[E0308]: mismatched types
- --> $DIR/raw-ptr-const-param.rs:7:40
+error: using raw pointers as const generic parameters is forbidden
+ --> $DIR/raw-ptr-const-param.rs:4:23
|
-LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}`
- |
- = note: expected type `{0xf as *const u32}`
- found type `{0xa as *const u32}`
+LL | struct Const<const P: *const u32>;
+ | ^^^^^^^^^^
error: aborting due to previous error; 1 warning emitted
-For more information about this error, try `rustc --explain E0308`.
--> $DIR/types-mismatch-const-args.rs:13:41
|
LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2u32`, found `4u32`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2_u32`, found `4_u32`
|
- = note: expected type `2u32`
- found type `4u32`
+ = note: expected type `2_u32`
+ found type `4_u32`
error[E0308]: mismatched types
--> $DIR/types-mismatch-const-args.rs:15:41
LL | pub const A: i8 = -std::i8::MIN;
| ------------------^^^^^^^^^^^^^-
| |
- | attempt to negate with overflow
+ | attempt to negate i8::MIN which would overflow
|
note: the lint level is defined here
--> $DIR/const-err-early.rs:1:9
LL | pub const B: u8 = 200u8 + 200u8;
| ------------------^^^^^^^^^^^^^-
| |
- | attempt to add with overflow
+ | attempt to compute `200_u8 + 200_u8` which would overflow
error: any use of this value will cause an error
--> $DIR/const-err-early.rs:5:19
LL | pub const C: u8 = 200u8 * 4;
| ------------------^^^^^^^^^-
| |
- | attempt to multiply with overflow
+ | attempt to compute `200_u8 * 4_u8` which would overflow
error: any use of this value will cause an error
--> $DIR/const-err-early.rs:6:19
LL | pub const D: u8 = 42u8 - (42u8 + 1);
| ------------------^^^^^^^^^^^^^^^^^-
| |
- | attempt to subtract with overflow
+ | attempt to compute `42_u8 - 43_u8` which would overflow
error: any use of this value will cause an error
--> $DIR/const-err-early.rs:7:19
LL | pub const A: i8 = -std::i8::MIN;
| ------------------^^^^^^^^^^^^^-
| |
- | attempt to negate with overflow
+ | attempt to negate i8::MIN which would overflow
|
note: the lint level is defined here
--> $DIR/const-err-multi.rs:1:9
--> $DIR/const-err2.rs:19:13
|
LL | let a = -std::i8::MIN;
- | ^^^^^^^^^^^^^ attempt to negate with overflow
+ | ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow
|
= note: `#[deny(arithmetic_overflow)]` on by default
--> $DIR/const-err2.rs:21:18
|
LL | let a_i128 = -std::i128::MIN;
- | ^^^^^^^^^^^^^^^ attempt to negate with overflow
+ | ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow
error: this arithmetic operation will overflow
--> $DIR/const-err2.rs:23:13
|
LL | let b = 200u8 + 200u8 + 200u8;
- | ^^^^^^^^^^^^^ attempt to add with overflow
+ | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow
error: this arithmetic operation will overflow
--> $DIR/const-err2.rs:25:18
|
LL | let b_i128 = std::i128::MIN - std::i128::MAX;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow
error: this arithmetic operation will overflow
--> $DIR/const-err2.rs:27:13
|
LL | let c = 200u8 * 4;
- | ^^^^^^^^^ attempt to multiply with overflow
+ | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow
error: this arithmetic operation will overflow
--> $DIR/const-err2.rs:29:13
|
LL | let d = 42u8 - (42u8 + 1);
- | ^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow
error: this operation will panic at runtime
--> $DIR/const-err2.rs:31:14
--> $DIR/const-err2.rs:19:13
|
LL | let a = -std::i8::MIN;
- | ^^^^^^^^^^^^^ attempt to negate with overflow
+ | ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow
|
= note: `#[deny(arithmetic_overflow)]` on by default
--> $DIR/const-err2.rs:21:18
|
LL | let a_i128 = -std::i128::MIN;
- | ^^^^^^^^^^^^^^^ attempt to negate with overflow
+ | ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow
error: this arithmetic operation will overflow
--> $DIR/const-err2.rs:23:13
|
LL | let b = 200u8 + 200u8 + 200u8;
- | ^^^^^^^^^^^^^ attempt to add with overflow
+ | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow
error: this arithmetic operation will overflow
--> $DIR/const-err2.rs:25:18
|
LL | let b_i128 = std::i128::MIN - std::i128::MAX;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow
error: this arithmetic operation will overflow
--> $DIR/const-err2.rs:27:13
|
LL | let c = 200u8 * 4;
- | ^^^^^^^^^ attempt to multiply with overflow
+ | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow
error: this arithmetic operation will overflow
--> $DIR/const-err2.rs:29:13
|
LL | let d = 42u8 - (42u8 + 1);
- | ^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow
error: this operation will panic at runtime
--> $DIR/const-err2.rs:31:14
--> $DIR/const-err2.rs:19:13
|
LL | let a = -std::i8::MIN;
- | ^^^^^^^^^^^^^ attempt to negate with overflow
+ | ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow
|
= note: `#[deny(arithmetic_overflow)]` on by default
--> $DIR/const-err2.rs:21:18
|
LL | let a_i128 = -std::i128::MIN;
- | ^^^^^^^^^^^^^^^ attempt to negate with overflow
+ | ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow
error: this arithmetic operation will overflow
--> $DIR/const-err2.rs:23:13
|
LL | let b = 200u8 + 200u8 + 200u8;
- | ^^^^^^^^^^^^^ attempt to add with overflow
+ | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow
error: this arithmetic operation will overflow
--> $DIR/const-err2.rs:25:18
|
LL | let b_i128 = std::i128::MIN - std::i128::MAX;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow
error: this arithmetic operation will overflow
--> $DIR/const-err2.rs:27:13
|
LL | let c = 200u8 * 4;
- | ^^^^^^^^^ attempt to multiply with overflow
+ | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow
error: this arithmetic operation will overflow
--> $DIR/const-err2.rs:29:13
|
LL | let d = 42u8 - (42u8 + 1);
- | ^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow
error: this operation will panic at runtime
--> $DIR/const-err2.rs:31:14
LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
| ------------------^^^^^---------------------------
| |
- | attempt to subtract with overflow
+ | attempt to compute `5_u32 - 6_u32` which would overflow
|
note: the lint level is defined here
--> $DIR/conditional_array_execution.rs:3:9
--> $DIR/const-eval-overflow-3.rs:20:11
|
LL | = [0; (i8::MAX + 1) as usize];
- | ^^^^^^^^^^^^^ attempt to add with overflow
+ | ^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow
error: aborting due to previous error
--> $DIR/const-eval-overflow-4.rs:13:13
|
LL | : [u32; (i8::MAX as i8 + 1i8) as usize]
- | ^^^^^^^^^^^^^^^^^^^^^ attempt to add with overflow
+ | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow
error: aborting due to previous error
--> $DIR/const-eval-overflow-4b.rs:25:13
|
LL | : [u32; 5i8 as char as usize]
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^ invalid cast
error: aborting due to 3 previous errors
LL | / const VALS_I8: (i8,) =
LL | | (
LL | | i8::MIN - 1,
- | | ^^^^^^^^^^^ attempt to subtract with overflow
+ | | ^^^^^^^^^^^ attempt to compute `i8::MIN - 1_i8` which would overflow
LL | | );
| |_______-
|
LL | / const VALS_I16: (i16,) =
LL | | (
LL | | i16::MIN - 1,
- | | ^^^^^^^^^^^^ attempt to subtract with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `i16::MIN - 1_i16` which would overflow
LL | | );
| |_______-
LL | / const VALS_I32: (i32,) =
LL | | (
LL | | i32::MIN - 1,
- | | ^^^^^^^^^^^^ attempt to subtract with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `i32::MIN - 1_i32` which would overflow
LL | | );
| |_______-
LL | / const VALS_I64: (i64,) =
LL | | (
LL | | i64::MIN - 1,
- | | ^^^^^^^^^^^^ attempt to subtract with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `i64::MIN - 1_i64` which would overflow
LL | | );
| |_______-
LL | / const VALS_U8: (u8,) =
LL | | (
LL | | u8::MIN - 1,
- | | ^^^^^^^^^^^ attempt to subtract with overflow
+ | | ^^^^^^^^^^^ attempt to compute `0_u8 - 1_u8` which would overflow
LL | | );
| |_______-
|
LL | / const VALS_U16: (u16,) = (
LL | | u16::MIN - 1,
- | | ^^^^^^^^^^^^ attempt to subtract with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `0_u16 - 1_u16` which would overflow
LL | | );
| |_______-
|
LL | / const VALS_U32: (u32,) = (
LL | | u32::MIN - 1,
- | | ^^^^^^^^^^^^ attempt to subtract with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
LL | | );
| |_______-
LL | / const VALS_U64: (u64,) =
LL | | (
LL | | u64::MIN - 1,
- | | ^^^^^^^^^^^^ attempt to subtract with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `0_u64 - 1_u64` which would overflow
LL | | );
| |_______-
LL | / const VALS_I8: (i8,) =
LL | | (
LL | | i8::MAX + 1,
- | | ^^^^^^^^^^^ attempt to add with overflow
+ | | ^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow
LL | | );
| |_______-
|
LL | / const VALS_I16: (i16,) =
LL | | (
LL | | i16::MAX + 1,
- | | ^^^^^^^^^^^^ attempt to add with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `i16::MAX + 1_i16` which would overflow
LL | | );
| |_______-
LL | / const VALS_I32: (i32,) =
LL | | (
LL | | i32::MAX + 1,
- | | ^^^^^^^^^^^^ attempt to add with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
LL | | );
| |_______-
LL | / const VALS_I64: (i64,) =
LL | | (
LL | | i64::MAX + 1,
- | | ^^^^^^^^^^^^ attempt to add with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `i64::MAX + 1_i64` which would overflow
LL | | );
| |_______-
LL | / const VALS_U8: (u8,) =
LL | | (
LL | | u8::MAX + 1,
- | | ^^^^^^^^^^^ attempt to add with overflow
+ | | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8` which would overflow
LL | | );
| |_______-
|
LL | / const VALS_U16: (u16,) = (
LL | | u16::MAX + 1,
- | | ^^^^^^^^^^^^ attempt to add with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `u16::MAX + 1_u16` which would overflow
LL | | );
| |_______-
|
LL | / const VALS_U32: (u32,) = (
LL | | u32::MAX + 1,
- | | ^^^^^^^^^^^^ attempt to add with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `u32::MAX + 1_u32` which would overflow
LL | | );
| |_______-
LL | / const VALS_U64: (u64,) =
LL | | (
LL | | u64::MAX + 1,
- | | ^^^^^^^^^^^^ attempt to add with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `u64::MAX + 1_u64` which would overflow
LL | | );
| |_______-
LL | / const VALS_I8: (i8,) =
LL | | (
LL | | i8::MIN * 2,
- | | ^^^^^^^^^^^ attempt to multiply with overflow
+ | | ^^^^^^^^^^^ attempt to compute `i8::MIN * 2_i8` which would overflow
LL | | );
| |_______-
|
LL | / const VALS_I16: (i16,) =
LL | | (
LL | | i16::MIN * 2,
- | | ^^^^^^^^^^^^ attempt to multiply with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `i16::MIN * 2_i16` which would overflow
LL | | );
| |_______-
LL | / const VALS_I32: (i32,) =
LL | | (
LL | | i32::MIN * 2,
- | | ^^^^^^^^^^^^ attempt to multiply with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `i32::MIN * 2_i32` which would overflow
LL | | );
| |_______-
LL | / const VALS_I64: (i64,) =
LL | | (
LL | | i64::MIN * 2,
- | | ^^^^^^^^^^^^ attempt to multiply with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `i64::MIN * 2_i64` which would overflow
LL | | );
| |_______-
LL | / const VALS_U8: (u8,) =
LL | | (
LL | | u8::MAX * 2,
- | | ^^^^^^^^^^^ attempt to multiply with overflow
+ | | ^^^^^^^^^^^ attempt to compute `u8::MAX * 2_u8` which would overflow
LL | | );
| |_______-
|
LL | / const VALS_U16: (u16,) = (
LL | | u16::MAX * 2,
- | | ^^^^^^^^^^^^ attempt to multiply with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `u16::MAX * 2_u16` which would overflow
LL | | );
| |_______-
|
LL | / const VALS_U32: (u32,) = (
LL | | u32::MAX * 2,
- | | ^^^^^^^^^^^^ attempt to multiply with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `u32::MAX * 2_u32` which would overflow
LL | | );
| |_______-
LL | / const VALS_U64: (u64,) =
LL | | (
LL | | u64::MAX * 2,
- | | ^^^^^^^^^^^^ attempt to multiply with overflow
+ | | ^^^^^^^^^^^^ attempt to compute `u64::MAX * 2_u64` which would overflow
LL | | );
| |_______-
--> $DIR/const_let.rs:16:32
|
LL | const Y: FakeNeedsDrop = { let mut x = FakeNeedsDrop; x = FakeNeedsDrop; x };
- | ^^^^^ constants cannot evaluate destructors
+ | ^^^^^ - value is dropped here
+ | |
+ | constants cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/const_let.rs:20:33
|
LL | const Y2: FakeNeedsDrop = { let mut x; x = FakeNeedsDrop; x = FakeNeedsDrop; x };
- | ^^^^^ constants cannot evaluate destructors
+ | ^^^^^ - value is dropped here
+ | |
+ | constants cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/const_let.rs:24:21
|
LL | const Z: () = { let mut x = None; x = Some(FakeNeedsDrop); };
- | ^^^^^ constants cannot evaluate destructors
+ | ^^^^^ - value is dropped here
+ | |
+ | constants cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/const_let.rs:28:22
|
LL | const Z2: () = { let mut x; x = None; x = Some(FakeNeedsDrop); };
- | ^^^^^ constants cannot evaluate destructors
+ | ^^^^^ - value is dropped here
+ | |
+ | constants cannot evaluate destructors
error: aborting due to 4 previous errors
-#![feature(const_raw_ptr_to_usize_cast, const_compare_raw_pointers, const_raw_ptr_deref)]
-
fn main() {}
// unconst and bad, will thus error in miri
-const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR any use of this
-// unconst and bad, will thus error in miri
-const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR any use of this
-// unconst and fine
-const Y: usize = unsafe { 42usize as *const i32 as usize + 1 };
-// unconst and bad, will thus error in miri
-const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
-// unconst and fine
-const Z: i32 = unsafe { *(&1 as *const i32) };
+const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be reliably
// unconst and bad, will thus error in miri
-const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause
-const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause
+const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably
-error: any use of this value will cause an error
- --> $DIR/const_raw_ptr_ops.rs:6:26
+error: pointers cannot be reliably compared during const eval.
+ --> $DIR/const_raw_ptr_ops.rs:4:26
|
LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
- | -------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
- | |
- | "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `#[deny(const_err)]` on by default
+ = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-error: any use of this value will cause an error
- --> $DIR/const_raw_ptr_ops.rs:8:27
+error: pointers cannot be reliably compared during const eval.
+ --> $DIR/const_raw_ptr_ops.rs:6:27
|
LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
- | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
- | |
- | "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
-
-error: any use of this value will cause an error
- --> $DIR/const_raw_ptr_ops.rs:12:28
- |
-LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 };
- | ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^-------
- | |
- | "pointer-to-integer cast" needs an rfc before being allowed inside constants
-
-error: any use of this value will cause an error
- --> $DIR/const_raw_ptr_ops.rs:16:26
- |
-LL | const Z2: i32 = unsafe { *(42 as *const i32) };
- | -------------------------^^^^^^^^^^^^^^^^^^^---
- | |
- | unable to turn bytes into a pointer
-
-error: any use of this value will cause an error
- --> $DIR/const_raw_ptr_ops.rs:17:26
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-LL | const Z3: i32 = unsafe { *(44 as *const i32) };
- | -------------------------^^^^^^^^^^^^^^^^^^^---
- | |
- | unable to turn bytes into a pointer
+ = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
--- /dev/null
+#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)]
+
+fn main() {}
+
+// unconst and fine
+const Y: usize = unsafe { 42usize as *const i32 as usize + 1 };
+// unconst and bad, will thus error in miri
+const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
+// unconst and fine
+const Z: i32 = unsafe { *(&1 as *const i32) };
+// unconst and bad, will thus error in miri
+const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause
+const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause
--- /dev/null
+error: any use of this value will cause an error
+ --> $DIR/const_raw_ptr_ops2.rs:8:28
+ |
+LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 };
+ | ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^-------
+ | |
+ | "pointer-to-integer cast" needs an rfc before being allowed inside constants
+ |
+ = note: `#[deny(const_err)]` on by default
+
+error: any use of this value will cause an error
+ --> $DIR/const_raw_ptr_ops2.rs:12:26
+ |
+LL | const Z2: i32 = unsafe { *(42 as *const i32) };
+ | -------------------------^^^^^^^^^^^^^^^^^^^---
+ | |
+ | unable to turn bytes into a pointer
+
+error: any use of this value will cause an error
+ --> $DIR/const_raw_ptr_ops2.rs:13:26
+ |
+LL | const Z3: i32 = unsafe { *(44 as *const i32) };
+ | -------------------------^^^^^^^^^^^^^^^^^^^---
+ | |
+ | unable to turn bytes into a pointer
+
+error: aborting due to 3 previous errors
+
LL | | Union { u8: &BAR }.foo,
LL | | Union { u8: &BAR }.bar,
LL | | )};
- | |___^ type validation failed: encountered 0x05 at .1.<deref>, but expected a valid enum discriminant
+ | |___^ type validation failed: encountered 0x05 at .1.<deref>, but expected a valid enum tag
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
let _ = [(); {
let mut n = 113383; // #20 in https://oeis.org/A006884
while n != 0 {
- //~^ ERROR `while` is not allowed in a `const`
n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
//~^ ERROR evaluation of constant value failed
- //~| ERROR `if` is not allowed in a `const`
}
n
}];
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/infinite_loop.rs:6:9
- |
-LL | / while n != 0 {
-LL | |
-LL | | n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
-LL | |
-LL | |
-LL | | }
- | |_________^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/infinite_loop.rs:8:17
- |
-LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
error[E0080]: evaluation of constant value failed
- --> $DIR/infinite_loop.rs:8:17
+ --> $DIR/infinite_loop.rs:7:17
|
LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
-error: aborting due to 3 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0080, E0658.
-For more information about an error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0080`.
LL | const X: u32 = 0 - 1;
| ---------------^^^^^-
| |
- | attempt to subtract with overflow
+ | attempt to compute `0_u32 - 1_u32` which would overflow
|
note: the lint level is defined here
--> $DIR/issue-43197.rs:3:9
LL | const Y: u32 = foo(0 - 1);
| -------------------^^^^^--
| |
- | attempt to subtract with overflow
+ | attempt to compute `0_u32 - 1_u32` which would overflow
error[E0080]: evaluation of constant expression failed
--> $DIR/issue-43197.rs:14:23
LL | const MAX: u8 = A::MAX + B::MAX;
| ----------------^^^^^^^^^^^^^^^-
| |
- | attempt to add with overflow
+ | attempt to compute `u8::MAX + u8::MAX` which would overflow
|
= note: `#[deny(const_err)]` on by default
fn main() {
[(); { &loop { break } as *const _ as usize } ];
- //~^ ERROR `loop` is not allowed in a `const`
- //~| ERROR casting pointers to integers in constants is unstable
+ //~^ ERROR casting pointers to integers in constants is unstable
//~| ERROR evaluation of constant value failed
}
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/issue-52442.rs:2:14
- |
-LL | [(); { &loop { break } as *const _ as usize } ];
- | ^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
error[E0658]: casting pointers to integers in constants is unstable
--> $DIR/issue-52442.rs:2:13
|
LL | [(); { &loop { break } as *const _ as usize } ];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
Some errors have detailed explanations: E0080, E0658.
For more information about an error, try `rustc --explain E0080`.
let mut x = &0;
let mut n = 0;
while n < 5 {
- //~^ ERROR `while` is not allowed in a `const`
n = (n + 1) % 5; //~ ERROR evaluation of constant value failed
x = &0; // Materialize a new AllocId
}
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/issue-52475.rs:5:9
- |
-LL | / while n < 5 {
-LL | |
-LL | | n = (n + 1) % 5;
-LL | | x = &0; // Materialize a new AllocId
-LL | | }
- | |_________^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
error[E0080]: evaluation of constant value failed
- --> $DIR/issue-52475.rs:7:17
+ --> $DIR/issue-52475.rs:6:17
|
LL | n = (n + 1) % 5;
| ^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0080, E0658.
-For more information about an error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0080`.
+++ /dev/null
-// `loop`s unconditionally-broken-from used to be allowed in constants, but are now forbidden by
-// the HIR const-checker.
-//
-// See https://github.com/rust-lang/rust/pull/66170 and
-// https://github.com/rust-lang/rust/issues/62272.
-
-const FOO: () = loop { break; }; //~ ERROR `loop` is not allowed in a `const`
-
-fn main() {
- [FOO; { let x; loop { x = 5; break; } x }]; //~ ERROR `loop` is not allowed in a `const`
-}
+++ /dev/null
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/issue-62272.rs:7:17
- |
-LL | const FOO: () = loop { break; };
- | ^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/issue-62272.rs:10:20
- |
-LL | [FOO; { let x; loop { x = 5; break; } x }];
- | ^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
const _: Vec<i32> = {
let mut x = Vec::<i32>::new(); //~ ERROR destructors cannot be evaluated at compile-time
- let r = &mut x; //~ ERROR references in constants may only refer to immutable values
+ let r = &mut x; //~ ERROR mutable references are not allowed in constants
let y = x;
y
};
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
--> $DIR/issue-65394.rs:8:13
|
LL | let r = &mut x;
- | ^^^^^^ constants require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^ `&mut` is only allowed in `const fn`
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/issue-65394.rs:7:9
|
LL | let mut x = Vec::<i32>::new();
| ^^^^^ constants cannot evaluate destructors
+...
+LL | };
+ | - value is dropped here
error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0493, E0658.
+Some errors have detailed explanations: E0493, E0764.
For more information about an error, try `rustc --explain E0493`.
-#![feature(const_loop)]
-
static _X: () = loop {}; //~ ERROR could not evaluate static initializer
fn main() {}
error[E0080]: could not evaluate static initializer
- --> $DIR/issue-70723.rs:3:17
+ --> $DIR/issue-70723.rs:1:17
|
LL | static _X: () = loop {};
| ^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
--- /dev/null
+const _: Option<Vec<i32>> = {
+ let mut never_returned = Some(Vec::new());
+ let mut always_returned = None; //~ ERROR destructors cannot be evaluated at compile-time
+
+ let mut i = 0;
+ loop {
+ always_returned = never_returned;
+ never_returned = None;
+
+ i += 1;
+ if i == 10 {
+ break always_returned;
+ }
+ }
+};
+
+fn main() {}
--- /dev/null
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/livedrop.rs:3:9
+ |
+LL | let mut always_returned = None;
+ | ^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors
+...
+LL | always_returned = never_returned;
+ | --------------- value is dropped here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0493`.
let _: [u8; 0] = [4; {
match &1 as *const i32 as usize {
//~^ ERROR casting pointers to integers in constants
- //~| ERROR `match` is not allowed in a `const`
//~| ERROR evaluation of constant value failed
0 => 42,
n => n,
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/match-test-ptr-null.rs:6:9
- |
-LL | / match &1 as *const i32 as usize {
-LL | |
-LL | |
-LL | |
-LL | | 0 => 42,
-LL | | n => n,
-LL | | }
- | |_________^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
error[E0658]: casting pointers to integers in constants is unstable
--> $DIR/match-test-ptr-null.rs:6:15
|
LL | match &1 as *const i32 as usize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
Some errors have detailed explanations: E0080, E0658.
For more information about an error, try `rustc --explain E0080`.
--> $DIR/promoted_errors.rs:12:20
|
LL | println!("{}", 0u32 - 1);
- | ^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
|
note: the lint level is defined here
--> $DIR/promoted_errors.rs:9:20
--> $DIR/promoted_errors.rs:14:14
|
LL | let _x = 0u32 - 1;
- | ^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
warning: this operation will panic at runtime
--> $DIR/promoted_errors.rs:16:20
|
LL | println!("{}", 1 / (1 - 1));
- | ^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^ attempt to divide 1_i32 by zero
|
note: the lint level is defined here
--> $DIR/promoted_errors.rs:9:41
--> $DIR/promoted_errors.rs:20:14
|
LL | let _x = 1 / (1 - 1);
- | ^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^ attempt to divide 1_i32 by zero
warning: this operation will panic at runtime
--> $DIR/promoted_errors.rs:22:20
|
LL | println!("{}", 1 / (false as u32));
- | ^^^^^^^^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
warning: reaching this expression at runtime will panic or abort
--> $DIR/promoted_errors.rs:22:20
--> $DIR/promoted_errors.rs:26:14
|
LL | let _x = 1 / (false as u32);
- | ^^^^^^^^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
warning: 10 warnings emitted
--> $DIR/promoted_errors.rs:14:14
|
LL | let _x = 0u32 - 1;
- | ^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
|
note: the lint level is defined here
--> $DIR/promoted_errors.rs:9:20
--> $DIR/promoted_errors.rs:16:20
|
LL | println!("{}", 1 / (1 - 1));
- | ^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^ attempt to divide 1_i32 by zero
|
note: the lint level is defined here
--> $DIR/promoted_errors.rs:9:41
--> $DIR/promoted_errors.rs:20:14
|
LL | let _x = 1 / (1 - 1);
- | ^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^ attempt to divide 1_i32 by zero
warning: this operation will panic at runtime
--> $DIR/promoted_errors.rs:22:20
|
LL | println!("{}", 1 / (false as u32));
- | ^^^^^^^^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
warning: reaching this expression at runtime will panic or abort
--> $DIR/promoted_errors.rs:22:20
--> $DIR/promoted_errors.rs:26:14
|
LL | let _x = 1 / (false as u32);
- | ^^^^^^^^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
warning: 9 warnings emitted
--> $DIR/promoted_errors.rs:12:20
|
LL | println!("{}", 0u32 - 1);
- | ^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
|
note: the lint level is defined here
--> $DIR/promoted_errors.rs:9:20
--> $DIR/promoted_errors.rs:14:14
|
LL | let _x = 0u32 - 1;
- | ^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
warning: this operation will panic at runtime
--> $DIR/promoted_errors.rs:16:20
|
LL | println!("{}", 1 / (1 - 1));
- | ^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^ attempt to divide 1_i32 by zero
|
note: the lint level is defined here
--> $DIR/promoted_errors.rs:9:41
--> $DIR/promoted_errors.rs:20:14
|
LL | let _x = 1 / (1 - 1);
- | ^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^ attempt to divide 1_i32 by zero
warning: this operation will panic at runtime
--> $DIR/promoted_errors.rs:22:20
|
LL | println!("{}", 1 / (false as u32));
- | ^^^^^^^^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
warning: reaching this expression at runtime will panic or abort
--> $DIR/promoted_errors.rs:22:20
--> $DIR/promoted_errors.rs:26:14
|
LL | let _x = 1 / (false as u32);
- | ^^^^^^^^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
warning: 10 warnings emitted
-#![feature(const_raw_ptr_to_usize_cast, const_compare_raw_pointers, const_raw_ptr_deref)]
+#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)]
fn main() {
let x: &'static bool = &(42 as *const i32 == 43 as *const i32);
LL | pub const Z: u32 = 0 - 1;
| -------------------^^^^^-
| |
- | attempt to subtract with overflow
+ | attempt to compute `0_u32 - 1_u32` which would overflow
|
note: the lint level is defined here
--> $DIR/pub_const_err.rs:2:9
LL | pub const Z: u32 = 0 - 1;
| -------------------^^^^^-
| |
- | attempt to subtract with overflow
+ | attempt to compute `0_u32 - 1_u32` which would overflow
|
note: the lint level is defined here
--> $DIR/pub_const_err_bin.rs:2:9
--> $DIR/shift_overflow.rs:3:9
|
LL | X = 1 << ((u32::MAX as u64) + 1),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left by 4294967296_u64 which would overflow
error: aborting due to previous error
--> $DIR/ub-enum.rs:24:1
|
LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001, but expected a valid enum discriminant
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001, but expected a valid enum tag
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
--> $DIR/ub-enum.rs:42:1
|
LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000, but expected a valid enum discriminant
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000, but expected a valid enum tag
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+// run-pass
+
// Using labeled break in a while loop has caused an illegal instruction being
// generated, and an ICE later.
//
// See https://github.com/rust-lang/rust/issues/51350 for more information.
-//
-// It is now forbidden by the HIR const-checker.
-//
-// See https://github.com/rust-lang/rust/pull/66170.
-const CRASH: () = 'a: while break 'a {}; //~ ERROR `while` is not allowed in a `const`
+#[allow(unreachable_code)]
+const _: () = 'a: while break 'a {};
fn main() {}
+++ /dev/null
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/const-labeled-break.rs:10:19
- |
-LL | const CRASH: () = 'a: while break 'a {};
- | ^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
LL | const LEN: usize = ONE - TWO;
| -------------------^^^^^^^^^-
| |
- | attempt to subtract with overflow
+ | attempt to compute `1_usize - 2_usize` which would overflow
|
= note: `#[deny(const_err)]` on by default
fn main() {
let a: [i8; ONE - TWO] = unimplemented!();
//~^ ERROR evaluation of constant value failed
- //~| attempt to subtract with overflow
+ //~| attempt to compute `1_usize - 2_usize` which would overflow
}
--> $DIR/const-len-underflow-subspans.rs:8:17
|
LL | let a: [i8; ONE - TWO] = unimplemented!();
- | ^^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^^ attempt to compute `1_usize - 2_usize` which would overflow
error: aborting due to previous error
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
--> $DIR/const-match-check.rs:25:15
|
LL | A = { let 0 = 0; 0 },
- | ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+ | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
--> $DIR/const-match-check.rs:31:24
|
LL | let x: [i32; { let 0 = 0; 0 }] = [];
- | ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+ | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
--> $DIR/const-match-check.rs:4:22
|
LL | const X: i32 = { let 0 = 0; 0 };
- | ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+ | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
LL | const X: i32 = { if let 0 = 0 { /* */ } 0 };
| ^^^^^^^^^^^^^^^^^^^^^^
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
--> $DIR/const-match-check.rs:8:23
|
LL | static Y: i32 = { let 0 = 0; 0 };
- | ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+ | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
LL | static Y: i32 = { if let 0 = 0 { /* */ } 0 };
| ^^^^^^^^^^^^^^^^^^^^^^
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
--> $DIR/const-match-check.rs:13:26
|
LL | const X: i32 = { let 0 = 0; 0 };
- | ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+ | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
LL | const X: i32 = { if let 0 = 0 { /* */ } 0 };
| ^^^^^^^^^^^^^^^^^^^^^^
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
--> $DIR/const-match-check.rs:19:26
|
LL | const X: i32 = { let 0 = 0; 0 };
- | ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+ | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-#![allow(warnings)]
+// check-pass
-const x: bool = match Some(true) { //~ ERROR `match` is not allowed in a `const`
+const _: bool = match Some(true) {
Some(value) => true,
_ => false
};
-const y: bool = {
- match Some(true) { //~ ERROR `match` is not allowed in a `const`
+const _: bool = {
+ match Some(true) {
Some(value) => true,
_ => false
}
+++ /dev/null
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/const-match-pattern-arm.rs:3:17
- |
-LL | const x: bool = match Some(true) {
- | _________________^
-LL | | Some(value) => true,
-LL | | _ => false
-LL | | };
- | |_^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/const-match-pattern-arm.rs:9:5
- |
-LL | / match Some(true) {
-LL | | Some(value) => true,
-LL | | _ => false
-LL | | }
- | |_____^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
const _: i32 = {
let mut a = 5;
- let p = &mut a; //~ ERROR references in constants may only refer to immutable values
+ let p = &mut a; //~ ERROR mutable references are not allowed in constants
let reborrow = {p};
let pp = &reborrow;
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
--> $DIR/const-multi-ref.rs:6:13
|
LL | let p = &mut a;
- | ^^^^^^ constants require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^ `&mut` is only allowed in `const fn`
error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
--> $DIR/const-multi-ref.rs:16:13
error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0492, E0658.
+Some errors have detailed explanations: E0492, E0764.
For more information about an error, try `rustc --explain E0492`.
-// check-pass
-
#![feature(const_mut_refs)]
#![feature(const_fn)]
#![feature(raw_ref_op)]
const _: () = {
foo().bar();
+ //~^ ERROR mutable references are not allowed in constants
baz(&mut foo());
+ //~^ ERROR mutable references are not allowed in constants
};
fn main() {}
--- /dev/null
+error[E0764]: mutable references are not allowed in constants
+ --> $DIR/const_mut_address_of.rs:24:5
+ |
+LL | foo().bar();
+ | ^^^^^ `&mut` is only allowed in `const fn`
+
+error[E0764]: mutable references are not allowed in constants
+ --> $DIR/const_mut_address_of.rs:26:9
+ |
+LL | baz(&mut foo());
+ | ^^^^^^^^^^ `&mut` is only allowed in `const fn`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0764`.
-// run-pass
-
#![feature(const_mut_refs)]
struct Foo {
fn main() {
let _: [(); foo().bar()] = [(); 1];
+ //~^ ERROR mutable references are not allowed in constants
let _: [(); baz(&mut foo())] = [(); 2];
+ //~^ ERROR mutable references are not allowed in constants
let _: [(); bazz(&mut foo())] = [(); 3];
+ //~^ ERROR mutable references are not allowed in constants
}
--- /dev/null
+error[E0764]: mutable references are not allowed in constants
+ --> $DIR/const_mut_refs.rs:31:17
+ |
+LL | let _: [(); foo().bar()] = [(); 1];
+ | ^^^^^ `&mut` is only allowed in `const fn`
+
+error[E0764]: mutable references are not allowed in constants
+ --> $DIR/const_mut_refs.rs:33:21
+ |
+LL | let _: [(); baz(&mut foo())] = [(); 2];
+ | ^^^^^^^^^^ `&mut` is only allowed in `const fn`
+
+error[E0764]: mutable references are not allowed in constants
+ --> $DIR/const_mut_refs.rs:35:22
+ |
+LL | let _: [(); bazz(&mut foo())] = [(); 3];
+ | ^^^^^^^^^^ `&mut` is only allowed in `const fn`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0764`.
const a: u8 = 2;
fn main() {
- let a = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX
- let c = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX
- let d = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX
+ let a = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX
+ let c = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX
+ let d = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX
fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115).
}
-error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX` not covered
+error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
--> $DIR/const-pattern-irrefutable.rs:12:9
|
LL | const a: u8 = 2;
|
= note: the matched value is of type `u8`
-error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX` not covered
+error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
--> $DIR/const-pattern-irrefutable.rs:13:9
|
LL | pub const b: u8 = 2;
|
= note: the matched value is of type `u8`
-error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX` not covered
+error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
--> $DIR/const-pattern-irrefutable.rs:14:9
|
LL | pub const d: u8 = 2;
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+#![feature(variant_count)]
+#![feature(never_type)]
+
+use std::mem::variant_count;
+
+enum Void {}
+
+enum Foo {
+ A,
+ B,
+ C,
+}
+
+enum Bar {
+ A,
+ B,
+ C,
+ D(usize),
+ E { field_1: usize, field_2: Foo },
+}
+
+struct Baz {
+ a: u32,
+ b: *const u8,
+}
+
+const TEST_VOID: usize = variant_count::<Void>();
+const TEST_FOO: usize = variant_count::<Foo>();
+const TEST_BAR: usize = variant_count::<Bar>();
+
+const NO_ICE_STRUCT: usize = variant_count::<Baz>();
+const NO_ICE_BOOL: usize = variant_count::<bool>();
+const NO_ICE_PRIM: usize = variant_count::<*const u8>();
+
+fn main() {
+ assert_eq!(TEST_VOID, 0);
+ assert_eq!(TEST_FOO, 3);
+ assert_eq!(TEST_BAR, 5);
+ assert_eq!(variant_count::<Void>(), 0);
+ assert_eq!(variant_count::<Foo>(), 3);
+ assert_eq!(variant_count::<Bar>(), 5);
+ assert_eq!(variant_count::<Option<char>>(), 2);
+ assert_eq!(variant_count::<Option<!>>(), 2);
+ assert_eq!(variant_count::<Result<!, !>>(), 2);
+}
// run-pass
-#![feature(const_if_match)]
#![warn(indirect_structural_match)]
struct CustomEq;
// check-pass
-#![feature(const_if_match)]
#![warn(indirect_structural_match)]
//~^ NOTE lint level is defined here
warning: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]`
- --> $DIR/custom-eq-branch-warn.rs:33:9
+ --> $DIR/custom-eq-branch-warn.rs:32:9
|
LL | BAR_BAZ => panic!(),
| ^^^^^^^
|
note: the lint level is defined here
- --> $DIR/custom-eq-branch-warn.rs:4:9
+ --> $DIR/custom-eq-branch-warn.rs:3:9
|
LL | #![warn(indirect_structural_match)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
--- /dev/null
+// run-pass
+
+// Regression test for https://github.com/rust-lang/rust/issues/73431.
+
+pub trait Zero {
+ const ZERO: Self;
+}
+
+impl Zero for usize {
+ const ZERO: Self = 0;
+}
+
+impl<T: Zero> Zero for Wrapper<T> {
+ const ZERO: Self = Wrapper(T::ZERO);
+}
+
+#[derive(Debug, PartialEq, Eq)]
+pub struct Wrapper<T>(T);
+
+fn is_zero(x: Wrapper<usize>) -> bool {
+ match x {
+ Zero::ZERO => true,
+ _ => false,
+ }
+}
+
+fn main() {
+ let _ = is_zero(Wrapper(42));
+}
-#![feature(const_if_match)]
#![warn(indirect_structural_match)]
struct NoEq;
error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
- --> $DIR/no-eq-branch-fail.rs:22:9
+ --> $DIR/no-eq-branch-fail.rs:21:9
|
LL | BAR_BAZ => panic!(),
| ^^^^^^^
error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
- --> $DIR/no-eq-branch-fail.rs:22:9
+ --> $DIR/no-eq-branch-fail.rs:21:9
|
LL | BAR_BAZ => panic!(),
| ^^^^^^^
const FOO: S = {
let mut s = S { state: 42 };
- s.foo(3); //~ ERROR references in constants may only refer to immutable values
+ s.foo(3); //~ ERROR mutable references are not allowed in constants
s
};
type Array = [u32; {
let mut x = 2;
let y = &mut x;
-//~^ ERROR references in constants may only refer to immutable values
+//~^ ERROR mutable references are not allowed in constants
*y = 42;
//~^ ERROR constant contains unimplemented expression type
*y
|
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
--> $DIR/const_let_assign3.rs:16:5
|
LL | s.foo(3);
- | ^ constants require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^ `&mut` is only allowed in `const fn`
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
--> $DIR/const_let_assign3.rs:22:13
|
LL | let y = &mut x;
- | ^^^^^^ constants require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^ `&mut` is only allowed in `const fn`
error[E0019]: constant contains unimplemented expression type
--> $DIR/const_let_assign3.rs:24:5
error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0019, E0658.
+Some errors have detailed explanations: E0019, E0764.
For more information about an error, try `rustc --explain E0019`.
const fn slice(&[a, b]: &[i32]) -> i32 {
//~^ ERROR refutable pattern in function argument
- //~| ERROR loops and conditional expressions are not stable in const fn
a + b
}
|
= note: the matched value is of type `&[i32]`
-error[E0723]: loops and conditional expressions are not stable in const fn
- --> $DIR/const_let_refutable.rs:3:17
- |
-LL | const fn slice(&[a, b]: &[i32]) -> i32 {
- | ^^^^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0005, E0723.
-For more information about an error, try `rustc --explain E0005`.
+For more information about this error, try `rustc --explain E0005`.
// check-pass
#![feature(const_eval_limit)]
-#![feature(const_loop, const_if_match)]
// This needs to be higher than the number of loop iterations since each pass through the loop may
// hit more than one terminator.
#![feature(const_eval_limit)]
-#![feature(const_loop, const_if_match)]
-
-#![const_eval_limit="500"]
+#![const_eval_limit = "500"]
const X: usize = {
let mut x = 0;
error: any use of this value will cause an error
- --> $DIR/const_eval_limit_reached.rs:8:5
+ --> $DIR/const_eval_limit_reached.rs:6:5
|
LL | / const X: usize = {
LL | | let mut x = 0;
+// check-pass
+
const _: bool = false && false;
const _: bool = true && false;
const _: bool = {
let mut x = true && false;
- //~^ ERROR new features like let bindings are not permitted
x
};
const _: bool = {
let x = true && false;
- //~^ ERROR new features like let bindings are not permitted
x
};
+++ /dev/null
-error: new features like let bindings are not permitted in constants which also use short circuiting operators
- --> $DIR/const_short_circuit.rs:4:9
- |
-LL | let mut x = true && false;
- | ^^^^^
- |
-note: use of `&&` operator here does not actually short circuit due to the const evaluator presently not being able to do control flow. See issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information.
- --> $DIR/const_short_circuit.rs:4:22
- |
-LL | let mut x = true && false;
- | ^^
-
-error: new features like let bindings are not permitted in constants which also use short circuiting operators
- --> $DIR/const_short_circuit.rs:9:9
- |
-LL | let x = true && false;
- | ^
- |
-note: use of `&&` operator here does not actually short circuit due to the const evaluator presently not being able to do control flow. See issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information.
- --> $DIR/const_short_circuit.rs:9:18
- |
-LL | let x = true && false;
- | ^^
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-error: any use of this value will cause an error
- --> $DIR/assert.rs:12:15
- |
-LL | const _: () = assert!(false);
- | --------------^^^^^^^^^^^^^^-
- | |
- | the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:12:15
- |
- = note: `#[deny(const_err)]` on by default
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
+++ /dev/null
-error[E0658]: panicking in constants is unstable
- --> $DIR/assert.rs:8:15
- |
-LL | const _: () = assert!(true);
- | ^^^^^^^^^^^^^
- |
- = note: see issue #51999 <https://github.com/rust-lang/rust/issues/51999> for more information
- = help: add `#![feature(const_panic)]` to the crate attributes to enable
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0658]: panicking in constants is unstable
- --> $DIR/assert.rs:12:15
- |
-LL | const _: () = assert!(false);
- | ^^^^^^^^^^^^^^
- |
- = note: see issue #51999 <https://github.com/rust-lang/rust/issues/51999> for more information
- = help: add `#![feature(const_panic)]` to the crate attributes to enable
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/assert.rs:8:15
- |
-LL | const _: () = assert!(true);
- | ^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/assert.rs:12:15
+error: any use of this value will cause an error
+ --> $DIR/assert.rs:10:15
|
LL | const _: () = assert!(false);
- | ^^^^^^^^^^^^^^
+ | --------------^^^^^^^^^^^^^^-
+ | |
+ | the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:10:15
|
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+ = note: `#[deny(const_err)]` on by default
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0658`.
-// Test that `assert` works only when both `const_if_match` and `const_panic` are enabled.
+// Test that `assert` works when `const_panic` is enabled.
-// revisions: stock if_match panic both
+// revisions: stock panic
-#![cfg_attr(any(both, if_match), feature(const_if_match))]
-#![cfg_attr(any(both, panic), feature(const_panic))]
+#![cfg_attr(panic, feature(const_panic))]
const _: () = assert!(true);
-//[stock,panic]~^ ERROR `if` is not allowed in a `const`
-//[if_match]~^^ ERROR panicking in constants is unstable
+//[stock]~^ ERROR panicking in constants is unstable
const _: () = assert!(false);
-//[stock,panic]~^ ERROR `if` is not allowed in a `const`
-//[if_match]~^^ ERROR panicking in constants is unstable
-//[both]~^^^ ERROR any use of this value will cause an error
+//[stock]~^ ERROR panicking in constants is unstable
+//[panic]~^^ ERROR any use of this value will cause an error
fn main() {}
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/assert.rs:8:15
+error[E0658]: panicking in constants is unstable
+ --> $DIR/assert.rs:7:15
|
LL | const _: () = assert!(true);
| ^^^^^^^^^^^^^
|
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+ = note: see issue #51999 <https://github.com/rust-lang/rust/issues/51999> for more information
+ = help: add `#![feature(const_panic)]` to the crate attributes to enable
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/assert.rs:12:15
+error[E0658]: panicking in constants is unstable
+ --> $DIR/assert.rs:10:15
|
LL | const _: () = assert!(false);
| ^^^^^^^^^^^^^^
|
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+ = note: see issue #51999 <https://github.com/rust-lang/rust/issues/51999> for more information
+ = help: add `#![feature(const_panic)]` to the crate attributes to enable
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
// run-pass
#![feature(const_panic)]
-#![feature(const_if_match)]
-#![feature(const_loop)]
#![feature(const_fn)]
const X: u32 = 4;
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/drop-fail.rs:10:9
+ --> $DIR/drop-fail.rs:8:9
|
LL | let x = Some(Vec::new());
| ^ constants cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/drop-fail.rs:41:9
+ --> $DIR/drop-fail.rs:39:9
|
LL | let mut tmp = None;
| ^^^^^^^ constants cannot evaluate destructors
// revisions: stock precise
-#![feature(const_if_match)]
-#![feature(const_loop)]
#![cfg_attr(precise, feature(const_precise_live_drops))]
// `x` is *not* always moved into the final value and may be dropped inside the initializer.
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/drop-fail.rs:10:9
+ --> $DIR/drop-fail.rs:8:9
|
LL | let x = Some(Vec::new());
| ^ constants cannot evaluate destructors
+...
+LL | };
+ | - value is dropped here
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/drop-fail.rs:23:9
+ --> $DIR/drop-fail.rs:21:9
|
LL | let vec_tuple = (Vec::new(),);
| ^^^^^^^^^ constants cannot evaluate destructors
+...
+LL | };
+ | - value is dropped here
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/drop-fail.rs:31:9
+ --> $DIR/drop-fail.rs:29:9
|
LL | let x: Result<_, Vec<i32>> = Ok(Vec::new());
| ^ constants cannot evaluate destructors
+...
+LL | };
+ | - value is dropped here
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/drop-fail.rs:41:9
+ --> $DIR/drop-fail.rs:39:9
|
LL | let mut tmp = None;
| ^^^^^^^ constants cannot evaluate destructors
+...
+LL | };
+ | - value is dropped here
error: aborting due to 4 previous errors
// run-pass
// revisions: stock precise
-#![feature(const_if_match)]
-#![feature(const_loop)]
#![cfg_attr(precise, feature(const_precise_live_drops))]
// `x` is always moved into the final value and is not dropped inside the initializer.
// run-pass
// gate-test-const_precise_live_drops
-#![feature(const_if_match)]
-#![feature(const_loop)]
#![feature(const_precise_live_drops)]
const _: Vec<i32> = {
// check-pass
-#![feature(const_if_match)]
-
enum E {
A,
B,
+++ /dev/null
-error: fatal error triggered by #[rustc_error]
- --> $DIR/feature-gate-const-if-match.rs:108:1
- |
-LL | / fn main() {
-LL | | let _ = [0; {
-LL | | let x = if false { 0 } else { 1 };
-LL | |
-... |
-LL | | }];
-LL | | }
- | |_^
-
-error: aborting due to previous error
-
-// Ensure that `if`, `if let` and `match` are only allowed in the various const contexts when
-// `#![feature(const_if_match)]` is enabled. When the feature gate is removed, the `#[rustc_error]`
-// on `main` should be removed and this test converted to `check-pass`.
+// check-pass
-// revisions: stock if_match
+const _: i32 = if true { 5 } else { 6 };
-#![feature(rustc_attrs)]
-#![cfg_attr(if_match, feature(const_if_match))]
+const _: i32 = if let Some(true) = Some(false) { 0 } else { 1 };
-const _: i32 = if true { //[stock]~ ERROR `if` is not allowed in a `const`
- 5
-} else {
- 6
-};
-
-const _: i32 = if let Some(true) = Some(false) { //[stock]~ ERROR `if` is not allowed in a `const`
- 0
-} else {
- 1
-};
-
-const _: i32 = match 1 { //[stock]~ ERROR `match` is not allowed in a `const`
+const _: i32 = match 1 {
2 => 3,
4 => 5,
_ => 0,
static FOO: i32 = {
let x = if true { 0 } else { 1 };
- //[stock]~^ ERROR `if` is not allowed in a `static`
- let x = match x { 0 => 1, _ => 0 };
- //[stock]~^ ERROR `match` is not allowed in a `static`
+ let x = match x {
+ 0 => 1,
+ _ => 0,
+ };
if let Some(x) = Some(x) { x } else { 1 }
- //[stock]~^ ERROR `if` is not allowed in a `static`
};
static mut BAR: i32 = {
let x = if true { 0 } else { 1 };
- //[stock]~^ ERROR `if` is not allowed in a `static mut`
- let x = match x { 0 => 1, _ => 0 };
- //[stock]~^ ERROR `match` is not allowed in a `static mut`
+ let x = match x {
+ 0 => 1,
+ _ => 0,
+ };
if let Some(x) = Some(x) { x } else { 1 }
- //[stock]~^ ERROR `if` is not allowed in a `static mut`
};
const fn if_() -> i32 {
- if true { 5 } else { 6 } //[stock]~ ERROR `if` is not allowed in a `const fn`
+ if true { 5 } else { 6 }
}
const fn if_let(a: Option<bool>) -> i32 {
- if let Some(true) = a { //[stock]~ ERROR `if` is not allowed in a `const fn`
- 0
- } else {
- 1
- }
+ if let Some(true) = a { 0 } else { 1 }
}
const fn match_(i: i32) -> i32 {
- match i { //[stock]~ ERROR `match` is not allowed in a `const fn`
+ match i {
i if i > 10 => i,
1 => 2,
- _ => 0
+ _ => 0,
}
}
pub trait Foo {
const IF: i32 = if true { 5 } else { 6 };
- //[stock]~^ ERROR `if` is not allowed in a `const`
-
const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
- //[stock]~^ ERROR `if` is not allowed in a `const`
-
- const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
- //[stock]~^ ERROR `match` is not allowed in a `const`
+ const MATCH: i32 = match 0 {
+ 1 => 2,
+ _ => 0,
+ };
}
impl Foo for () {
const IF: i32 = if true { 5 } else { 6 };
- //[stock]~^ ERROR `if` is not allowed in a `const`
-
const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
- //[stock]~^ ERROR `if` is not allowed in a `const`
-
- const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
- //[stock]~^ ERROR `match` is not allowed in a `const`
+ const MATCH: i32 = match 0 {
+ 1 => 2,
+ _ => 0,
+ };
}
fn non_const_outside() {
const fn const_inside(y: bool) -> i32 {
let x = if y { 0 } else { 1 };
- //[stock]~^ ERROR `if` is not allowed in a `const fn`
- let x = match x { 0 => 1, _ => 0 };
- //[stock]~^ ERROR `match` is not allowed in a `const fn`
+ let x = match x {
+ 0 => 1,
+ _ => 0,
+ };
if let Some(x) = Some(x) { x } else { 1 }
- //[stock]~^ ERROR `if` is not allowed in a `const fn`
}
}
const fn const_outside() {
fn non_const_inside(y: bool) -> i32 {
let x = if y { 0 } else { 1 };
- let x = match x { 0 => 1, _ => 0 };
+ let x = match x {
+ 0 => 1,
+ _ => 0,
+ };
if let Some(x) = Some(x) { x } else { 1 }
}
}
-#[rustc_error]
-fn main() { //[if_match]~ ERROR fatal error triggered by #[rustc_error]
+fn main() {
let _ = [0; {
let x = if false { 0 } else { 1 };
- //[stock]~^ ERROR `if` is not allowed in a `const`
- let x = match x { 0 => 1, _ => 0 };
- //[stock]~^ ERROR `match` is not allowed in a `const`
+ let x = match x {
+ 0 => 1,
+ _ => 0,
+ };
if let Some(x) = Some(x) { x } else { 1 }
- //[stock]~^ ERROR `if` is not allowed in a `const`
}];
}
+++ /dev/null
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:10:16
- |
-LL | const _: i32 = if true {
- | ________________^
-LL | | 5
-LL | | } else {
-LL | | 6
-LL | | };
- | |_^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:16:16
- |
-LL | const _: i32 = if let Some(true) = Some(false) {
- | ________________^
-LL | | 0
-LL | | } else {
-LL | | 1
-LL | | };
- | |_^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:22:16
- |
-LL | const _: i32 = match 1 {
- | ________________^
-LL | | 2 => 3,
-LL | | 4 => 5,
-LL | | _ => 0,
-LL | | };
- | |_^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `static`
- --> $DIR/feature-gate-const-if-match.rs:29:13
- |
-LL | let x = if true { 0 } else { 1 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `static`
- --> $DIR/feature-gate-const-if-match.rs:31:13
- |
-LL | let x = match x { 0 => 1, _ => 0 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `static`
- --> $DIR/feature-gate-const-if-match.rs:33:5
- |
-LL | if let Some(x) = Some(x) { x } else { 1 }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `static mut`
- --> $DIR/feature-gate-const-if-match.rs:38:13
- |
-LL | let x = if true { 0 } else { 1 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `static mut`
- --> $DIR/feature-gate-const-if-match.rs:40:13
- |
-LL | let x = match x { 0 => 1, _ => 0 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `static mut`
- --> $DIR/feature-gate-const-if-match.rs:42:5
- |
-LL | if let Some(x) = Some(x) { x } else { 1 }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const fn`
- --> $DIR/feature-gate-const-if-match.rs:47:5
- |
-LL | if true { 5 } else { 6 }
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const fn`
- --> $DIR/feature-gate-const-if-match.rs:51:5
- |
-LL | / if let Some(true) = a {
-LL | | 0
-LL | | } else {
-LL | | 1
-LL | | }
- | |_____^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const fn`
- --> $DIR/feature-gate-const-if-match.rs:59:5
- |
-LL | / match i {
-LL | | i if i > 10 => i,
-LL | | 1 => 2,
-LL | | _ => 0
-LL | | }
- | |_____^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const fn`
- --> $DIR/feature-gate-const-if-match.rs:90:17
- |
-LL | let x = if y { 0 } else { 1 };
- | ^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const fn`
- --> $DIR/feature-gate-const-if-match.rs:92:17
- |
-LL | let x = match x { 0 => 1, _ => 0 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const fn`
- --> $DIR/feature-gate-const-if-match.rs:94:9
- |
-LL | if let Some(x) = Some(x) { x } else { 1 }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:110:17
- |
-LL | let x = if false { 0 } else { 1 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:112:17
- |
-LL | let x = match x { 0 => 1, _ => 0 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:114:9
- |
-LL | if let Some(x) = Some(x) { x } else { 1 }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:67:21
- |
-LL | const IF: i32 = if true { 5 } else { 6 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:70:25
- |
-LL | const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:73:24
- |
-LL | const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:78:21
- |
-LL | const IF: i32 = if true { 5 } else { 6 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:81:25
- |
-LL | const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:84:24
- |
-LL | const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error: aborting due to 24 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
// Ensure that *any* assignment to the return place of a value with interior mutability
// disqualifies it from promotion.
-#![feature(const_if_match)]
-#![feature(const_loop)]
-
use std::cell::Cell;
const X: Option<Cell<i32>> = {
z
};
-
fn main() {
let x: &'static _ = &X; //~ ERROR temporary value dropped while borrowed
let y: &'static _ = &Y; //~ ERROR temporary value dropped while borrowed
error[E0716]: temporary value dropped while borrowed
- --> $DIR/interior-mutability.rs:44:26
+ --> $DIR/interior-mutability.rs:40:26
|
LL | let x: &'static _ = &X;
| ---------- ^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/interior-mutability.rs:45:26
+ --> $DIR/interior-mutability.rs:41:26
|
LL | let y: &'static _ = &Y;
| ---------- ^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/interior-mutability.rs:46:26
+ --> $DIR/interior-mutability.rs:42:26
|
LL | let z: &'static _ = &Z;
| ---------- ^ creates a temporary which is freed while still in use
+++ /dev/null
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
- --> $DIR/issue-46843.rs:11:26
- |
-LL | pub const Q: i32 = match non_const() {
- | ^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0015`.
-// revisions: stock if_match
-
-#![cfg_attr(if_match, feature(const_if_match))]
-
-enum Thing { This, That }
+enum Thing {
+ This,
+ That,
+}
fn non_const() -> Thing {
Thing::This
}
pub const Q: i32 = match non_const() {
- //[stock]~^ ERROR `match` is not allowed in a `const`
- //[if_match]~^^ ERROR calls in constants are limited to constant functions
+ //~^ ERROR calls in constants are limited to constant functions
Thing::This => 1,
Thing::That => 0
};
--- /dev/null
+error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/issue-46843.rs:10:26
+ |
+LL | pub const Q: i32 = match non_const() {
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
+++ /dev/null
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/issue-46843.rs:11:20
- |
-LL | pub const Q: i32 = match non_const() {
- | ____________________^
-LL | |
-LL | |
-LL | | Thing::This => 1,
-LL | | Thing::That => 0
-LL | | };
- | |_^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-error[E0317]: `if` may be missing an `else` clause
- --> $DIR/issue-50577.rs:7:16
- |
-LL | Drop = assert_eq!(1, 1)
- | ^^^^^^^^^^^^^^^^
- | |
- | expected `()`, found `isize`
- | found here
- |
- = note: `if` expressions without `else` evaluate to `()`
- = help: consider adding an `else` block that evaluates to the expected type
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0317`.
-// revisions: stock if_match
-
-#![cfg_attr(if_match, feature(const_if_match))]
-
fn main() {
enum Foo {
- Drop = assert_eq!(1, 1)
- //[stock,if_match]~^ ERROR `if` may be missing an `else` clause
- //[stock]~^^ ERROR `match` is not allowed in a `const`
- //[stock]~| ERROR `match` is not allowed in a `const`
- //[stock]~| ERROR `if` is not allowed in a `const`
+ Drop = assert_eq!(1, 1),
+ //~^ ERROR `if` may be missing an `else` clause
}
}
--- /dev/null
+error[E0317]: `if` may be missing an `else` clause
+ --> $DIR/issue-50577.rs:3:16
+ |
+LL | Drop = assert_eq!(1, 1),
+ | ^^^^^^^^^^^^^^^^
+ | |
+ | expected `()`, found `isize`
+ | found here
+ |
+ = note: `if` expressions without `else` evaluate to `()`
+ = help: consider adding an `else` block that evaluates to the expected type
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0317`.
+++ /dev/null
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/issue-50577.rs:7:16
- |
-LL | Drop = assert_eq!(1, 1)
- | ^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/issue-50577.rs:7:16
- |
-LL | Drop = assert_eq!(1, 1)
- | ^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/issue-50577.rs:7:16
- |
-LL | Drop = assert_eq!(1, 1)
- | ^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0317]: `if` may be missing an `else` clause
- --> $DIR/issue-50577.rs:7:16
- |
-LL | Drop = assert_eq!(1, 1)
- | ^^^^^^^^^^^^^^^^
- | |
- | expected `()`, found `isize`
- | found here
- |
- = note: `if` expressions without `else` evaluate to `()`
- = help: consider adding an `else` block that evaluates to the expected type
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0317, E0658.
-For more information about an error, try `rustc --explain E0317`.
+++ /dev/null
-error[E0744]: `for` is not allowed in a `const`
- --> $DIR/loop.rs:63:5
- |
-LL | / for i in 0..4 {
-LL | | x += i;
-LL | | }
- | |_____^
-
-error[E0744]: `for` is not allowed in a `const`
- --> $DIR/loop.rs:67:5
- |
-LL | / for i in 0..4 {
-LL | | x += i;
-LL | | }
- | |_____^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0744`.
+++ /dev/null
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/loop.rs:10:15
- |
-LL | const _: () = loop {};
- | ^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `static`
- --> $DIR/loop.rs:12:19
- |
-LL | static FOO: i32 = loop { break 4; };
- | ^^^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const fn`
- --> $DIR/loop.rs:15:5
- |
-LL | loop {}
- | ^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const fn`
- --> $DIR/loop.rs:28:9
- |
-LL | loop {}
- | ^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:40:9
- |
-LL | while false {}
- | ^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:49:5
- |
-LL | / while x < 4 {
-LL | | x += 1;
-LL | | }
- | |_____^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:53:5
- |
-LL | / while x < 8 {
-LL | | x += 1;
-LL | | }
- | |_____^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0744]: `for` is not allowed in a `const`
- --> $DIR/loop.rs:63:5
- |
-LL | / for i in 0..4 {
-LL | | x += i;
-LL | | }
- | |_____^
-
-error[E0744]: `for` is not allowed in a `const`
- --> $DIR/loop.rs:67:5
- |
-LL | / for i in 0..4 {
-LL | | x += i;
-LL | | }
- | |_____^
-
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/loop.rs:77:5
- |
-LL | / loop {
-LL | | x += 1;
-LL | | if x == 4 {
-LL | | break;
-LL | | }
-LL | | }
- | |_____^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/loop.rs:84:5
- |
-LL | / loop {
-LL | | x += 1;
-LL | | if x == 8 {
-LL | | break;
-LL | | }
-LL | | }
- | |_____^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:96:5
- |
-LL | while let None = Some(x) { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:97:5
- |
-LL | while let None = Some(x) { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/loop.rs:19:22
- |
-LL | const BAR: i32 = loop { break 4; };
- | ^^^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/loop.rs:23:22
- |
-LL | const BAR: i32 = loop { break 4; };
- | ^^^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error: aborting due to 15 previous errors
-
-Some errors have detailed explanations: E0658, E0744.
-For more information about an error, try `rustc --explain E0658`.
+++ /dev/null
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:40:9
- |
-LL | while false {}
- | ^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
- = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
-
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:49:5
- |
-LL | / while x < 4 {
-LL | | x += 1;
-LL | | }
- | |_____^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
- = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
-
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:53:5
- |
-LL | / while x < 8 {
-LL | | x += 1;
-LL | | }
- | |_____^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
- = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
-
-error[E0744]: `for` is not allowed in a `const`
- --> $DIR/loop.rs:63:5
- |
-LL | / for i in 0..4 {
-LL | | x += i;
-LL | | }
- | |_____^
-
-error[E0744]: `for` is not allowed in a `const`
- --> $DIR/loop.rs:67:5
- |
-LL | / for i in 0..4 {
-LL | | x += i;
-LL | | }
- | |_____^
-
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/loop.rs:79:9
- |
-LL | / if x == 4 {
-LL | | break;
-LL | | }
- | |_________^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/loop.rs:86:9
- |
-LL | / if x == 8 {
-LL | | break;
-LL | | }
- | |_________^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:96:5
- |
-LL | while let None = Some(x) { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
- = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
-
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:97:5
- |
-LL | while let None = Some(x) { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
- = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
-
-error: aborting due to 9 previous errors
-
-Some errors have detailed explanations: E0658, E0744.
-For more information about an error, try `rustc --explain E0658`.
-// Ensure that loops are forbidden in a const context unless `#![feature(const_loop)]` is enabled.
-// `while` loops require `#![feature(const_if_match)]` to be enabled as well.
+const _: () = loop { break (); };
-// gate-test-const_loop
-// revisions: stock if_match loop_ both
-
-#![cfg_attr(any(both, if_match), feature(const_if_match))]
-#![cfg_attr(any(both, loop_), feature(const_loop))]
-
-const _: () = loop {}; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
-
-static FOO: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `static`
+static FOO: i32 = loop { break 4; };
const fn foo() {
- loop {} //[stock,if_match]~ ERROR `loop` is not allowed in a `const fn`
+ loop {}
}
pub trait Foo {
- const BAR: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
+ const BAR: i32 = loop { break 4; };
}
impl Foo for () {
- const BAR: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
+ const BAR: i32 = loop { break 4; };
}
fn non_const_outside() {
const fn const_inside() {
- loop {} //[stock,if_match]~ ERROR `loop` is not allowed in a `const fn`
+ loop {}
}
}
fn main() {
let x = [0; {
while false {}
- //[stock,if_match,loop_]~^ ERROR `while` is not allowed in a `const`
4
}];
}
const _: i32 = {
let mut x = 0;
- while x < 4 { //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
+ while x < 4 {
x += 1;
}
- while x < 8 { //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
+ while x < 8 {
x += 1;
}
const _: i32 = {
let mut x = 0;
- for i in 0..4 { //[stock,if_match,loop_,both]~ ERROR `for` is not allowed in a `const`
+ for i in 0..4 { //~ ERROR `for` is not allowed in a `const`
x += i;
}
- for i in 0..4 { //[stock,if_match,loop_,both]~ ERROR `for` is not allowed in a `const`
+ for i in 0..4 { //~ ERROR `for` is not allowed in a `const`
x += i;
}
const _: i32 = {
let mut x = 0;
- loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
+ loop {
x += 1;
- if x == 4 { //[stock,loop_]~ ERROR `if` is not allowed in a `const`
+ if x == 4 {
break;
}
}
- loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
+ loop {
x += 1;
- if x == 8 { //[stock,loop_]~ ERROR `if` is not allowed in a `const`
+ if x == 8 {
break;
}
}
const _: i32 = {
let mut x = 0;
- while let None = Some(x) { } //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
- while let None = Some(x) { } //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
+ while let None = Some(x) { }
+ while let None = Some(x) { }
x
};
--- /dev/null
+error[E0744]: `for` is not allowed in a `const`
+ --> $DIR/loop.rs:53:5
+ |
+LL | / for i in 0..4 {
+LL | | x += i;
+LL | | }
+ | |_____^
+
+error[E0744]: `for` is not allowed in a `const`
+ --> $DIR/loop.rs:57:5
+ |
+LL | / for i in 0..4 {
+LL | | x += i;
+LL | | }
+ | |_____^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0744`.
+++ /dev/null
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/loop.rs:10:15
- |
-LL | const _: () = loop {};
- | ^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `static`
- --> $DIR/loop.rs:12:19
- |
-LL | static FOO: i32 = loop { break 4; };
- | ^^^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const fn`
- --> $DIR/loop.rs:15:5
- |
-LL | loop {}
- | ^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const fn`
- --> $DIR/loop.rs:28:9
- |
-LL | loop {}
- | ^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:40:9
- |
-LL | while false {}
- | ^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:49:5
- |
-LL | / while x < 4 {
-LL | | x += 1;
-LL | | }
- | |_____^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:53:5
- |
-LL | / while x < 8 {
-LL | | x += 1;
-LL | | }
- | |_____^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0744]: `for` is not allowed in a `const`
- --> $DIR/loop.rs:63:5
- |
-LL | / for i in 0..4 {
-LL | | x += i;
-LL | | }
- | |_____^
-
-error[E0744]: `for` is not allowed in a `const`
- --> $DIR/loop.rs:67:5
- |
-LL | / for i in 0..4 {
-LL | | x += i;
-LL | | }
- | |_____^
-
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/loop.rs:77:5
- |
-LL | / loop {
-LL | | x += 1;
-LL | | if x == 4 {
-LL | | break;
-LL | | }
-LL | | }
- | |_____^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/loop.rs:79:9
- |
-LL | / if x == 4 {
-LL | | break;
-LL | | }
- | |_________^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/loop.rs:84:5
- |
-LL | / loop {
-LL | | x += 1;
-LL | | if x == 8 {
-LL | | break;
-LL | | }
-LL | | }
- | |_____^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
- --> $DIR/loop.rs:86:9
- |
-LL | / if x == 8 {
-LL | | break;
-LL | | }
- | |_________^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:96:5
- |
-LL | while let None = Some(x) { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/loop.rs:97:5
- |
-LL | while let None = Some(x) { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/loop.rs:19:22
- |
-LL | const BAR: i32 = loop { break 4; };
- | ^^^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const`
- --> $DIR/loop.rs:23:22
- |
-LL | const BAR: i32 = loop { break 4; };
- | ^^^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error: aborting due to 17 previous errors
-
-Some errors have detailed explanations: E0658, E0744.
-For more information about an error, try `rustc --explain E0658`.
// run-pass
-#![feature(const_if_match)]
#![feature(const_panic)]
const X: i32 = {
+++ /dev/null
-error: fatal error triggered by #[rustc_error]
- --> $DIR/short-circuit.rs:14:1
- |
-LL | fn main() {}
- | ^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-// Test that both `&&` and `||` actually short-circuit when the `const_if_match` feature flag is
-// enabled. Without the feature flag, both sides are evaluated unconditionally.
+// run-pass
-// revisions: stock if_match
+// Test that both `&&` and `||` actually short-circuit.
+// Formerly, both sides were evaluated unconditionally
-#![feature(rustc_attrs)]
#![feature(const_panic)]
-#![cfg_attr(if_match, feature(const_if_match))]
-const _: bool = true || panic!(); //[stock]~ ERROR any use of this value will cause an error
-const _: bool = false && panic!(); //[stock]~ ERROR any use of this value will cause an error
+const TRUE: bool = true || panic!();
+const FALSE: bool = false && panic!();
-#[rustc_error]
-fn main() {} //[if_match]~ ERROR fatal error triggered by #[rustc_error]
+fn main() {
+ assert!(TRUE);
+ assert!(!FALSE);
+}
+++ /dev/null
-error: any use of this value will cause an error
- --> $DIR/short-circuit.rs:10:25
- |
-LL | const _: bool = true || panic!();
- | ------------------------^^^^^^^^-
- | |
- | the evaluated program panicked at 'explicit panic', $DIR/short-circuit.rs:10:25
- |
- = note: `#[deny(const_err)]` on by default
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: any use of this value will cause an error
- --> $DIR/short-circuit.rs:11:26
- |
-LL | const _: bool = false && panic!();
- | -------------------------^^^^^^^^-
- | |
- | the evaluated program panicked at 'explicit panic', $DIR/short-circuit.rs:11:26
- |
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 2 previous errors
-
// check-pass
-#![feature(const_if_match)]
-
enum Foo {
Prob,
}
// The `?` operator is still not const-evaluatable because it calls `From::from` on the error
// variant.
-#![feature(const_if_match)]
-
const fn opt() -> Option<i32> {
let x = Some(2);
x?; //~ ERROR `?` is not allowed in a `const fn`
error[E0744]: `?` is not allowed in a `const fn`
- --> $DIR/try.rs:8:5
+ --> $DIR/try.rs:6:5
|
LL | x?;
| ^^
+++ /dev/null
-const fn foo() {
- loop {} //~ ERROR `loop` is not allowed in a `const fn`
-}
-
-fn main() {}
+++ /dev/null
-error[E0658]: `loop` is not allowed in a `const fn`
- --> $DIR/loop_ice.rs:2:5
- |
-LL | loop {}
- | ^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
//~^ ERROR casting pointers to ints is unstable
const fn foo30_6() -> bool { let x = true; x }
-const fn foo36(a: bool, b: bool) -> bool { a && b }
-//~^ ERROR loops and conditional expressions are not stable in const fn
-const fn foo37(a: bool, b: bool) -> bool { a || b }
-//~^ ERROR loops and conditional expressions are not stable in const fn
const fn inc(x: &mut i32) { *x += 1 }
//~^ ERROR mutable references in const fn are unstable
+// ok
+const fn foo36(a: bool, b: bool) -> bool { a && b }
+const fn foo37(a: bool, b: bool) -> bool { a || b }
+
fn main() {}
impl<T: std::fmt::Debug> Foo<T> {
--> $DIR/min_const_fn.rs:37:25
|
LL | const fn into_inner(self) -> T { self.0 }
- | ^^^^ constant functions cannot evaluate destructors
+ | ^^^^ - value is dropped here
+ | |
+ | constant functions cannot evaluate destructors
error[E0723]: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:39:36
--> $DIR/min_const_fn.rs:44:28
|
LL | const fn into_inner_lt(self) -> T { self.0 }
- | ^^^^ constant functions cannot evaluate destructors
+ | ^^^^ - value is dropped here
+ | |
+ | constant functions cannot evaluate destructors
error[E0723]: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:46:42
--> $DIR/min_const_fn.rs:51:27
|
LL | const fn into_inner_s(self) -> T { self.0 }
- | ^^^^ constant functions cannot evaluate destructors
+ | ^^^^ - value is dropped here
+ | |
+ | constant functions cannot evaluate destructors
error[E0723]: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:53:38
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
= help: add `#![feature(const_fn)]` to the crate attributes to enable
-error[E0723]: loops and conditional expressions are not stable in const fn
- --> $DIR/min_const_fn.rs:101:44
- |
-LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
- | ^^^^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn)]` to the crate attributes to enable
-
-error[E0723]: loops and conditional expressions are not stable in const fn
- --> $DIR/min_const_fn.rs:103:44
- |
-LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
- | ^^^^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn)]` to the crate attributes to enable
-
error[E0723]: mutable references in const fn are unstable
- --> $DIR/min_const_fn.rs:105:14
+ --> $DIR/min_const_fn.rs:101:14
|
LL | const fn inc(x: &mut i32) { *x += 1 }
| ^
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
= help: add `#![feature(const_fn)]` to the crate attributes to enable
-error: aborting due to 32 previous errors
+error: aborting due to 30 previous errors
Some errors have detailed explanations: E0493, E0723.
For more information about an error, try `rustc --explain E0493`.
// aux-build:static_cross_crate.rs
#![allow(const_err)]
-// `const_if_match` is a HIR check and thus needed even when unleashed.
-#![feature(exclusive_range_pattern, half_open_range_patterns, const_if_match)]
+#![feature(exclusive_range_pattern, half_open_range_patterns)]
extern crate static_cross_crate;
error[E0080]: it is undefined behavior to use this value
- --> $DIR/const_refers_to_static_cross_crate.rs:12:1
+ --> $DIR/const_refers_to_static_cross_crate.rs:11:1
|
LL | / const SLICE_MUT: &[u8; 1] = {
LL | |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
error: could not evaluate constant pattern
- --> $DIR/const_refers_to_static_cross_crate.rs:40:9
+ --> $DIR/const_refers_to_static_cross_crate.rs:39:9
|
LL | SLICE_MUT => true,
| ^^^^^^^^^
error[E0080]: it is undefined behavior to use this value
- --> $DIR/const_refers_to_static_cross_crate.rs:18:1
+ --> $DIR/const_refers_to_static_cross_crate.rs:17:1
|
LL | / const U8_MUT: &u8 = {
LL | |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
error: could not evaluate constant pattern
- --> $DIR/const_refers_to_static_cross_crate.rs:49:9
+ --> $DIR/const_refers_to_static_cross_crate.rs:48:9
|
LL | U8_MUT => true,
| ^^^^^^
warning: any use of this value will cause an error
- --> $DIR/const_refers_to_static_cross_crate.rs:27:14
+ --> $DIR/const_refers_to_static_cross_crate.rs:26:14
|
LL | / const U8_MUT2: &u8 = {
LL | | unsafe { &(*static_cross_crate::ZERO_REF)[0] }
| |__-
|
note: the lint level is defined here
- --> $DIR/const_refers_to_static_cross_crate.rs:25:8
+ --> $DIR/const_refers_to_static_cross_crate.rs:24:8
|
LL | #[warn(const_err)]
| ^^^^^^^^^
error: could not evaluate constant pattern
- --> $DIR/const_refers_to_static_cross_crate.rs:60:9
+ --> $DIR/const_refers_to_static_cross_crate.rs:59:9
|
LL | U8_MUT2 => true,
| ^^^^^^^
warning: any use of this value will cause an error
- --> $DIR/const_refers_to_static_cross_crate.rs:33:51
+ --> $DIR/const_refers_to_static_cross_crate.rs:32:51
|
LL | / const U8_MUT3: &u8 = {
LL | | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
| |__-
|
note: the lint level is defined here
- --> $DIR/const_refers_to_static_cross_crate.rs:31:8
+ --> $DIR/const_refers_to_static_cross_crate.rs:30:8
|
LL | #[warn(const_err)]
| ^^^^^^^^^
error: could not evaluate constant pattern
- --> $DIR/const_refers_to_static_cross_crate.rs:68:9
+ --> $DIR/const_refers_to_static_cross_crate.rs:67:9
|
LL | U8_MUT3 => true,
| ^^^^^^^
error: could not evaluate constant pattern
- --> $DIR/const_refers_to_static_cross_crate.rs:40:9
+ --> $DIR/const_refers_to_static_cross_crate.rs:39:9
|
LL | SLICE_MUT => true,
| ^^^^^^^^^
error: could not evaluate constant pattern
- --> $DIR/const_refers_to_static_cross_crate.rs:49:9
+ --> $DIR/const_refers_to_static_cross_crate.rs:48:9
|
LL | U8_MUT => true,
| ^^^^^^
error: could not evaluate constant pattern
- --> $DIR/const_refers_to_static_cross_crate.rs:60:9
+ --> $DIR/const_refers_to_static_cross_crate.rs:59:9
|
LL | U8_MUT2 => true,
| ^^^^^^^
error: could not evaluate constant pattern
- --> $DIR/const_refers_to_static_cross_crate.rs:68:9
+ --> $DIR/const_refers_to_static_cross_crate.rs:67:9
|
LL | U8_MUT3 => true,
| ^^^^^^^
warning: skipping const checks
|
help: skipping check that does not even have a feature gate
- --> $DIR/const_refers_to_static_cross_crate.rs:15:15
+ --> $DIR/const_refers_to_static_cross_crate.rs:14:15
|
LL | unsafe { &static_cross_crate::ZERO }
| ^^^^^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
- --> $DIR/const_refers_to_static_cross_crate.rs:15:15
+ --> $DIR/const_refers_to_static_cross_crate.rs:14:15
|
LL | unsafe { &static_cross_crate::ZERO }
| ^^^^^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
- --> $DIR/const_refers_to_static_cross_crate.rs:21:15
+ --> $DIR/const_refers_to_static_cross_crate.rs:20:15
|
LL | unsafe { &static_cross_crate::ZERO[0] }
| ^^^^^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
- --> $DIR/const_refers_to_static_cross_crate.rs:21:15
+ --> $DIR/const_refers_to_static_cross_crate.rs:20:15
|
LL | unsafe { &static_cross_crate::ZERO[0] }
| ^^^^^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
- --> $DIR/const_refers_to_static_cross_crate.rs:21:15
+ --> $DIR/const_refers_to_static_cross_crate.rs:20:15
|
LL | unsafe { &static_cross_crate::ZERO[0] }
| ^^^^^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
- --> $DIR/const_refers_to_static_cross_crate.rs:27:17
+ --> $DIR/const_refers_to_static_cross_crate.rs:26:17
|
LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
- --> $DIR/const_refers_to_static_cross_crate.rs:33:20
+ --> $DIR/const_refers_to_static_cross_crate.rs:32:20
|
LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
- --> $DIR/const_refers_to_static_cross_crate.rs:33:20
- |
-LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check that does not even have a feature gate
- --> $DIR/const_refers_to_static_cross_crate.rs:33:20
+ --> $DIR/const_refers_to_static_cross_crate.rs:32:20
|
LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: skipping check for `const_panic` feature
- --> $DIR/const_refers_to_static_cross_crate.rs:33:77
+ --> $DIR/const_refers_to_static_cross_crate.rs:32:77
|
LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
| ^^^^^^^^
help: skipping check that does not even have a feature gate
- --> $DIR/const_refers_to_static_cross_crate.rs:33:20
+ --> $DIR/const_refers_to_static_cross_crate.rs:32:20
|
LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
--> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:11:20
|
LL | const F: u32 = (U::X, 42).1;
- | ^^^^^^^^^^ constants cannot evaluate destructors
+ | ^^^^^^^^^^ - value is dropped here
+ | |
+ | constants cannot evaluate destructors
error: aborting due to previous error
static CMP: () = {
let x = &0 as *const _;
- let _v = x == x; //~ NOTE in this
+ let _v = x == x;
//~^ ERROR could not evaluate static initializer
//~| NOTE pointer arithmetic or comparison
- //~| NOTE in this
};
static INT_PTR_ARITH: () = unsafe {
let x: usize = std::mem::transmute(&0);
- let _v = x + 0; //~ NOTE in this
+ let _v = x + 0;
//~^ ERROR could not evaluate static initializer
//~| NOTE pointer-to-integer cast
};
| ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
error[E0080]: could not evaluate static initializer
- --> $DIR/ptr_arith.rs:17:14
+ --> $DIR/ptr_arith.rs:16:14
|
LL | let _v = x + 0;
| ^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
warning: skipping const checks
|
-help: skipping check for `const_compare_raw_pointers` feature
+help: skipping check that does not even have a feature gate
--> $DIR/ptr_arith.rs:9:14
|
LL | let _v = x == x;
| ^^^^^^
help: skipping check that does not even have a feature gate
- --> $DIR/ptr_arith.rs:16:20
+ --> $DIR/ptr_arith.rs:15:20
|
LL | let x: usize = std::mem::transmute(&0);
| ^^^^^^^^^^^^^^^^^^^^^^^
--- /dev/null
+// compile-flags: -Zunleash-the-miri-inside-of-you
+// run-pass
+
+#![feature(const_raw_ptr_comparison)]
+
+const EMPTY_SLICE: &[i32] = &[];
+const EMPTY_EQ: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[] as *const _);
+const EMPTY_EQ2: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[] as *const _);
+const EMPTY_NE: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[1] as *const _);
+const EMPTY_NE2: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[1] as *const _);
+
+fn main() {
+ assert!(!EMPTY_EQ);
+ assert!(!EMPTY_EQ2);
+ assert!(!EMPTY_NE);
+ assert!(!EMPTY_NE2);
+}
LL | intrinsics::ptr_offset_from(self, origin)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
- | exact_div: 1isize cannot be divided by 2isize without remainder
+ | exact_div: 1_isize cannot be divided by 2_isize without remainder
| inside `std::ptr::const_ptr::<impl *const u16>::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
| inside `NOT_MULTIPLE_OF_SIZE` at $DIR/offset_from_ub.rs:31:14
|
+error[E0764]: mutable references are not allowed in constants
+ --> $DIR/projection_qualif.rs:10:27
+ |
+LL | let b: *mut u32 = &mut a;
+ | ^^^^^^ `&mut` is only allowed in `const fn`
+
error[E0658]: dereferencing raw pointers in constants is unstable
--> $DIR/projection_qualif.rs:11:18
|
= note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
= help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
-error: aborting due to previous error
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0658, E0764.
+For more information about an error, try `rustc --explain E0658`.
const FOO: &u32 = {
let mut a = 42;
{
- let b: *mut u32 = &mut a; //[stock]~ ERROR may only refer to immutable values
+ let b: *mut u32 = &mut a; //~ ERROR mutable references are not allowed in constants
unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants
//[stock]~^ contains unimplemented expression
}
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
--> $DIR/projection_qualif.rs:10:27
|
LL | let b: *mut u32 = &mut a;
- | ^^^^^^ constants require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^ `&mut` is only allowed in `const fn`
error[E0658]: dereferencing raw pointers in constants is unstable
--> $DIR/projection_qualif.rs:11:18
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0019, E0658.
+Some errors have detailed explanations: E0019, E0658, E0764.
For more information about an error, try `rustc --explain E0019`.
-// run-pass
+// We are keeping this test in case we decide to allow mutable references in statics again
#![feature(const_mut_refs)]
#![allow(const_err)]
-static OH_YES: &mut i32 = &mut 42;
-
+static OH_NO: &mut i32 = &mut 42;
+//~^ ERROR mutable references are not allowed in statics
fn main() {
- // Make sure `OH_YES` can be read.
- assert_eq!(*OH_YES, 42);
+ assert_eq!(*OH_NO, 42);
}
--- /dev/null
+error[E0764]: mutable references are not allowed in statics
+ --> $DIR/read_from_static_mut_ref.rs:5:26
+ |
+LL | static OH_NO: &mut i32 = &mut 42;
+ | ^^^^^^^ `&mut` is only allowed in `const fn`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0764`.
-error[E0080]: could not evaluate static initializer
- --> $DIR/static_mut_containing_mut_ref2.rs:7:45
+error[E0764]: mutable references are not allowed in statics
+ --> $DIR/static_mut_containing_mut_ref2.rs:7:46
|
LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0764`.
static mut STDERR_BUFFER_SPACE: u8 = 0;
pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
-//[mut_refs]~^ ERROR could not evaluate static initializer
-//[stock]~^^ ERROR references in statics may only refer to immutable values
+//~^ ERROR mutable references are not allowed in statics
//[stock]~| ERROR static contains unimplemented expression type
fn main() {}
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
--> $DIR/static_mut_containing_mut_ref2.rs:7:46
|
LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ statics require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn`
error[E0019]: static contains unimplemented expression type
--> $DIR/static_mut_containing_mut_ref2.rs:7:45
error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0019, E0658.
+Some errors have detailed explanations: E0019, E0764.
For more information about an error, try `rustc --explain E0019`.
// Tests that specialization does not cause optimizations running on polymorphic MIR to resolve
// to a `default` implementation.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Marker {}
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/trait_specialization.rs:8:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// gate was not enabled in libcore.
#![stable(feature = "core", since = "1.6.0")]
-#![feature(const_if_match)]
#![feature(rustc_const_unstable)]
#![feature(staged_api)]
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
- --> $DIR/unstable-const-fn-in-libcore.rs:24:26
+ --> $DIR/unstable-const-fn-in-libcore.rs:23:26
|
LL | Opt::None => f(),
| ^^^
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/unstable-const-fn-in-libcore.rs:19:53
+ --> $DIR/unstable-const-fn-in-libcore.rs:18:53
|
LL | const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
| ^ constant functions cannot evaluate destructors
+...
+LL | }
+ | - value is dropped here
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/unstable-const-fn-in-libcore.rs:19:47
+ --> $DIR/unstable-const-fn-in-libcore.rs:18:47
|
LL | const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
| ^^^^ constant functions cannot evaluate destructors
+...
+LL | }
+ | - value is dropped here
error: aborting due to 3 previous errors
|
= help: the trait `std::marker::Sized` is not implemented for `[isize]`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider relaxing the implicit `Sized` restriction
+ |
+LL | trait Foo<T: ?Sized> : Sized { fn take(self, x: &T) { } } // Note: T is sized
+ | ^^^^^^^^
error[E0277]: the size for values of type `[usize]` cannot be known at compilation time
--> $DIR/dst-sized-trait-param.rs:10:6
// run-pass
#![feature(const_panic)]
-#![feature(const_if_match)]
//! Make sure that we read and write enum discriminants correctly for corner cases caused
//! by layout optimizations.
const C: i32 = 2;
static mut M: i32 = 3;
-const CR: &'static mut i32 = &mut C; //~ ERROR E0658
-static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658
+const CR: &'static mut i32 = &mut C; //~ ERROR E0764
+static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0764
//~| ERROR E0019
//~| ERROR cannot borrow
-static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0658
-static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0658
+static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764
+static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0764
fn main() {}
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
--> $DIR/E0017.rs:5:30
|
LL | const CR: &'static mut i32 = &mut C;
- | ^^^^^^ constants require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^ `&mut` is only allowed in `const fn`
error[E0019]: static contains unimplemented expression type
--> $DIR/E0017.rs:6:39
|
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
--> $DIR/E0017.rs:6:39
|
LL | static STATIC_REF: &'static mut i32 = &mut X;
- | ^^^^^^ statics require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^ `&mut` is only allowed in `const fn`
error[E0596]: cannot borrow immutable static item `X` as mutable
--> $DIR/E0017.rs:6:39
LL | static STATIC_REF: &'static mut i32 = &mut X;
| ^^^^^^ cannot borrow as mutable
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
--> $DIR/E0017.rs:9:38
|
LL | static CONST_REF: &'static mut i32 = &mut C;
- | ^^^^^^ statics require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^ `&mut` is only allowed in `const fn`
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
--> $DIR/E0017.rs:10:52
|
LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M };
- | ^^^^^^ statics require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^ `&mut` is only allowed in `const fn`
error: aborting due to 6 previous errors
-Some errors have detailed explanations: E0019, E0596, E0658.
+Some errors have detailed explanations: E0019, E0596, E0764.
For more information about an error, try `rustc --explain E0019`.
enum Enum {
X = (1 << 500), //~ ERROR E0080
- //~| shift left with overflow
+ //~| attempt to shift left by 500_i32 which would overflow
Y = (1 / 0) //~ ERROR E0080
}
--> $DIR/E0080.rs:2:9
|
LL | X = (1 << 500),
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 500_i32 which would overflow
error[E0080]: evaluation of constant value failed
--> $DIR/E0080.rs:4:9
|
LL | Y = (1 / 0)
- | ^^^^^^^ attempt to divide by zero
+ | ^^^^^^^ attempt to divide 1_isize by zero
error: aborting due to 2 previous errors
static X: i32 = 1;
const C: i32 = 2;
-const CR: &'static mut i32 = &mut C; //~ ERROR E0658
-static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658
+const CR: &'static mut i32 = &mut C; //~ ERROR E0764
+static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0019
//~| ERROR cannot borrow
- //~| ERROR E0019
-static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0658
+ //~| ERROR E0764
+static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764
fn main() {}
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
--> $DIR/E0388.rs:4:30
|
LL | const CR: &'static mut i32 = &mut C;
- | ^^^^^^ constants require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^ `&mut` is only allowed in `const fn`
error[E0019]: static contains unimplemented expression type
--> $DIR/E0388.rs:5:39
|
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
--> $DIR/E0388.rs:5:39
|
LL | static STATIC_REF: &'static mut i32 = &mut X;
- | ^^^^^^ statics require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^ `&mut` is only allowed in `const fn`
error[E0596]: cannot borrow immutable static item `X` as mutable
--> $DIR/E0388.rs:5:39
LL | static STATIC_REF: &'static mut i32 = &mut X;
| ^^^^^^ cannot borrow as mutable
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
--> $DIR/E0388.rs:8:38
|
LL | static CONST_REF: &'static mut i32 = &mut C;
- | ^^^^^^ statics require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^ `&mut` is only allowed in `const fn`
error: aborting due to 5 previous errors
-Some errors have detailed explanations: E0019, E0596, E0658.
+Some errors have detailed explanations: E0019, E0596, E0764.
For more information about an error, try `rustc --explain E0019`.
-// gate-test-const_compare_raw_pointers
-
static FOO: i32 = 42;
static BAR: i32 = 42;
static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
-//~^ ERROR comparing raw pointers inside static
+//~^ ERROR pointers cannot be reliably compared during const eval
fn main() {
}
-error[E0658]: comparing raw pointers inside static
- --> $DIR/E0395.rs:6:29
+error: pointers cannot be reliably compared during const eval.
+ --> $DIR/E0395.rs:4:29
|
LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
- = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0658`.
#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
trait SpaceLlama {
fn fly(&self);
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/E0520.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0520]: `fly` specializes an item from a parent `impl`, but that item is not marked `default`
- --> $DIR/E0520.rs:16:5
+ --> $DIR/E0520.rs:17:5
|
LL | / impl<T: Clone> SpaceLlama for T {
LL | | fn fly(&self) {}
|
= note: to specialize, `fly` in the parent `impl` must be marked `default`
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0520`.
--> $DIR/E0604.rs:2:5
|
LL | 1u32 as char;
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^ invalid cast
error: aborting due to previous error
--> $DIR/E0605.rs:3:5
|
LL | x as Vec<u8>;
- | ^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0605]: non-primitive cast: `*const u8` as `&u8`
--> $DIR/E0605.rs:6:5
|
LL | v as &u8;
- | ^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to 2 previous errors
--> $DIR/error-festival.rs:25:5
|
LL | 0u32 as char;
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^ invalid cast
error[E0605]: non-primitive cast: `u8` as `std::vec::Vec<u8>`
--> $DIR/error-festival.rs:29:5
|
LL | x as Vec<u8>;
- | ^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0054]: cannot cast as `bool`
--> $DIR/error-festival.rs:33:24
enum Test {
DivZero = 1/0,
- //~^ attempt to divide by zero
+ //~^ attempt to divide 1_isize by zero
//~| ERROR evaluation of constant value failed
RemZero = 1%0,
- //~^ attempt to calculate the remainder with a divisor of zero
+ //~^ attempt to calculate the remainder of 1_isize with a divisor of zero
//~| ERROR evaluation of constant value failed
}
--> $DIR/eval-enum.rs:2:15
|
LL | DivZero = 1/0,
- | ^^^ attempt to divide by zero
+ | ^^^ attempt to divide 1_isize by zero
error[E0080]: evaluation of constant value failed
--> $DIR/eval-enum.rs:5:15
|
LL | RemZero = 1%0,
- | ^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^ attempt to calculate the remainder of 1_isize with a divisor of zero
error: aborting due to 2 previous errors
= help: within `Foo`, the trait `std::marker::Sized` is not implemented for `A`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required because it appears within the type `Foo`
+help: consider relaxing the implicit `Sized` restriction
+ |
+LL | fn assert_sized<T: ?Sized>() { }
+ | ^^^^^^^^
error[E0277]: the size for values of type `A` cannot be known at compilation time
--> $DIR/extern-types-unsized.rs:28:5
= help: within `Bar<A>`, the trait `std::marker::Sized` is not implemented for `A`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required because it appears within the type `Bar<A>`
+help: consider relaxing the implicit `Sized` restriction
+ |
+LL | fn assert_sized<T: ?Sized>() { }
+ | ^^^^^^^^
error[E0277]: the size for values of type `A` cannot be known at compilation time
--> $DIR/extern-types-unsized.rs:31:5
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required because it appears within the type `Bar<A>`
= note: required because it appears within the type `Bar<Bar<A>>`
+help: consider relaxing the implicit `Sized` restriction
+ |
+LL | fn assert_sized<T: ?Sized>() { }
+ | ^^^^^^^^
error: aborting due to 4 previous errors
--> $DIR/fat-ptr-cast.rs:14:5
|
LL | b as usize;
- | ^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0606]: casting `*const [i32]` as `usize` is invalid
--> $DIR/fat-ptr-cast.rs:15:5
struct ConstFn<const F: fn()>;
//~^ ERROR const generics are unstable
-//~^^ ERROR using function pointers as const generic parameters is unstable
+//~^^ ERROR using function pointers as const generic parameters is forbidden
struct ConstPtr<const P: *const u32>;
//~^ ERROR const generics are unstable
-//~^^ ERROR using raw pointers as const generic parameters is unstable
+//~^^ ERROR using raw pointers as const generic parameters is forbidden
fn main() {}
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
= help: add `#![feature(const_generics)]` to the crate attributes to enable
-error[E0658]: using function pointers as const generic parameters is unstable
+error: using function pointers as const generic parameters is forbidden
--> $DIR/feature-gate-const_generics-ptr.rs:1:25
|
LL | struct ConstFn<const F: fn()>;
| ^^^^
- |
- = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
- = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
-error[E0658]: using raw pointers as const generic parameters is unstable
+error: using raw pointers as const generic parameters is forbidden
--> $DIR/feature-gate-const_generics-ptr.rs:5:26
|
LL | struct ConstPtr<const P: *const u32>;
| ^^^^^^^^^^
- |
- = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
- = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
error: aborting due to 4 previous errors
trait PointerFamily<U> {
type Pointer<T>: Deref<Target = T>;
//~^ ERROR generic associated types are unstable
- //~| ERROR type-generic associated types are not yet implemented
type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
//~^ ERROR generic associated types are unstable
//~| ERROR where clauses on associated types are unstable
- //~| ERROR type-generic associated types are not yet implemented
}
struct Foo;
= help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
error[E0658]: generic associated types are unstable
- --> $DIR/feature-gate-generic_associated_types.rs:7:5
+ --> $DIR/feature-gate-generic_associated_types.rs:6:5
|
LL | type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
error[E0658]: where clauses on associated types are unstable
- --> $DIR/feature-gate-generic_associated_types.rs:7:5
+ --> $DIR/feature-gate-generic_associated_types.rs:6:5
|
LL | type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
error[E0658]: generic associated types are unstable
- --> $DIR/feature-gate-generic_associated_types.rs:16:5
+ --> $DIR/feature-gate-generic_associated_types.rs:14:5
|
LL | type Pointer<Usize> = Box<Usize>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
error[E0658]: generic associated types are unstable
- --> $DIR/feature-gate-generic_associated_types.rs:18:5
+ --> $DIR/feature-gate-generic_associated_types.rs:16:5
|
LL | type Pointer2<U32> = Box<U32>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
error[E0658]: where clauses on associated types are unstable
- --> $DIR/feature-gate-generic_associated_types.rs:23:5
+ --> $DIR/feature-gate-generic_associated_types.rs:21:5
|
LL | type Assoc where Self: Sized;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
error[E0658]: where clauses on associated types are unstable
- --> $DIR/feature-gate-generic_associated_types.rs:28:5
+ --> $DIR/feature-gate-generic_associated_types.rs:26:5
|
LL | type Assoc where Self: Sized = Foo;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
= help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
-error: type-generic associated types are not yet implemented
- --> $DIR/feature-gate-generic_associated_types.rs:4:5
- |
-LL | type Pointer<T>: Deref<Target = T>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
- --> $DIR/feature-gate-generic_associated_types.rs:7:5
- |
-LL | type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 9 previous errors
+error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0658`.
fn main() {
eq(foo::<u8>, bar::<u8>);
//~^ ERROR mismatched types
- //~| expected fn item `fn(_) -> _ {foo::<u8>}`
- //~| found fn item `fn(_) -> _ {bar::<u8>}`
- //~| expected fn item, found a different fn item
+ //~| expected fn item `fn(_) -> _ {foo::<u8>}`
+ //~| found fn item `fn(_) -> _ {bar::<u8>}`
+ //~| expected fn item, found a different fn item
+ //~| different `fn` items always have unique types, even if their signatures are the same
+ //~| change the expected type to be function pointer
+ //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
eq(foo::<u8>, foo::<i8>);
//~^ ERROR mismatched types
//~| expected `u8`, found `i8`
+ //~| different `fn` items always have unique types, even if their signatures are the same
+ //~| change the expected type to be function pointer
+ //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
eq(bar::<String>, bar::<Vec<u8>>);
//~^ ERROR mismatched types
- //~| expected fn item `fn(_) -> _ {bar::<std::string::String>}`
- //~| found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
- //~| expected struct `std::string::String`, found struct `std::vec::Vec`
+ //~| expected fn item `fn(_) -> _ {bar::<std::string::String>}`
+ //~| found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
+ //~| expected struct `std::string::String`, found struct `std::vec::Vec`
+ //~| different `fn` items always have unique types, even if their signatures are the same
+ //~| change the expected type to be function pointer
+ //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
// Make sure we distinguish between trait methods correctly.
eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
//~^ ERROR mismatched types
//~| expected `u8`, found `u16`
+ //~| different `fn` items always have unique types, even if their signatures are the same
+ //~| change the expected type to be function pointer
+ //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
+
+ eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
+ //~^ ERROR mismatched types
+ //~| expected fn item `fn(_) -> _ {foo::<u8>}`
+ //~| found fn pointer `fn(_) -> _`
+ //~| expected fn item, found fn pointer
+ //~| change the expected type to be function pointer
+ //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
+
+ eq(foo::<u8> as fn(isize) -> isize, bar::<u8>); // ok!
}
|
= note: expected fn item `fn(_) -> _ {foo::<u8>}`
found fn item `fn(_) -> _ {bar::<u8>}`
+ = note: different `fn` items always have unique types, even if their signatures are the same
+ = help: change the expected type to be function pointer `fn(isize) -> isize`
+ = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
error[E0308]: mismatched types
- --> $DIR/fn-item-type.rs:19:19
+ --> $DIR/fn-item-type.rs:22:19
|
LL | eq(foo::<u8>, foo::<i8>);
| ^^^^^^^^^ expected `u8`, found `i8`
|
= note: expected fn item `fn(_) -> _ {foo::<u8>}`
found fn item `fn(_) -> _ {foo::<i8>}`
+ = note: different `fn` items always have unique types, even if their signatures are the same
+ = help: change the expected type to be function pointer `fn(isize) -> isize`
+ = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
error[E0308]: mismatched types
- --> $DIR/fn-item-type.rs:23:23
+ --> $DIR/fn-item-type.rs:29:23
|
LL | eq(bar::<String>, bar::<Vec<u8>>);
| ^^^^^^^^^^^^^^ expected struct `std::string::String`, found struct `std::vec::Vec`
|
= note: expected fn item `fn(_) -> _ {bar::<std::string::String>}`
found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
+ = note: different `fn` items always have unique types, even if their signatures are the same
+ = help: change the expected type to be function pointer `fn(isize) -> isize`
+ = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `bar::<std::string::String> as fn(isize) -> isize`
error[E0308]: mismatched types
- --> $DIR/fn-item-type.rs:30:26
+ --> $DIR/fn-item-type.rs:39:26
|
LL | eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
| ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
|
= note: expected fn item `fn() {<u8 as Foo>::foo}`
found fn item `fn() {<u16 as Foo>::foo}`
+ = note: different `fn` items always have unique types, even if their signatures are the same
+ = help: change the expected type to be function pointer `fn()`
+ = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `<u8 as Foo>::foo as fn()`
-error: aborting due to 4 previous errors
+error[E0308]: mismatched types
+ --> $DIR/fn-item-type.rs:46:19
+ |
+LL | eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
+ |
+ = note: expected fn item `fn(_) -> _ {foo::<u8>}`
+ found fn pointer `fn(_) -> _`
+ = help: change the expected type to be function pointer `fn(isize) -> isize`
+ = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
+
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0308`.
-error[E0005]: refutable pattern in `for` loop binding: `&i32::MIN..=0i32` and `&2i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in `for` loop binding: `&i32::MIN..=0_i32` and `&2_i32..=i32::MAX` not covered
--> $DIR/for-loop-refutable-pattern-error-message.rs:2:9
|
LL | for &1 in [1].iter() {}
- | ^^ patterns `&i32::MIN..=0i32` and `&2i32..=i32::MAX` not covered
+ | ^^ patterns `&i32::MIN..=0_i32` and `&2_i32..=i32::MAX` not covered
|
= note: the matched value is of type `&i32`
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/resume-arg-late-bound.rs:15:5
+ |
+LL | test(gen);
+ | ^^^^^^^^^
+
+error: aborting due to previous error
+
*arg = true;
};
test(gen);
- //~^ ERROR type mismatch in function arguments
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
}
-error[E0631]: type mismatch in function arguments
- --> $DIR/resume-arg-late-bound.rs:15:10
+error[E0308]: mismatched types
+ --> $DIR/resume-arg-late-bound.rs:15:5
|
-LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {}
- | ------------------------------- required by this bound in `test`
-...
LL | test(gen);
- | ^^^
- | |
- | expected signature of `for<'a> fn(&'a mut bool) -> _`
- | found signature of `fn(&mut bool) -> _`
+ | ^^^^ one type is more general than the other
+ |
+ = note: expected type `for<'a> std::ops::Generator<&'a mut bool>`
+ found type `std::ops::Generator<&mut bool>`
+
+error[E0308]: mismatched types
+ --> $DIR/resume-arg-late-bound.rs:15:5
+ |
+LL | test(gen);
+ | ^^^^ one type is more general than the other
+ |
+ = note: expected type `for<'a> std::ops::Generator<&'a mut bool>`
+ found type `std::ops::Generator<&mut bool>`
-error: aborting due to previous error
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0631`.
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+#![feature(associated_type_defaults)]
+
+// A Collection trait and collection families. Based on
+// http://smallcultfollowing.com/babysteps/blog/2016/11/03/
+// associated-type-constructors-part-2-family-traits/
+
+// check that we don't normalize with trait defaults.
+
+trait Collection<T> {
+ type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter;
+ type Family: CollectionFamily;
+ // Test associated type defaults with parameters
+ type Sibling<U>: Collection<U> =
+ <<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
+
+ fn empty() -> Self;
+
+ fn add(&mut self, value: T);
+
+ fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>;
+}
+
+trait CollectionFamily {
+ type Member<T>: Collection<T, Family = Self>;
+}
+
+struct VecFamily;
+
+impl CollectionFamily for VecFamily {
+ type Member<T> = Vec<T>;
+}
+
+impl<T> Collection<T> for Vec<T> {
+ type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>;
+ type Family = VecFamily;
+
+ fn empty() -> Self {
+ Vec::new()
+ }
+
+ fn add(&mut self, value: T) {
+ self.push(value)
+ }
+
+ fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> {
+ self.iter()
+ }
+}
+
+fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
+where
+ C: Collection<i32>,
+{
+ let mut res = <C::Family as CollectionFamily>::Member::<f32>::empty();
+ for &v in ints.iterate() {
+ res.add(v as f32);
+ }
+ res
+ //~^ ERROR mismatched types
+}
+
+fn use_floatify() {
+ let a = vec![1i32, 2, 3];
+ let c = floatify_sibling(&a);
+ assert_eq!(Some(&1.0), c.iterate().next());
+}
+
+fn main() {
+ use_floatify();
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/collections-project-default.rs:60:5
+ |
+LL | fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
+ | ------------------------------------ expected `<C as Collection<i32>>::Sibling<f32>` because of return type
+...
+LL | res
+ | ^^^ expected Collection::Sibling, found CollectionFamily::Member
+ |
+ = note: expected associated type `<C as Collection<i32>>::Sibling<f32>`
+ found associated type `<<C as Collection<i32>>::Family as CollectionFamily>::Member<f32>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
// http://smallcultfollowing.com/babysteps/blog/2016/11/03/
// associated-type-constructors-part-2-family-traits/
+// run-pass
+
trait Collection<T> {
- type Iter<'iter>: Iterator<Item=&'iter T>;
+ type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter;
type Family: CollectionFamily;
// Test associated type defaults with parameters
type Sibling<U>: Collection<U> =
<<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
- //~^^ ERROR type-generic associated types are not yet implemented
fn empty() -> Self;
trait CollectionFamily {
type Member<T>: Collection<T, Family = Self>;
- //~^ ERROR type-generic associated types are not yet implemented
}
struct VecFamily;
}
impl<T> Collection<T> for Vec<T> {
- type Iter<'iter> = std::slice::Iter<'iter, T>;
+ type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>;
type Family = VecFamily;
fn empty() -> Self {
where
C: Collection<i32>,
{
- let mut res = C::Family::Member::<f32>::empty();
- for &v in ints.iterate() {
- res.add(v as f32);
- }
- res
-}
-
-fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
-where
- C: Collection<i32>,
-{
- let mut res = C::Family::Member::<f32>::empty();
+ let mut res = <C::Family as CollectionFamily>::Member::<f32>::empty();
for &v in ints.iterate() {
res.add(v as f32);
}
}
fn use_floatify() {
- let a = vec![1i32, 2, 3];
- let b = floatify(a);
- println!("{}", b.iterate().next());
- let c = floatify_sibling(a);
- println!("{}", c.iterate().next());
+ let a = vec![1, 2, 3];
+ let b = floatify(&a);
+ assert_eq!(Some(&1.0), b.iterate().next());
}
-fn main() {}
+fn main() {
+ use_floatify();
+}
+++ /dev/null
-error: type-generic associated types are not yet implemented
- --> $DIR/collections.rs:13:5
- |
-LL | / type Sibling<U>: Collection<U> =
-LL | | <<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
- | |_________________________________________________________________________^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
- --> $DIR/collections.rs:25:5
- |
-LL | type Member<T>: Collection<T, Family = Self>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 2 previous errors
-
#![allow(incomplete_features)]
#![feature(generic_associated_types)]
-// FIXME(#30472) normalize enough to handle this.
+// check-pass
use std::ops::Deref;
}
impl<T> Baz for T where T: Foo {
-//~^ ERROR type mismatch resolving
type Quux<'a> where T: 'a = T;
type Baa<'a> where T: 'a = &'a <T as Foo>::Bar<'a, 'static>;
+++ /dev/null
-error[E0271]: type mismatch resolving `for<'a> <<T as Baz>::Baa<'a> as std::ops::Deref>::Target == <<T as Baz>::Quux<'a> as Foo>::Bar<'a, 'static>`
- --> $DIR/construct_with_other_type.rs:19:9
- |
-LL | impl<T> Baz for T where T: Foo {
- | - ^^^ expected type parameter `T`, found associated type
- | |
- | this type parameter
- |
- = note: expected associated type `<T as Foo>::Bar<'_, 'static>`
- found associated type `<<T as Baz>::Quux<'_> as Foo>::Bar<'_, 'static>`
-help: consider further restricting this bound
- |
-LL | impl<T> Baz for T where T: Foo + Baz<Quux = T> {
- | ^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0271`.
trait MyTrait {
type Item<T>;
//~^ ERROR generic associated types are unstable [E0658]
- //~| ERROR type-generic associated types are not yet implemented
}
impl MyTrait for Foo {
= help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
error[E0658]: generic associated types are unstable
- --> $DIR/gat-dont-ice-on-absent-feature-2.rs:13:5
+ --> $DIR/gat-dont-ice-on-absent-feature-2.rs:12:5
|
LL | type Item<T> = T;
| ^^^^^^^^^^^^^^^^^
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
= help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
-error: type-generic associated types are not yet implemented
- --> $DIR/gat-dont-ice-on-absent-feature-2.rs:7:5
- |
-LL | type Item<T>;
- | ^^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.
trait Foo {
type Assoc where Self: Sized;
type Assoc2<T> where T: Display;
- //~^ ERROR type-generic associated types are not yet implemented
type Assoc3<T>;
- //~^ ERROR type-generic associated types are not yet implemented
- type WithDefault<'a, T: Debug + 'a> = dyn Iterator<Item=T>;
- //~^ ERROR type-generic associated types are not yet implemented
+ type WithDefault<'a, T: Debug + 'a>: ?Sized = dyn Iterator<Item=T>;
type NoGenerics;
}
type Assoc = usize;
type Assoc2<T> = Vec<T>;
type Assoc3<T> where T: Iterator = Vec<T>;
+ //~^ impl has stricter requirements than trait
type WithDefault<'a, T: Debug + 'a> = &'a dyn Iterator<Item=T>;
type NoGenerics = ::std::cell::Cell<i32>;
}
-error: type-generic associated types are not yet implemented
- --> $DIR/generic-associated-types-where.rs:11:5
- |
-LL | type Assoc2<T> where T: Display;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
- --> $DIR/generic-associated-types-where.rs:13:5
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/generic-associated-types-where.rs:22:5
|
LL | type Assoc3<T>;
- | ^^^^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
- --> $DIR/generic-associated-types-where.rs:15:5
- |
-LL | type WithDefault<'a, T: Debug + 'a> = dyn Iterator<Item=T>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+ | --------------- definition of `Assoc3` from trait
+...
+LL | type Assoc3<T> where T: Iterator = Vec<T>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator`
-error: aborting due to 3 previous errors
+error: aborting due to previous error
+For more information about this error, try `rustc --explain E0276`.
trait Foo {
type Assoc3<T>;
- //~^ type-generic associated types are not yet implemented
}
struct Bar;
impl Foo for Bar {
type Assoc3<T> where T: Iterator = Vec<T>;
+ //~^ ERROR impl has stricter requirements than trait
}
fn main() {}
-error: type-generic associated types are not yet implemented
- --> $DIR/issue-47206-where-clause.rs:7:5
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/issue-47206-where-clause.rs:13:5
|
LL | type Assoc3<T>;
- | ^^^^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+ | --------------- definition of `Assoc3` from trait
+...
+LL | type Assoc3<T> where T: Iterator = Vec<T>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator`
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0276`.
#![allow(incomplete_features)]
#![feature(generic_associated_types)]
-// FIXME(generic-associated-types) Investigate why this doesn't compile.
+// check-pass
trait Iterator {
type Item<'a>: 'a;
- //~^ ERROR the requirement `for<'a> <Self as Iterator>::Item<'a>: 'a` is not satisfied
+}
+
+impl Iterator for () {
+ type Item<'a> = &'a ();
}
fn main() {}
+++ /dev/null
-error[E0280]: the requirement `for<'a> <Self as Iterator>::Item<'a>: 'a` is not satisfied
- --> $DIR/issue-62326-parameter-out-of-range.rs:7:20
- |
-LL | trait Iterator {
- | -------- required by a bound in this
-LL | type Item<'a>: 'a;
- | ^^ required by this bound in `Iterator`
-
-error: aborting due to previous error
-
trait Trait2 {
type Type1<B>: Trait1<A=B>;
//~^ ERROR: generic associated types are unstable
- //~| ERROR: type-generic associated types are not yet implemented
}
fn main() {}
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
= help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
-error: type-generic associated types are not yet implemented
- --> $DIR/issue-67424.rs:8:5
- |
-LL | type Type1<B>: Trait1<A=B>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Regression test for #68641
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait UnsafeCopy {
+ type Item<'a>: Copy;
+
+ fn copy<'a>(item: &Self::Item<'a>) -> Self::Item<'a> {
+ *item
+ }
+}
+
+impl<T> UnsafeCopy for T {
+ type Item<'a> = T;
+ //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied
+}
+
+fn main() {
+ let mut s = String::from("Hello world!");
+
+ let copy = String::copy(&s);
+
+ // Do we indeed point to the samme memory?
+ assert!(s.as_ptr() == copy.as_ptr());
+
+ // Any use of `copy` is certeinly UB after this
+ drop(s);
+
+ // UB UB UB UB UB!!
+ println!("{}", copy);
+}
--- /dev/null
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-68641-check-gat-bounds.rs:3:12
+ |
+LL | #![feature(generic_associated_types)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+ --> $DIR/issue-68641-check-gat-bounds.rs:15:5
+ |
+LL | type Item<'a>: Copy;
+ | -------------------- required by `UnsafeCopy::Item`
+...
+LL | type Item<'a> = T;
+ | ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+ |
+help: consider restricting type parameter `T`
+ |
+LL | impl<T: std::marker::Copy> UnsafeCopy for T {
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// Regression test for #68642
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait Fun {
+ type F<'a>: Fn() -> u32;
+
+ fn callme<'a>(f: Self::F<'a>) -> u32 {
+ f()
+ }
+}
+
+impl<T> Fun for T {
+ type F<'a> = Self;
+ //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T`
+}
+
+fn main() {
+ <fn() -> usize>::callme(|| 1);
+}
--- /dev/null
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-68642-broken-llvm-ir.rs:3:12
+ |
+LL | #![feature(generic_associated_types)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: expected a `std::ops::Fn<()>` closure, found `T`
+ --> $DIR/issue-68642-broken-llvm-ir.rs:15:5
+ |
+LL | type F<'a>: Fn() -> u32;
+ | ------------------------ required by `Fun::F`
+...
+LL | type F<'a> = Self;
+ | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+ |
+ = help: the trait `std::ops::Fn<()>` is not implemented for `T`
+ = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+help: consider restricting type parameter `T`
+ |
+LL | impl<T: std::ops::Fn<()>> Fun for T {
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// Regression test for #68643
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait Fun {
+ type F<'a>: Fn() -> u32;
+
+ fn callme<'a>(f: Self::F<'a>) -> u32 {
+ f()
+ }
+}
+
+impl<T> Fun for T {
+ type F<'a> = Self;
+ //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T`
+}
+
+pub fn main() {
+ <fn()>::callme(|| {});
+}
--- /dev/null
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-68643-broken-mir.rs:3:12
+ |
+LL | #![feature(generic_associated_types)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: expected a `std::ops::Fn<()>` closure, found `T`
+ --> $DIR/issue-68643-broken-mir.rs:15:5
+ |
+LL | type F<'a>: Fn() -> u32;
+ | ------------------------ required by `Fun::F`
+...
+LL | type F<'a> = Self;
+ | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+ |
+ = help: the trait `std::ops::Fn<()>` is not implemented for `T`
+ = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+help: consider restricting type parameter `T`
+ |
+LL | impl<T: std::ops::Fn<()>> Fun for T {
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// Regression test for #68644
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait Fun {
+ type F<'a>: Fn() -> u32;
+
+ fn callme<'a>(f: Self::F<'a>) -> u32 {
+ f()
+ }
+}
+
+impl<T> Fun for T {
+ type F<'a> = Self;
+ //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T`
+}
+
+fn main() {
+ <u8>::callme(0);
+}
--- /dev/null
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-68644-codegen-selection.rs:3:12
+ |
+LL | #![feature(generic_associated_types)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: expected a `std::ops::Fn<()>` closure, found `T`
+ --> $DIR/issue-68644-codegen-selection.rs:15:5
+ |
+LL | type F<'a>: Fn() -> u32;
+ | ------------------------ required by `Fun::F`
+...
+LL | type F<'a> = Self;
+ | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+ |
+ = help: the trait `std::ops::Fn<()>` is not implemented for `T`
+ = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+help: consider restricting type parameter `T`
+ |
+LL | impl<T: std::ops::Fn<()>> Fun for T {
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// Regression test for #68645
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait Fun {
+ type F<'a>: Fn() -> u32;
+
+ fn callme<'a>(f: Self::F<'a>) -> u32 {
+ f()
+ }
+}
+
+impl<T> Fun for T {
+ type F<'a> = Self;
+ //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T`
+}
+
+fn main() {
+ <&dyn Iterator<Item = u8>>::callme(&std::iter::once(1));
+}
--- /dev/null
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-68645-codegen-fulfillment.rs:3:12
+ |
+LL | #![feature(generic_associated_types)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: expected a `std::ops::Fn<()>` closure, found `T`
+ --> $DIR/issue-68645-codegen-fulfillment.rs:15:5
+ |
+LL | type F<'a>: Fn() -> u32;
+ | ------------------------ required by `Fun::F`
+...
+LL | type F<'a> = Self;
+ | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+ |
+ = help: the trait `std::ops::Fn<()>` is not implemented for `T`
+ = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+help: consider restricting type parameter `T`
+ |
+LL | impl<T: std::ops::Fn<()>> Fun for T {
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// Regression test for #68656
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait UnsafeCopy<T: Copy> {
+ type Item<'a>: std::ops::Deref<Target = T>;
+
+ fn bug<'a>(item: &Self::Item<'a>) -> () {
+ let x: T = **item;
+ &x as *const _;
+ }
+}
+
+impl<T: Copy + std::ops::Deref> UnsafeCopy<T> for T {
+ type Item<'a> = T;
+ //~^ ERROR type mismatch resolving `<T as std::ops::Deref>::Target == T`
+}
+
+fn main() {
+ <&'static str>::bug(&"");
+}
--- /dev/null
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-68656-unsized-values.rs:3:12
+ |
+LL | #![feature(generic_associated_types)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0271]: type mismatch resolving `<T as std::ops::Deref>::Target == T`
+ --> $DIR/issue-68656-unsized-values.rs:16:5
+ |
+LL | type Item<'a>: std::ops::Deref<Target = T>;
+ | ------------------------------------------- required by `UnsafeCopy::Item`
+...
+LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<T> for T {
+ | - this type parameter
+LL | type Item<'a> = T;
+ | ^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found associated type
+ |
+ = note: expected type parameter `T`
+ found associated type `<T as std::ops::Deref>::Target`
+help: consider further restricting this bound
+ |
+LL | impl<T: Copy + std::ops::Deref + std::ops::Deref<Target = T>> UnsafeCopy<T> for T {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0271`.
#![allow(incomplete_features)]
#![feature(generic_associated_types)]
-// FIXME(#30472) normalize enough to handle this.
+// run-pass
trait Iterable {
type Item<'a> where Self: 'a;
// Impl for struct type
impl<T> Iterable for Vec<T> {
type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
- //~^ ERROR type mismatch resolving
type Iter<'a> where T: 'a = std::slice::Iter<'a, T>;
fn iter<'a>(&'a self) -> Self::Iter<'a> {
- //~^ ERROR type mismatch resolving
- self.iter()
+ self[..].iter()
}
}
// Impl for a primitive type
impl<T> Iterable for [T] {
type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
- //~^ ERROR type mismatch resolving
type Iter<'a> where T: 'a = std::slice::Iter<'a, T>;
fn iter<'a>(&'a self) -> Self::Iter<'a> {
- //~^ ERROR type mismatch resolving
self.iter()
}
}
-fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> {
+fn make_iter<'a, I: Iterable + ?Sized>(it: &'a I) -> I::Iter<'a> {
it.iter()
}
-fn get_first<'a, I: Iterable>(it: &'a I) -> Option<I::Item<'a>> {
+fn get_first<'a, I: Iterable + ?Sized>(it: &'a I) -> Option<I::Item<'a>> {
it.iter().next()
}
fn main() {
let v = vec![1, 2, 3];
- assert_eq!(v, make_iter(&v).copied().collect());
- assert_eq!(v, make_iter(&*v).copied().collect());
- assert_eq!(1, get_first(&v));
- assert_eq!(1, get_first(&*v));
+ assert_eq!(v, make_iter(&v).copied().collect::<Vec<_>>());
+ assert_eq!(v, make_iter(&*v).copied().collect::<Vec<_>>());
+ assert_eq!(Some(&1), get_first(&v));
+ assert_eq!(Some(&1), get_first(&*v));
}
+++ /dev/null
-error[E0271]: type mismatch resolving `for<'a> <<std::vec::Vec<T> as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <std::vec::Vec<T> as Iterable>::Item<'a>`
- --> $DIR/iterable.rs:15:33
- |
-LL | type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found associated type
- |
- = note: expected reference `&T`
- found associated type `<std::vec::Vec<T> as Iterable>::Item<'_>`
- = help: consider constraining the associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` to `&_`
- = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
-error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>`
- --> $DIR/iterable.rs:27:33
- |
-LL | type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found associated type
- |
- = note: expected reference `&T`
- found associated type `<[T] as Iterable>::Item<'_>`
- = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_`
- = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
-error[E0271]: type mismatch resolving `for<'a> <<std::vec::Vec<T> as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <std::vec::Vec<T> as Iterable>::Item<'a>`
- --> $DIR/iterable.rs:19:30
- |
-LL | trait Iterable {
- | -------- required by a bound in this
-LL | type Item<'a> where Self: 'a;
-LL | type Iter<'a>: Iterator<Item = Self::Item<'a>> where Self: 'a;
- | --------------------- required by this bound in `Iterable`
-...
-LL | fn iter<'a>(&'a self) -> Self::Iter<'a> {
- | ^^^^^^^^^^^^^^ expected associated type, found reference
- |
- = note: expected associated type `<std::vec::Vec<T> as Iterable>::Item<'_>`
- found reference `&T`
- = help: consider constraining the associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` to `&_` or calling a method that returns `<std::vec::Vec<T> as Iterable>::Item<'_>`
- = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
-error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>`
- --> $DIR/iterable.rs:31:30
- |
-LL | trait Iterable {
- | -------- required by a bound in this
-LL | type Item<'a> where Self: 'a;
-LL | type Iter<'a>: Iterator<Item = Self::Item<'a>> where Self: 'a;
- | --------------------- required by this bound in `Iterable`
-...
-LL | fn iter<'a>(&'a self) -> Self::Iter<'a> {
- | ^^^^^^^^^^^^^^ expected associated type, found reference
- |
- = note: expected associated type `<[T] as Iterable>::Item<'_>`
- found reference `&T`
- = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` or calling a method that returns `<[T] as Iterable>::Item<'_>`
- = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0271`.
struct E<B>(B);
-impl<B: Add> Add for E<B> where B: Add<Output = B>, B: std::ops::Add<Output = B> {
- //~^ ERROR equality constraints are not yet supported in `where` clauses
+impl<B: Add> Add for E<B> where B: Add<Output = B> {
type Output = Self;
fn add(self, rhs: Self) -> Self {
- Self(self.0 + rhs.0) //~ ERROR mismatched types
+ Self(self.0 + rhs.0)
}
}
struct E<B>(B);
-impl<B: Add> Add for E<B> where <B as Add>::Output = B {
- //~^ ERROR equality constraints are not yet supported in `where` clauses
+impl<B: Add> Add for E<B> where B: Add<Output = B> {
type Output = Self;
fn add(self, rhs: Self) -> Self {
- Self(self.0 + rhs.0) //~ ERROR mismatched types
+ Self(self.0 + rhs.0)
}
}
-error: equality constraints are not yet supported in `where` clauses
- --> $DIR/missing-bounds.rs:37:33
- |
-LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
- | ^^^^^^^^^^^^^^^^^^^^^^ not supported
- |
- = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-help: if `Output` is an associated type you're trying to set, use the associated type binding syntax
- |
-LL | impl<B: Add> Add for E<B> where B: Add<Output = B> {
- | ^^^^^^^^^^^^^^^^^^
-
error[E0308]: mismatched types
--> $DIR/missing-bounds.rs:11:11
|
LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0308]: mismatched types
- --> $DIR/missing-bounds.rs:42:14
- |
-LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
- | - this type parameter
-...
-LL | Self(self.0 + rhs.0)
- | ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type
- |
- = note: expected type parameter `B`
- found associated type `<B as std::ops::Add>::Output`
-help: consider further restricting type parameter `B`
- |
-LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B, B: std::ops::Add<Output = B> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.
type B<'a, 'b>;
type C;
type D<T>;
- //~^ ERROR type-generic associated types are not yet implemented
type E<'a, T>;
- //~^ ERROR type-generic associated types are not yet implemented
// Test parameters in default values
type FOk<T> = Self::E<'static, T>;
- //~^ ERROR type-generic associated types are not yet implemented
type FErr1 = Self::E<'static, 'static>;
//~^ ERROR wrong number of lifetime arguments: expected 1, found 2
//~| ERROR wrong number of type arguments: expected 1, found 0
type FErr2<T> = Self::E<'static, T, u32>;
- //~^ ERROR type-generic associated types are not yet implemented
- //~| ERROR wrong number of type arguments: expected 1, found 2
+ //~^ ERROR wrong number of type arguments: expected 1, found 2
}
fn main() {}
-error: type-generic associated types are not yet implemented
- --> $DIR/parameter_number_and_kind.rs:9:5
- |
-LL | type D<T>;
- | ^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
- --> $DIR/parameter_number_and_kind.rs:11:5
- |
-LL | type E<'a, T>;
- | ^^^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
- --> $DIR/parameter_number_and_kind.rs:14:5
- |
-LL | type FOk<T> = Self::E<'static, T>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
- --> $DIR/parameter_number_and_kind.rs:19:5
- |
-LL | type FErr2<T> = Self::E<'static, T, u32>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
error[E0107]: wrong number of lifetime arguments: expected 1, found 2
- --> $DIR/parameter_number_and_kind.rs:16:35
+ --> $DIR/parameter_number_and_kind.rs:13:35
|
LL | type FErr1 = Self::E<'static, 'static>;
| ^^^^^^^ unexpected lifetime argument
error[E0107]: wrong number of type arguments: expected 1, found 0
- --> $DIR/parameter_number_and_kind.rs:16:18
+ --> $DIR/parameter_number_and_kind.rs:13:18
|
LL | type FErr1 = Self::E<'static, 'static>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 type argument
error[E0107]: wrong number of type arguments: expected 1, found 2
- --> $DIR/parameter_number_and_kind.rs:19:41
+ --> $DIR/parameter_number_and_kind.rs:16:41
|
LL | type FErr2<T> = Self::E<'static, T, u32>;
| ^^^ unexpected type argument
-error: aborting due to 7 previous errors
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0107`.
#![allow(incomplete_features)]
#![feature(generic_associated_types)]
-// FIXME(#44265): allow type-generic associated types.
+// check-pass
use std::rc::Rc;
use std::sync::Arc;
trait PointerFamily {
type Pointer<T>: Deref<Target = T>;
- //~^ ERROR type-generic associated types are not yet implemented
fn new<T>(value: T) -> Self::Pointer<T>;
}
+++ /dev/null
-error: type-generic associated types are not yet implemented
- --> $DIR/pointer_family.rs:11:5
- |
-LL | type Pointer<T>: Deref<Target = T>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to previous error
-
trait ShadowT<T> {
type Bar<T>;
//~^ ERROR the name `T` is already used
- //~| ERROR type-generic associated types are not yet implemented
}
trait NoShadowT<T> {
type Bar<U>; // OK
- //~^ ERROR type-generic associated types are not yet implemented
}
impl<T> NoShadowT<T> for Option<T> {
| ^ already used
error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters
- --> $DIR/shadowing.rs:30:14
+ --> $DIR/shadowing.rs:28:14
|
LL | impl<T> NoShadowT<T> for Option<T> {
| - first use of `T`
LL | type Bar<'a> = i32;
| ^^ lifetime 'a already in scope
-error: type-generic associated types are not yet implemented
- --> $DIR/shadowing.rs:19:5
- |
-LL | type Bar<T>;
- | ^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
- --> $DIR/shadowing.rs:25:5
- |
-LL | type Bar<U>; // OK
- | ^^^^^^^^^^^^
- |
- = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
Some errors have detailed explanations: E0403, E0496.
For more information about an error, try `rustc --explain E0403`.
--- /dev/null
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+
+trait ATy {
+ type Item<'a>: 'a;
+}
+
+impl<'b> ATy for &'b () {
+ type Item<'a> = &'b ();
+ //~^ ERROR does not fulfill the required lifetime
+}
+
+trait StaticTy {
+ type Item<'a>: 'static;
+}
+
+impl StaticTy for () {
+ type Item<'a> = &'a ();
+ //~^ ERROR does not fulfill the required lifetime
+}
+
+fn main() {}
--- /dev/null
+error[E0477]: the type `&'b ()` does not fulfill the required lifetime
+ --> $DIR/unsatisfied-outlives-bound.rs:9:5
+ |
+LL | type Item<'a> = &'b ();
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: type must outlive the lifetime `'a` as defined on the associated item at 9:15
+ --> $DIR/unsatisfied-outlives-bound.rs:9:15
+ |
+LL | type Item<'a> = &'b ();
+ | ^^
+
+error[E0477]: the type `&'a ()` does not fulfill the required lifetime
+ --> $DIR/unsatisfied-outlives-bound.rs:18:5
+ |
+LL | type Item<'a> = &'a ();
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: type must satisfy the static lifetime
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0477`.
foo::<C>(); //~ ERROR: cannot find type `C` in this scope
foo::<D>(); //~ ERROR: cannot find type `D` in this scope
}
+
+mod other {
+ pub fn import() {}
+}
|
LL | import();
| ^^^^^^ not found in this scope
+ |
+help: consider importing this function
+ |
+LL | use other::import;
+ |
error[E0412]: cannot find type `A` in this scope
--> $DIR/glob-resolve1.rs:28:11
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
-error[E0004]: non-exhaustive patterns: `254u8..=u8::MAX` not covered
+error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12
|
LL | m!(0, ..ALMOST_MAX);
- | ^ pattern `254u8..=u8::MAX` not covered
+ | ^ pattern `254_u8..=u8::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
-error[E0004]: non-exhaustive patterns: `0u8` not covered
+error[E0004]: non-exhaustive patterns: `0_u8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12
|
LL | m!(0, ALMOST_MIN..);
- | ^ pattern `0u8` not covered
+ | ^ pattern `0_u8` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
-error[E0004]: non-exhaustive patterns: `43u8` not covered
+error[E0004]: non-exhaustive patterns: `43_u8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:45:12
|
LL | m!(0, ..=VAL | VAL_2..);
- | ^ pattern `43u8` not covered
+ | ^ pattern `43_u8` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
-error[E0004]: non-exhaustive patterns: `43u8` not covered
+error[E0004]: non-exhaustive patterns: `43_u8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:46:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
- | ^ pattern `43u8` not covered
+ | ^ pattern `43_u8` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
-error[E0004]: non-exhaustive patterns: `65534u16..=u16::MAX` not covered
+error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12
|
LL | m!(0, ..ALMOST_MAX);
- | ^ pattern `65534u16..=u16::MAX` not covered
+ | ^ pattern `65534_u16..=u16::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
-error[E0004]: non-exhaustive patterns: `0u16` not covered
+error[E0004]: non-exhaustive patterns: `0_u16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12
|
LL | m!(0, ALMOST_MIN..);
- | ^ pattern `0u16` not covered
+ | ^ pattern `0_u16` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
-error[E0004]: non-exhaustive patterns: `43u16` not covered
+error[E0004]: non-exhaustive patterns: `43_u16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:58:12
|
LL | m!(0, ..=VAL | VAL_2..);
- | ^ pattern `43u16` not covered
+ | ^ pattern `43_u16` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
-error[E0004]: non-exhaustive patterns: `43u16` not covered
+error[E0004]: non-exhaustive patterns: `43_u16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:59:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
- | ^ pattern `43u16` not covered
+ | ^ pattern `43_u16` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
-error[E0004]: non-exhaustive patterns: `4294967294u32..=u32::MAX` not covered
+error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12
|
LL | m!(0, ..ALMOST_MAX);
- | ^ pattern `4294967294u32..=u32::MAX` not covered
+ | ^ pattern `4294967294_u32..=u32::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
-error[E0004]: non-exhaustive patterns: `0u32` not covered
+error[E0004]: non-exhaustive patterns: `0_u32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12
|
LL | m!(0, ALMOST_MIN..);
- | ^ pattern `0u32` not covered
+ | ^ pattern `0_u32` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
-error[E0004]: non-exhaustive patterns: `43u32` not covered
+error[E0004]: non-exhaustive patterns: `43_u32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:71:12
|
LL | m!(0, ..=VAL | VAL_2..);
- | ^ pattern `43u32` not covered
+ | ^ pattern `43_u32` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
-error[E0004]: non-exhaustive patterns: `43u32` not covered
+error[E0004]: non-exhaustive patterns: `43_u32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:72:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
- | ^ pattern `43u32` not covered
+ | ^ pattern `43_u32` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
-error[E0004]: non-exhaustive patterns: `18446744073709551614u64..=u64::MAX` not covered
+error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12
|
LL | m!(0, ..ALMOST_MAX);
- | ^ pattern `18446744073709551614u64..=u64::MAX` not covered
+ | ^ pattern `18446744073709551614_u64..=u64::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
-error[E0004]: non-exhaustive patterns: `0u64` not covered
+error[E0004]: non-exhaustive patterns: `0_u64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12
|
LL | m!(0, ALMOST_MIN..);
- | ^ pattern `0u64` not covered
+ | ^ pattern `0_u64` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
-error[E0004]: non-exhaustive patterns: `43u64` not covered
+error[E0004]: non-exhaustive patterns: `43_u64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:84:12
|
LL | m!(0, ..=VAL | VAL_2..);
- | ^ pattern `43u64` not covered
+ | ^ pattern `43_u64` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
-error[E0004]: non-exhaustive patterns: `43u64` not covered
+error[E0004]: non-exhaustive patterns: `43_u64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:85:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
- | ^ pattern `43u64` not covered
+ | ^ pattern `43_u64` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
-error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454u128..=u128::MAX` not covered
+error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12
|
LL | m!(0, ..ALMOST_MAX);
- | ^ pattern `340282366920938463463374607431768211454u128..=u128::MAX` not covered
+ | ^ pattern `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
-error[E0004]: non-exhaustive patterns: `0u128` not covered
+error[E0004]: non-exhaustive patterns: `0_u128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12
|
LL | m!(0, ALMOST_MIN..);
- | ^ pattern `0u128` not covered
+ | ^ pattern `0_u128` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
-error[E0004]: non-exhaustive patterns: `43u128` not covered
+error[E0004]: non-exhaustive patterns: `43_u128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:97:12
|
LL | m!(0, ..=VAL | VAL_2..);
- | ^ pattern `43u128` not covered
+ | ^ pattern `43_u128` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
-error[E0004]: non-exhaustive patterns: `43u128` not covered
+error[E0004]: non-exhaustive patterns: `43_u128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:98:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
- | ^ pattern `43u128` not covered
+ | ^ pattern `43_u128` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
-error[E0004]: non-exhaustive patterns: `126i8..=i8::MAX` not covered
+error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12
|
LL | m!(0, ..ALMOST_MAX);
- | ^ pattern `126i8..=i8::MAX` not covered
+ | ^ pattern `126_i8..=i8::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
-error[E0004]: non-exhaustive patterns: `43i8` not covered
+error[E0004]: non-exhaustive patterns: `43_i8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:113:12
|
LL | m!(0, ..=VAL | VAL_2..);
- | ^ pattern `43i8` not covered
+ | ^ pattern `43_i8` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
-error[E0004]: non-exhaustive patterns: `43i8` not covered
+error[E0004]: non-exhaustive patterns: `43_i8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:114:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
- | ^ pattern `43i8` not covered
+ | ^ pattern `43_i8` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
-error[E0004]: non-exhaustive patterns: `32766i16..=i16::MAX` not covered
+error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12
|
LL | m!(0, ..ALMOST_MAX);
- | ^ pattern `32766i16..=i16::MAX` not covered
+ | ^ pattern `32766_i16..=i16::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
-error[E0004]: non-exhaustive patterns: `43i16` not covered
+error[E0004]: non-exhaustive patterns: `43_i16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:126:12
|
LL | m!(0, ..=VAL | VAL_2..);
- | ^ pattern `43i16` not covered
+ | ^ pattern `43_i16` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
-error[E0004]: non-exhaustive patterns: `43i16` not covered
+error[E0004]: non-exhaustive patterns: `43_i16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:127:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
- | ^ pattern `43i16` not covered
+ | ^ pattern `43_i16` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
-error[E0004]: non-exhaustive patterns: `2147483646i32..=i32::MAX` not covered
+error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12
|
LL | m!(0, ..ALMOST_MAX);
- | ^ pattern `2147483646i32..=i32::MAX` not covered
+ | ^ pattern `2147483646_i32..=i32::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
-error[E0004]: non-exhaustive patterns: `43i32` not covered
+error[E0004]: non-exhaustive patterns: `43_i32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:139:12
|
LL | m!(0, ..=VAL | VAL_2..);
- | ^ pattern `43i32` not covered
+ | ^ pattern `43_i32` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
-error[E0004]: non-exhaustive patterns: `43i32` not covered
+error[E0004]: non-exhaustive patterns: `43_i32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:140:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
- | ^ pattern `43i32` not covered
+ | ^ pattern `43_i32` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
-error[E0004]: non-exhaustive patterns: `9223372036854775806i64..=i64::MAX` not covered
+error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12
|
LL | m!(0, ..ALMOST_MAX);
- | ^ pattern `9223372036854775806i64..=i64::MAX` not covered
+ | ^ pattern `9223372036854775806_i64..=i64::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
-error[E0004]: non-exhaustive patterns: `43i64` not covered
+error[E0004]: non-exhaustive patterns: `43_i64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:152:12
|
LL | m!(0, ..=VAL | VAL_2..);
- | ^ pattern `43i64` not covered
+ | ^ pattern `43_i64` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
-error[E0004]: non-exhaustive patterns: `43i64` not covered
+error[E0004]: non-exhaustive patterns: `43_i64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:153:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
- | ^ pattern `43i64` not covered
+ | ^ pattern `43_i64` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
-error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726i128..=i128::MAX` not covered
+error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12
|
LL | m!(0, ..ALMOST_MAX);
- | ^ pattern `170141183460469231731687303715884105726i128..=i128::MAX` not covered
+ | ^ pattern `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
-error[E0004]: non-exhaustive patterns: `43i128` not covered
+error[E0004]: non-exhaustive patterns: `43_i128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:165:12
|
LL | m!(0, ..=VAL | VAL_2..);
- | ^ pattern `43i128` not covered
+ | ^ pattern `43_i128` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
-error[E0004]: non-exhaustive patterns: `43i128` not covered
+error[E0004]: non-exhaustive patterns: `43_i128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:166:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
- | ^ pattern `43i128` not covered
+ | ^ pattern `43_i128` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/hr-subtype.rs:45:13
+ |
+LL | gimme::<$t1>(None::<$t2>);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
+LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) }
+ | |_____________________________________________- in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
error[E0308]: mismatched types
- --> $DIR/hr-subtype.rs:39:26
+ --> $DIR/hr-subtype.rs:45:26
|
LL | gimme::<$t1>(None::<$t2>);
- | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+ | ^^^^^^^^^^^ one type is more general than the other
...
LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
-LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) }
- | |_________________________________________________________________________________________- in this macro invocation
+LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) }
+ | |_____________________________________________- in this macro invocation
|
= note: expected enum `std::option::Option<for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32>`
found enum `std::option::Option<for<'a> fn(&'a u32, &'a u32) -> &'a u32>`
-error[E0308]: mismatched types
- --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+ --> $DIR/hr-subtype.rs:102:1
|
-LL | gimme::<$t1>(None::<$t2>);
- | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
-...
-LL | / check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32),
-LL | | for<'a> fn(&'a u32, &'a u32)) }
- | |__________________________________________________________________- in this macro invocation
- |
- = note: expected enum `std::option::Option<for<'a, 'b> fn(&'a u32, &'b u32)>`
- found enum `std::option::Option<for<'a> fn(&'a u32, &'a u32)>`
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+... |
+LL | |
+LL | | }
+ | |_^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0308`.
error: fatal error triggered by #[rustc_error]
- --> $DIR/hr-subtype.rs:100:1
+ --> $DIR/hr-subtype.rs:102:1
|
LL | / fn main() {
LL | |
LL | |
LL | |
-LL | |
+... |
LL | |
LL | | }
| |_^
error: fatal error triggered by #[rustc_error]
- --> $DIR/hr-subtype.rs:100:1
+ --> $DIR/hr-subtype.rs:102:1
|
LL | / fn main() {
LL | |
LL | |
LL | |
-LL | |
+... |
LL | |
LL | | }
| |_^
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/hr-subtype.rs:45:13
+ |
+LL | gimme::<$t1>(None::<$t2>);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
+LL | | fn(&'x u32)) }
+ | |______________- in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
error[E0308]: mismatched types
- --> $DIR/hr-subtype.rs:39:26
+ --> $DIR/hr-subtype.rs:45:26
|
LL | gimme::<$t1>(None::<$t2>);
- | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+ | ^^^^^^^^^^^ one type is more general than the other
...
LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
-LL | | fn(&'x u32)) }
- | |___________________________________________- in this macro invocation
+LL | | fn(&'x u32)) }
+ | |______________- in this macro invocation
|
= note: expected enum `std::option::Option<for<'a> fn(&'a u32)>`
found enum `std::option::Option<fn(&'x u32)>`
-error[E0308]: mismatched types
- --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+ --> $DIR/hr-subtype.rs:102:1
|
-LL | gimme::<$t1>(None::<$t2>);
- | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
-...
-LL | / check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>),
-LL | | for<'a> fn(Co<'a>, Co<'a>)) }
- | |______________________________________________________________________- in this macro invocation
- |
- = note: expected enum `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>)>`
- found enum `std::option::Option<for<'a> fn(Co<'a>, Co<'a>)>`
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+... |
+LL | |
+LL | | }
+ | |_^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0308`.
-error[E0308]: mismatched types
- --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+ --> $DIR/hr-subtype.rs:102:1
|
-LL | gimme::<$t1>(None::<$t2>);
- | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
-...
-LL | / check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>,
-LL | | for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>) }
- | |______________________________________________________________________________________- in this macro invocation
- |
- = note: expected enum `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>) -> Contra<'a>>`
- found enum `std::option::Option<for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>>`
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+... |
+LL | |
+LL | | }
+ | |_^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0308`.
error: fatal error triggered by #[rustc_error]
- --> $DIR/hr-subtype.rs:100:1
+ --> $DIR/hr-subtype.rs:102:1
|
LL | / fn main() {
LL | |
LL | |
LL | |
-LL | |
+... |
LL | |
LL | | }
| |_^
-error[E0308]: mismatched types
- --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+ --> $DIR/hr-subtype.rs:102:1
|
-LL | gimme::<$t1>(None::<$t2>);
- | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
-...
-LL | / check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>,
-LL | | for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
- | |______________________________________________________________________________________________- in this macro invocation
- |
- = note: expected enum `std::option::Option<for<'a, 'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>>`
- found enum `std::option::Option<for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>>`
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+... |
+LL | |
+LL | | }
+ | |_^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/hr-subtype.rs:45:13
+ |
+LL | gimme::<$t1>(None::<$t2>);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
+LL | | for<'a> fn(Inv<'a>, Inv<'a>)) }
+ | |__________________________________- in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: higher-ranked subtype error
+ --> $DIR/hr-subtype.rs:45:13
+ |
+LL | gimme::<$t1>(None::<$t2>);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
+LL | | for<'a> fn(Inv<'a>, Inv<'a>)) }
+ | |__________________________________- in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
error[E0308]: mismatched types
- --> $DIR/hr-subtype.rs:39:26
+ --> $DIR/hr-subtype.rs:45:26
|
LL | gimme::<$t1>(None::<$t2>);
- | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+ | ^^^^^^^^^^^ one type is more general than the other
...
LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
-LL | | for<'a> fn(Inv<'a>, Inv<'a>)) }
- | |__________________________________________________________________________- in this macro invocation
+LL | | for<'a> fn(Inv<'a>, Inv<'a>)) }
+ | |__________________________________- in this macro invocation
|
= note: expected enum `std::option::Option<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>`
found enum `std::option::Option<for<'a> fn(Inv<'a>, Inv<'a>)>`
error: fatal error triggered by #[rustc_error]
- --> $DIR/hr-subtype.rs:100:1
+ --> $DIR/hr-subtype.rs:102:1
|
LL | / fn main() {
LL | |
LL | |
LL | |
-LL | |
+... |
LL | |
LL | | }
| |_^
error: lifetime may not live long enough
- --> $DIR/hr-subtype.rs:33:13
+ --> $DIR/hr-subtype.rs:39:13
|
-LL | fn subtype<'x,'y:'x,'z:'y>() {
- | -- -- lifetime `'y` defined here
+LL | fn subtype<'x, 'y: 'x, 'z: 'y>() {
+ | -- -- lifetime `'y` defined here
| |
| lifetime `'x` defined here
LL | gimme::<$t2>(None::<$t1>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
...
LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | | fn(Inv<'y>)) }
- | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+ | |______________- in this macro invocation
|
= help: consider adding the following bound: `'x: 'y`
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: lifetime may not live long enough
- --> $DIR/hr-subtype.rs:39:13
+ --> $DIR/hr-subtype.rs:45:13
|
-LL | fn supertype<'x,'y:'x,'z:'y>() {
- | -- -- lifetime `'y` defined here
+LL | fn supertype<'x, 'y: 'x, 'z: 'y>() {
+ | -- -- lifetime `'y` defined here
| |
| lifetime `'x` defined here
LL | gimme::<$t1>(None::<$t2>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
...
LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | | fn(Inv<'y>)) }
- | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+ | |______________- in this macro invocation
|
= help: consider adding the following bound: `'x: 'y`
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0308]: mismatched types
- --> $DIR/hr-subtype.rs:33:26
+ --> $DIR/hr-subtype.rs:39:26
|
LL | gimme::<$t2>(None::<$t1>);
| ^^^^^^^^^^^ lifetime mismatch
...
LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | | fn(Inv<'y>)) }
- | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+ | |______________- in this macro invocation
|
= note: expected enum `std::option::Option<fn(Inv<'y>)>`
found enum `std::option::Option<fn(Inv<'x>)>`
-note: the lifetime `'x` as defined on the function body at 32:20...
- --> $DIR/hr-subtype.rs:32:20
+note: the lifetime `'x` as defined on the function body at 38:20...
+ --> $DIR/hr-subtype.rs:38:20
|
-LL | fn subtype<'x,'y:'x,'z:'y>() {
+LL | fn subtype<'x, 'y: 'x, 'z: 'y>() {
| ^^
...
LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | | fn(Inv<'y>)) }
- | |__________________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 32:23
- --> $DIR/hr-subtype.rs:32:23
+LL | | fn(Inv<'y>)) }
+ | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:24
+ --> $DIR/hr-subtype.rs:38:24
|
-LL | fn subtype<'x,'y:'x,'z:'y>() {
- | ^^
+LL | fn subtype<'x, 'y: 'x, 'z: 'y>() {
+ | ^^
...
LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | | fn(Inv<'y>)) }
- | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+ | |______________- in this macro invocation
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0308]: mismatched types
- --> $DIR/hr-subtype.rs:39:26
+ --> $DIR/hr-subtype.rs:45:26
|
LL | gimme::<$t1>(None::<$t2>);
| ^^^^^^^^^^^ lifetime mismatch
...
LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | | fn(Inv<'y>)) }
- | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+ | |______________- in this macro invocation
|
= note: expected enum `std::option::Option<fn(Inv<'x>)>`
found enum `std::option::Option<fn(Inv<'y>)>`
-note: the lifetime `'x` as defined on the function body at 38:22...
- --> $DIR/hr-subtype.rs:38:22
+note: the lifetime `'x` as defined on the function body at 44:22...
+ --> $DIR/hr-subtype.rs:44:22
|
-LL | fn supertype<'x,'y:'x,'z:'y>() {
+LL | fn supertype<'x, 'y: 'x, 'z: 'y>() {
| ^^
...
LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | | fn(Inv<'y>)) }
- | |__________________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:25
- --> $DIR/hr-subtype.rs:38:25
+LL | | fn(Inv<'y>)) }
+ | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 44:26
+ --> $DIR/hr-subtype.rs:44:26
|
-LL | fn supertype<'x,'y:'x,'z:'y>() {
- | ^^
+LL | fn supertype<'x, 'y: 'x, 'z: 'y>() {
+ | ^^
...
LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | | fn(Inv<'y>)) }
- | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+ | |______________- in this macro invocation
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
error: fatal error triggered by #[rustc_error]
- --> $DIR/hr-subtype.rs:100:1
+ --> $DIR/hr-subtype.rs:102:1
|
LL | / fn main() {
LL | |
LL | |
LL | |
-LL | |
+... |
LL | |
LL | | }
| |_^
error: lifetime may not live long enough
- --> $DIR/hr-subtype.rs:39:13
+ --> $DIR/hr-subtype.rs:45:13
|
-LL | fn supertype<'x,'y:'x,'z:'y>() {
- | -- -- lifetime `'y` defined here
+LL | fn supertype<'x, 'y: 'x, 'z: 'y>() {
+ | -- -- lifetime `'y` defined here
| |
| lifetime `'x` defined here
LL | gimme::<$t1>(None::<$t2>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
...
LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | | fn(&'y u32)) }
- | |__________________________________________- in this macro invocation
+LL | | fn(&'y u32)) }
+ | |______________- in this macro invocation
|
= help: consider adding the following bound: `'x: 'y`
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0308]: mismatched types
- --> $DIR/hr-subtype.rs:39:26
+ --> $DIR/hr-subtype.rs:45:26
|
LL | gimme::<$t1>(None::<$t2>);
| ^^^^^^^^^^^ lifetime mismatch
...
LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | | fn(&'y u32)) }
- | |__________________________________________- in this macro invocation
+LL | | fn(&'y u32)) }
+ | |______________- in this macro invocation
|
= note: expected enum `std::option::Option<fn(&'x u32)>`
found enum `std::option::Option<fn(&'y u32)>`
-note: the lifetime `'x` as defined on the function body at 38:22...
- --> $DIR/hr-subtype.rs:38:22
+note: the lifetime `'x` as defined on the function body at 44:22...
+ --> $DIR/hr-subtype.rs:44:22
|
-LL | fn supertype<'x,'y:'x,'z:'y>() {
+LL | fn supertype<'x, 'y: 'x, 'z: 'y>() {
| ^^
...
LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | | fn(&'y u32)) }
- | |__________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:25
- --> $DIR/hr-subtype.rs:38:25
+LL | | fn(&'y u32)) }
+ | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 44:26
+ --> $DIR/hr-subtype.rs:44:26
|
-LL | fn supertype<'x,'y:'x,'z:'y>() {
- | ^^
+LL | fn supertype<'x, 'y: 'x, 'z: 'y>() {
+ | ^^
...
LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | | fn(&'y u32)) }
- | |__________________________________________- in this macro invocation
+LL | | fn(&'y u32)) }
+ | |______________- in this macro invocation
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
// revisions: bound_inv_a_b_vs_bound_inv_a
// revisions: bound_a_b_ret_a_vs_bound_a_ret_a
-fn gimme<T>(_: Option<T>) { }
+fn gimme<T>(_: Option<T>) {}
-struct Inv<'a> { x: *mut &'a u32 }
+struct Inv<'a> {
+ x: *mut &'a u32,
+}
-struct Co<'a> { x: fn(&'a u32) }
+struct Co<'a> {
+ x: fn(&'a u32),
+}
-struct Contra<'a> { x: &'a u32 }
+struct Contra<'a> {
+ x: &'a u32,
+}
macro_rules! check {
($rev:ident: ($t1:ty, $t2:ty)) => {
#[cfg($rev)]
- fn subtype<'x,'y:'x,'z:'y>() {
+ fn subtype<'x, 'y: 'x, 'z: 'y>() {
gimme::<$t2>(None::<$t1>);
//[free_inv_x_vs_free_inv_y]~^ ERROR
}
#[cfg($rev)]
- fn supertype<'x,'y:'x,'z:'y>() {
+ fn supertype<'x, 'y: 'x, 'z: 'y>() {
gimme::<$t1>(None::<$t2>);
//[bound_a_vs_free_x]~^ ERROR
//[free_x_vs_free_y]~^^ ERROR
//[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR
//[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^ ERROR
//[free_inv_x_vs_free_inv_y]~^^^^^ ERROR
- //[bound_a_b_vs_bound_a]~^^^^^^ ERROR mismatched types
- //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR
- //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^ ERROR
- //[bound_co_a_b_vs_bound_co_a]~^^^^^^^^^ ERROR
}
- }
+ };
}
// If both have bound regions, they are equivalent, regardless of
// variant.
check! { bound_a_vs_bound_a: (for<'a> fn(&'a u32),
- for<'a> fn(&'a u32)) }
+for<'a> fn(&'a u32)) }
check! { bound_a_vs_bound_b: (for<'a> fn(&'a u32),
- for<'b> fn(&'b u32)) }
+for<'b> fn(&'b u32)) }
check! { bound_inv_a_vs_bound_inv_b: (for<'a> fn(Inv<'a>),
- for<'b> fn(Inv<'b>)) }
+for<'b> fn(Inv<'b>)) }
check! { bound_co_a_vs_bound_co_b: (for<'a> fn(Co<'a>),
- for<'b> fn(Co<'b>)) }
+for<'b> fn(Co<'b>)) }
// Bound is a subtype of free.
check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
- fn(&'x u32)) }
+fn(&'x u32)) }
// Two free regions are relatable if subtyping holds.
check! { free_x_vs_free_x: (fn(&'x u32),
- fn(&'x u32)) }
+fn(&'x u32)) }
check! { free_x_vs_free_y: (fn(&'x u32),
- fn(&'y u32)) }
+fn(&'y u32)) }
check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
- fn(Inv<'y>)) }
+fn(Inv<'y>)) }
// Somewhat surprisingly, a fn taking two distinct bound lifetimes and
// a fn taking one bound lifetime can be interchangeable, but only if
// intersection;
// - if we are contravariant, then 'a can be inferred to 'static.
check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32),
- for<'a> fn(&'a u32, &'a u32)) }
+for<'a> fn(&'a u32, &'a u32)) }
check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>),
- for<'a> fn(Co<'a>, Co<'a>)) }
+for<'a> fn(Co<'a>, Co<'a>)) }
check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>,
- for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
+for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>,
- for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>) }
+for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>) }
// If we make those lifetimes invariant, then the two types are not interchangeable.
check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
- for<'a> fn(Inv<'a>, Inv<'a>)) }
+for<'a> fn(Inv<'a>, Inv<'a>)) }
check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
- for<'a> fn(&'a u32, &'a u32) -> &'a u32) }
+for<'a> fn(&'a u32, &'a u32) -> &'a u32) }
#[rustc_error]
fn main() {
-//[bound_a_vs_bound_a]~^ ERROR fatal error triggered by #[rustc_error]
-//[bound_a_vs_bound_b]~^^ ERROR fatal error triggered by #[rustc_error]
-//[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error]
-//[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error]
-//[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error]
+ //[bound_a_vs_bound_a]~^ ERROR fatal error triggered by #[rustc_error]
+ //[bound_a_vs_bound_b]~^^ ERROR fatal error triggered by #[rustc_error]
+ //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error]
+ //[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error]
+ //[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error]
+ //[bound_co_a_b_vs_bound_co_a]~^^^^^^ ERROR
+ //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR
+ //[bound_a_b_vs_bound_a]~^^^^^^^^ ERROR
+ //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR
}
--- /dev/null
+// check-pass
+
+fn make<T>() -> T {
+ panic!()
+}
+
+fn take<T>(x: T) {}
+
+fn main() {
+ let x: for<'a> fn(&'a u32) -> _ = make();
+ let y: &'static u32 = x(&22);
+ take::<for<'b> fn(&'b u32) -> &'b u32>(x);
+}
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/hrtb-conflate-regions.rs:27:10
+ |
+LL | fn b() { want_foo2::<SomeStruct>(); }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+ --> $DIR/hrtb-conflate-regions.rs:27:10
+ |
+LL | fn b() { want_foo2::<SomeStruct>(); }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
-error[E0277]: the trait bound `for<'a, 'b> SomeStruct: Foo<(&'a isize, &'b isize)>` is not satisfied
- --> $DIR/hrtb-conflate-regions.rs:27:22
+error: implementation of `Foo` is not general enough
+ --> $DIR/hrtb-conflate-regions.rs:27:10
|
-LL | fn want_foo2<T>()
- | --------- required by a bound in this
-LL | where T : for<'a,'b> Foo<(&'a isize, &'b isize)>
- | -------------------------------------- required by this bound in `want_foo2`
+LL | / trait Foo<X> {
+LL | | fn foo(&self, x: X) { }
+LL | | }
+ | |_- trait `Foo` defined here
...
-LL | fn b() { want_foo2::<SomeStruct>(); }
- | ^^^^^^^^^^ the trait `for<'a, 'b> Foo<(&'a isize, &'b isize)>` is not implemented for `SomeStruct`
+LL | fn b() { want_foo2::<SomeStruct>(); }
+ | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
- = help: the following implementations were found:
- <SomeStruct as Foo<(&'a isize, &'a isize)>>
+ = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+ = note: ...but `SomeStruct` actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/hrtb-exists-forall-fn.rs:17:12
+ |
+LL | let _: for<'b> fn(&'b u32) = foo();
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--> $DIR/hrtb-exists-forall-fn.rs:17:34
|
LL | let _: for<'b> fn(&'b u32) = foo();
- | ------------------- ^^^^^ expected concrete lifetime, found bound lifetime parameter 'b
- | |
- | expected due to this
+ | ^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'b> fn(&'b u32)`
found fn pointer `fn(&u32)`
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
+ |
+LL | foo::<()>();
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
// NB. *However*, the reinstated leak-check gives an error here.
foo::<()>();
- //~^ ERROR not satisfied
+ //~^ ERROR implementation of `Trait` is not general enough
}
-error[E0277]: the trait bound `(): Trait<for<'b> fn(&'b u32)>` is not satisfied
- --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:11
+error: implementation of `Trait` is not general enough
+ --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
|
-LL | fn foo<T>()
- | --- required by a bound in this
-LL | where
-LL | T: Trait<for<'b> fn(&'b u32)>,
- | -------------------------- required by this bound in `foo`
+LL | trait Trait<T> {}
+ | ----------------- trait `Trait` defined here
...
LL | foo::<()>();
- | ^^ the trait `Trait<for<'b> fn(&'b u32)>` is not implemented for `()`
+ | ^^^^^^^^^ implementation of `Trait` is not general enough
|
- = help: the following implementations were found:
- <() as Trait<fn(&'a u32)>>
+ = note: `()` must implement `Trait<for<'b> fn(&'b u32)>`
+ = note: ...but `()` actually implements `Trait<fn(&'0 u32)>`, for some specific lifetime `'0`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0277`.
//
// In particular, we test this pattern in trait solving, where it is not connected
// to any part of the source code.
+//
+// check-pass
trait Trait<T> {}
// - `?b: ?a` -- solveable if `?b` is inferred to `'static`
// - So the subtyping check succeeds, somewhat surprisingly.
// This is because we can use `'static`.
- //
- // NB. *However*, the reinstated leak-check gives an error here.
foo::<()>();
- //~^ ERROR not satisfied
}
+++ /dev/null
-error[E0277]: the trait bound `(): Trait<for<'b> fn(fn(&'b u32))>` is not satisfied
- --> $DIR/hrtb-exists-forall-trait-covariant.rs:36:11
- |
-LL | fn foo<T>()
- | --- required by a bound in this
-LL | where
-LL | T: Trait<for<'b> fn(fn(&'b u32))>,
- | ------------------------------ required by this bound in `foo`
-...
-LL | foo::<()>();
- | ^^ the trait `Trait<for<'b> fn(fn(&'b u32))>` is not implemented for `()`
- |
- = help: the following implementations were found:
- <() as Trait<fn(fn(&'a u32))>>
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
+ |
+LL | foo::<()>();
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
// yielding `fn(&!b u32)`, in a fresh universe U1
// - So we get `?a = !b` but the universe U0 assigned to `?a` cannot name `!b`.
- foo::<()>(); //~ ERROR not satisfied
+ foo::<()>(); //~ ERROR implementation of `Trait` is not general enough
}
-error[E0277]: the trait bound `(): Trait<for<'b> fn(std::cell::Cell<&'b u32>)>` is not satisfied
- --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:11
+error: implementation of `Trait` is not general enough
+ --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
|
-LL | fn foo<T>()
- | --- required by a bound in this
-LL | where
-LL | T: Trait<for<'b> fn(Cell<&'b u32>)>,
- | -------------------------------- required by this bound in `foo`
+LL | trait Trait<T> {}
+ | ----------------- trait `Trait` defined here
...
LL | foo::<()>();
- | ^^ the trait `Trait<for<'b> fn(std::cell::Cell<&'b u32>)>` is not implemented for `()`
+ | ^^^^^^^^^ implementation of `Trait` is not general enough
|
- = help: the following implementations were found:
- <() as Trait<fn(std::cell::Cell<&'a u32>)>>
+ = note: `()` must implement `Trait<for<'b> fn(std::cell::Cell<&'b u32>)>`
+ = note: ...but `()` actually implements `Trait<fn(std::cell::Cell<&'0 u32>)>`, for some specific lifetime `'0`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/hrtb-just-for-static.rs:24:5
+ |
+LL | want_hrtb::<StaticInt>()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+ --> $DIR/hrtb-just-for-static.rs:30:5
+ |
+LL | fn give_some<'a>() {
+ | -- lifetime `'a` defined here
+LL | want_hrtb::<&'a u32>()
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+
+error: higher-ranked subtype error
+ --> $DIR/hrtb-just-for-static.rs:30:5
+ |
+LL | want_hrtb::<&'a u32>()
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
-error[E0277]: the trait bound `for<'a> StaticInt: Foo<&'a isize>` is not satisfied
- --> $DIR/hrtb-just-for-static.rs:24:17
+error: implementation of `Foo` is not general enough
+ --> $DIR/hrtb-just-for-static.rs:24:5
|
-LL | fn want_hrtb<T>()
- | --------- required by a bound in this
-LL | where T : for<'a> Foo<&'a isize>
- | ---------------------- required by this bound in `want_hrtb`
+LL | / trait Foo<X> {
+LL | | fn foo(&self, x: X) { }
+LL | | }
+ | |_- trait `Foo` defined here
...
-LL | want_hrtb::<StaticInt>()
- | ^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `StaticInt`
+LL | want_hrtb::<StaticInt>()
+ | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
- = help: the following implementations were found:
- <StaticInt as Foo<&'static isize>>
+ = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`...
+ = note: ...but `StaticInt` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1`
-error[E0277]: the trait bound `for<'a> &'a u32: Foo<&'a isize>` is not satisfied
- --> $DIR/hrtb-just-for-static.rs:30:17
+error: implementation of `Foo` is not general enough
+ --> $DIR/hrtb-just-for-static.rs:30:5
|
-LL | fn want_hrtb<T>()
- | --------- required by a bound in this
-LL | where T : for<'a> Foo<&'a isize>
- | ---------------------- required by this bound in `want_hrtb`
+LL | / trait Foo<X> {
+LL | | fn foo(&self, x: X) { }
+LL | | }
+ | |_- trait `Foo` defined here
...
-LL | want_hrtb::<&'a u32>()
- | ^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `&'a u32`
+LL | want_hrtb::<&'a u32>()
+ | ^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
- = help: the following implementations were found:
- <&'a u32 as Foo<&'a isize>>
+ = note: `Foo<&'0 isize>` would have to be implemented for the type `&'a u32`, for any lifetime `'0`...
+ = note: ...but `Foo<&'1 isize>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0277`.
-error: implementation of `Stream` is not general enough
- --> $DIR/issue-30786.rs:108:22
+error[E0599]: no method named `filterx` found for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` in the current scope
+ --> $DIR/issue-30786.rs:128:22
|
-LL | / pub trait Stream {
-LL | | type Item;
-LL | | fn next(self) -> Option<Self::Item>;
-LL | | }
- | |_- trait `Stream` defined here
+LL | pub struct Map<S, F> {
+ | --------------------
+ | |
+ | method `filterx` not found for this
+ | doesn't satisfy `_: StreamExt`
...
-LL | let map = source.map(|x: &_| x);
- | ^^^ implementation of `Stream` is not general enough
+LL | let filter = map.filterx(|x: &_| true);
+ | ^^^^^^^ method not found in `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`
|
- = note: `Stream` would have to be implemented for the type `&'0 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for any lifetime `'0`...
- = note: ...but `Stream` is actually implemented for the type `&'1 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for some specific lifetime `'1`
+ = note: the method `filterx` exists but the following trait bounds were not satisfied:
+ `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+ which is required by `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+ `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+ which is required by `&Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+ `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+ which is required by `&mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
-error: aborting due to previous error
+error[E0599]: no method named `countx` found for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` in the current scope
+ --> $DIR/issue-30786.rs:141:24
+ |
+LL | pub struct Filter<S, F> {
+ | -----------------------
+ | |
+ | method `countx` not found for this
+ | doesn't satisfy `_: StreamExt`
+...
+LL | let count = filter.countx();
+ | ^^^^^^ method not found in `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`
+ |
+ = note: the method `countx` exists but the following trait bounds were not satisfied:
+ `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+ which is required by `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+ `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+ which is required by `&Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+ `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+ which is required by `&mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0599`.
-error: higher-ranked subtype error
- --> $DIR/issue-30786.rs:108:15
- |
-LL | let map = source.map(|x: &_| x);
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
- --> $DIR/issue-30786.rs:114:18
- |
-LL | let filter = map.filter(|x: &_| true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
- --> $DIR/issue-30786.rs:114:18
- |
-LL | let filter = map.filter(|x: &_| true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
- --> $DIR/issue-30786.rs:114:18
- |
-LL | let filter = map.filter(|x: &_| true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
- --> $DIR/issue-30786.rs:114:18
- |
-LL | let filter = map.filter(|x: &_| true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
- --> $DIR/issue-30786.rs:119:17
- |
-LL | let count = filter.count(); // Assert that we still have a valid stream.
- | ^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
- --> $DIR/issue-30786.rs:119:17
- |
-LL | let count = filter.count(); // Assert that we still have a valid stream.
- | ^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
- --> $DIR/issue-30786.rs:119:17
- |
-LL | let count = filter.count(); // Assert that we still have a valid stream.
- | ^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
- --> $DIR/issue-30786.rs:119:17
- |
-LL | let count = filter.count(); // Assert that we still have a valid stream.
- | ^^^^^^^^^^^^^^
-
-error: aborting due to 9 previous errors
-
+error[E0599]: no method named `filterx` found for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` in the current scope
+ --> $DIR/issue-30786.rs:128:22
+ |
+LL | pub struct Map<S, F> {
+ | --------------------
+ | |
+ | method `filterx` not found for this
+ | doesn't satisfy `_: StreamExt`
+...
+LL | let filter = map.filterx(|x: &_| true);
+ | ^^^^^^^ method not found in `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`
+ |
+ = note: the method `filterx` exists but the following trait bounds were not satisfied:
+ `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+ which is required by `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+ `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+ which is required by `&Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+ `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+ which is required by `&mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+
+error[E0599]: no method named `countx` found for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` in the current scope
+ --> $DIR/issue-30786.rs:141:24
+ |
+LL | pub struct Filter<S, F> {
+ | -----------------------
+ | |
+ | method `countx` not found for this
+ | doesn't satisfy `_: StreamExt`
+...
+LL | let count = filter.countx();
+ | ^^^^^^ method not found in `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`
+ |
+ = note: the method `countx` exists but the following trait bounds were not satisfied:
+ `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+ which is required by `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+ `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+ which is required by `&Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+ `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+ which is required by `&mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
//[nll]compile-flags: -Z borrowck=mir
-pub trait Stream { //[migrate]~ NOTE trait `Stream` defined here
+pub trait Stream {
type Item;
fn next(self) -> Option<Self::Item>;
}
}
impl<'a, A, F, T> Stream for &'a mut Map<A, F>
-where &'a mut A: Stream,
- F: FnMut(<&'a mut A as Stream>::Item) -> T,
+where
+ &'a mut A: Stream,
+ F: FnMut(<&'a mut A as Stream>::Item) -> T,
{
type Item = T;
fn next(self) -> Option<T> {
}
impl<'a, A, F, T> Stream for &'a mut Filter<A, F>
-where for<'b> &'b mut A: Stream<Item=T>, // <---- BAD
- F: FnMut(&T) -> bool,
+where
+ for<'b> &'b mut A: Stream<Item = T>, // <---- BAD
+ F: FnMut(&T) -> bool,
{
type Item = <&'a mut A as Stream>::Item;
fn next(self) -> Option<Self::Item> {
}
}
-pub trait StreamExt where for<'b> &'b mut Self: Stream {
- fn map<F>(self, func: F) -> Map<Self, F>
- where Self: Sized,
- for<'a> &'a mut Map<Self, F>: Stream,
+pub trait StreamExt
+where
+ for<'b> &'b mut Self: Stream,
+{
+ fn mapx<F>(self, func: F) -> Map<Self, F>
+ where
+ Self: Sized,
+ for<'a> &'a mut Map<Self, F>: Stream,
{
- Map {
- func: func,
- stream: self,
- }
+ Map { func: func, stream: self }
}
- fn filter<F>(self, func: F) -> Filter<Self, F>
- where Self: Sized,
- for<'a> &'a mut Filter<Self, F>: Stream,
+ fn filterx<F>(self, func: F) -> Filter<Self, F>
+ where
+ Self: Sized,
+ for<'a> &'a mut Filter<Self, F>: Stream,
{
- Filter {
- func: func,
- stream: self,
- }
+ Filter { func: func, stream: self }
}
- fn count(mut self) -> usize
- where Self: Sized,
+ fn countx(mut self) -> usize
+ where
+ Self: Sized,
{
let mut count = 0;
while let Some(_) = self.next() {
}
}
-impl<T> StreamExt for T where for<'a> &'a mut T: Stream { }
+impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
-fn main() {
+fn identity<T>(x: &T) -> &T {
+ x
+}
+
+fn variant1() {
let source = Repeat(10);
- let map = source.map(|x: &_| x);
- //[nll]~^ ERROR higher-ranked subtype error
- //[migrate]~^^ ERROR implementation of `Stream` is not general enough
- //[migrate]~| NOTE `Stream` would have to be implemented for the type `&'0 mut Map
- //[migrate]~| NOTE but `Stream` is actually implemented for the type `&'1
- //[migrate]~| NOTE implementation of `Stream` is not general enough
- let filter = map.filter(|x: &_| true);
- //[nll]~^ ERROR higher-ranked subtype error
- //[nll]~| ERROR higher-ranked subtype error
- //[nll]~| ERROR higher-ranked subtype error
- //[nll]~| ERROR higher-ranked subtype error
- let count = filter.count(); // Assert that we still have a valid stream.
- //[nll]~^ ERROR higher-ranked subtype error
- //[nll]~| ERROR higher-ranked subtype error
- //[nll]~| ERROR higher-ranked subtype error
- //[nll]~| ERROR higher-ranked subtype error
+
+ // Here, the call to `mapx` returns a type `T` to which `StreamExt`
+ // is not applicable, because `for<'b> &'b mut T: Stream`) doesn't hold.
+ //
+ // More concretely, the type `T` is `Map<Repeat, Closure>`, and
+ // the where clause doesn't hold because the signature of the
+ // closure gets inferred to a signature like `|&'_ Stream| -> &'_`
+ // for some specific `'_`, rather than a more generic
+ // signature.
+ //
+ // Why *exactly* we opt for this signature is a bit unclear to me,
+ // we deduce it somehow from a reuqirement that `Map: Stream` I
+ // guess.
+ let map = source.mapx(|x: &_| x);
+ let filter = map.filterx(|x: &_| true);
+ //[migrate]~^ ERROR no method named `filterx`
+ //[nll]~^^ ERROR no method named `filterx`
}
+
+fn variant2() {
+ let source = Repeat(10);
+
+ // Here, we use a function, which is not subject to the vagaries
+ // of closure signature inference. In this case, we get the error
+ // on `countx` as, I think, the test originally expected.
+ let map = source.mapx(identity);
+ let filter = map.filterx(|x: &_| true);
+ let count = filter.countx();
+ //[migrate]~^ ERROR no method named `countx`
+ //[nll]~^^ ERROR no method named `countx`
+}
+
+fn main() {}
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/issue-46989.rs:38:5
+ |
+LL | assert_foo::<fn(&i32)>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
//
// holds because 'a can be instantiated to 'empty.
-trait Foo {
+trait Foo {}
-}
-
-impl<A> Foo for fn(A) { }
+impl<A> Foo for fn(A) {}
fn assert_foo<T: Foo>() {}
fn main() {
assert_foo::<fn(&i32)>();
- //~^ ERROR the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied
+ //~^ ERROR implementation of `Foo` is not general enough
}
-error[E0277]: the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied
- --> $DIR/issue-46989.rs:40:18
+error: implementation of `Foo` is not general enough
+ --> $DIR/issue-46989.rs:38:5
|
-LL | fn assert_foo<T: Foo>() {}
- | --- required by this bound in `assert_foo`
+LL | trait Foo {}
+ | ------------ trait `Foo` defined here
...
LL | assert_foo::<fn(&i32)>();
- | ^^^^^^^^ the trait `Foo` is not implemented for `for<'r> fn(&'r i32)`
+ | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
- = help: the following implementations were found:
- <fn(A) as Foo>
+ = note: `Foo` would have to be implemented for the type `for<'r> fn(&'r i32)`
+ = note: ...but `Foo` is actually implemented for the type `fn(&'0 i32)`, for some specific lifetime `'0`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0277`.
| |_____- in this macro invocation
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider importing one of these items
+help: consider importing this function
|
LL | use bar::g;
|
-LL | use foo::test2::test::g;
- |
-LL | use foo::test::g;
- |
error[E0425]: cannot find function `f` in this scope
--> $DIR/globs.rs:61:12
Expansions:
0: parent: ExpnId(0), call_site_ctxt: #0, kind: Root
1: parent: ExpnId(0), call_site_ctxt: #0, kind: Macro(Bang, "foo")
-2: parent: ExpnId(0), call_site_ctxt: #1, kind: Desugaring(Operator)
-3: parent: ExpnId(0), call_site_ctxt: #1, kind: Desugaring(Operator)
SyntaxContexts:
#0: parent: #0, outer_mark: (ExpnId(0), Opaque)
#1: parent: #0, outer_mark: (ExpnId(1), SemiTransparent)
-#2: parent: #1, outer_mark: (ExpnId(2), Transparent)
-#3: parent: #1, outer_mark: (ExpnId(3), Transparent)
*/
--- /dev/null
+#![allow(incomplete_features)]
+#![feature(impl_trait_in_bindings)]
+
+fn foo() {
+ let _ : impl Copy;
+ //~^ ERROR cannot resolve opaque type
+}
+
+fn main() {}
--- /dev/null
+error[E0720]: cannot resolve opaque type
+ --> $DIR/binding-without-value.rs:5:13
+ |
+LL | let _ : impl Copy;
+ | - ^^^^^^^^^ cannot resolve opaque type
+ | |
+ | this binding might not have a concrete type
+ |
+help: set the binding to a value for a concrete type to be resolved
+ |
+LL | let _ : impl Copy = /* value */;
+ | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0720`.
// run-pass
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Foo: std::fmt::Debug + Eq {}
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/equality-rpass.rs:3:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Foo: Copy + ToString {}
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/equality.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0308]: mismatched types
--> $DIR/equality.rs:15:5
|
|
= help: the trait `std::ops::Add<impl Foo>` is not implemented for `u32`
-error: aborting due to 2 previous errors
+error: aborting due to 2 previous errors; 1 warning emitted
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Foo: Copy + ToString {}
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/equality2.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0308]: mismatched types
--> $DIR/equality2.rs:25:18
|
= note: expected opaque type `impl Foo` (`i32`)
found opaque type `impl Foo` (`u32`)
-error: aborting due to 4 previous errors
+error: aborting due to 4 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// check-pass
+
+#![feature(impl_trait_in_bindings)]
+#![allow(incomplete_features)]
+
+struct A<'a>(&'a ());
+
+trait Trait<T> {}
+
+impl<T> Trait<T> for () {}
+
+pub fn foo<'a>() {
+ let _x: impl Trait<A<'a>> = ();
+}
+
+fn main() {}
trait Quux {}
-fn foo() -> impl Quux { //~ opaque type expands to a recursive type
+fn foo() -> impl Quux { //~ ERROR cannot resolve opaque type
struct Foo<T>(T);
impl<T> Quux for Foo<T> {}
Foo(bar())
}
-fn bar() -> impl Quux { //~ opaque type expands to a recursive type
+fn bar() -> impl Quux { //~ ERROR cannot resolve opaque type
struct Bar<T>(T);
impl<T> Quux for Bar<T> {}
Bar(foo())
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/infinite-impl-trait-issue-38064.rs:8:13
|
LL | fn foo() -> impl Quux {
- | ^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `foo::Foo<bar::Bar<impl Quux>>`
+ | ^^^^^^^^^ recursive opaque type
+...
+LL | Foo(bar())
+ | ---------- returning here with type `foo::Foo<impl Quux>`
+...
+LL | fn bar() -> impl Quux {
+ | --------- returning this opaque type `foo::Foo<impl Quux>`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/infinite-impl-trait-issue-38064.rs:14:13
|
+LL | fn foo() -> impl Quux {
+ | --------- returning this opaque type `bar::Bar<impl Quux>`
+...
LL | fn bar() -> impl Quux {
- | ^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `bar::Bar<foo::Foo<impl Quux>>`
+ | ^^^^^^^^^ recursive opaque type
+...
+LL | Bar(foo())
+ | ---------- returning here with type `bar::Bar<impl Quux>`
error: aborting due to 2 previous errors
| ^^^^^^^^^^^^^^
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:12:69
+ --> $DIR/must_outlive_least_region_or_bound.rs:9:46
+ |
+LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
+ | - ^ returning this value requires that `'1` must outlive `'static`
+ | |
+ | let's call the lifetime of this reference `'1`
+ |
+ = help: consider replacing `'1` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/must_outlive_least_region_or_bound.rs:12:55
+ |
+LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
+ | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+ = help: consider replacing `'a` with `'static`
+
+error[E0621]: explicit lifetime required in the type of `x`
+ --> $DIR/must_outlive_least_region_or_bound.rs:15:41
+ |
+LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
+ | ---- ^ lifetime `'a` required
+ | |
+ | help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
+
+error: lifetime may not live long enough
+ --> $DIR/must_outlive_least_region_or_bound.rs:30:24
+ |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+ | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+ | |
+ | let's call the lifetime of this reference `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/must_outlive_least_region_or_bound.rs:37:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
= help: consider replacing `'a` with `'static`
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:17:61
+ --> $DIR/must_outlive_least_region_or_bound.rs:42:61
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
| -- -- lifetime `'b` defined here ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
= help: consider adding the following bound: `'b: 'a`
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:22:51
+ --> $DIR/must_outlive_least_region_or_bound.rs:47:51
|
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
| ^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `T: 'static`...
-error: aborting due to 5 previous errors
+error: aborting due to 9 previous errors
-For more information about this error, try `rustc --explain E0310`.
+Some errors have detailed explanations: E0310, E0621.
+For more information about an error, try `rustc --explain E0310`.
fn explicit<'a>(x: &'a i32) -> impl Copy { x }
//~^ ERROR cannot infer an appropriate lifetime
+fn elided2(x: &i32) -> impl Copy + 'static { x }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
+//~^ ERROR explicit lifetime required in the type of `x`
+
+fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+//~^ ERROR cannot infer an appropriate lifetime
+//~| ERROR cannot infer an appropriate lifetime
+
trait LifetimeTrait<'a> {}
impl<'a> LifetimeTrait<'a> for &'a i32 {}
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
--> $DIR/must_outlive_least_region_or_bound.rs:3:35
|
LL | fn elided(x: &i32) -> impl Copy { x }
- | ---- --------- ^ ...and is captured here
- | | |
- | | ...is required to be `'static` by this...
- | data with this lifetime...
+ | ---- ^ ...is captured here...
+ | |
+ | this data with an anonymous lifetime `'_`...
|
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1
+note: ...and is required to live as long as `'static` here
+ --> $DIR/must_outlive_least_region_or_bound.rs:3:23
+ |
+LL | fn elided(x: &i32) -> impl Copy { x }
+ | ^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
|
LL | fn elided(x: &i32) -> impl Copy + '_ { x }
| ^^^^
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
--> $DIR/must_outlive_least_region_or_bound.rs:6:44
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
- | ------- --------- ^ ...and is captured here
- | | |
- | | ...is required to be `'static` by this...
- | data with this lifetime...
+ | ------- ^ ...is captured here...
+ | |
+ | this data with lifetime `'a`...
|
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 6:13
+note: ...and is required to live as long as `'static` here
+ --> $DIR/must_outlive_least_region_or_bound.rs:6:32
+ |
+LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
+ | ^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'a` lifetime bound
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ^^^^
-error: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:12:69
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/must_outlive_least_region_or_bound.rs:9:46
+ |
+LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
+ | ---- ^ ...is captured here...
+ | |
+ | this data with an anonymous lifetime `'_`...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/must_outlive_least_region_or_bound.rs:9:24
+ |
+LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
+ | ^^^^^^^^^^^^^^^^^^^
+help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
+ |
+LL | fn elided2(x: &i32) -> impl Copy + '_ { x }
+ | ^^
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x }
+ | ^^^^^^^^^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/must_outlive_least_region_or_bound.rs:12:55
+ |
+LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
+ | ------- ^ ...is captured here...
+ | |
+ | this data with lifetime `'a`...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/must_outlive_least_region_or_bound.rs:12:33
+ |
+LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
+ | ^^^^^^^^^^^^^^^^^^^
+help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
+ |
+LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x }
+ | ^^
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn explicit2<'a>(x: &'static i32) -> impl Copy + 'static { x }
+ | ^^^^^^^^^^^^
+
+error[E0621]: explicit lifetime required in the type of `x`
+ --> $DIR/must_outlive_least_region_or_bound.rs:15:24
+ |
+LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
+ | ---- ^^^^^^^^^^^^^^ lifetime `'a` required
+ | |
+ | help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
+
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/must_outlive_least_region_or_bound.rs:30:65
+ |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+ | ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static`
+ |
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) }
+ | ^^^^
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
+ | ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/must_outlive_least_region_or_bound.rs:30:69
+ |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+ | ---- this data with an anonymous lifetime `'_`... ^ ...is captured here...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/must_outlive_least_region_or_bound.rs:30:41
+ |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+ | ^^^^^^^^^^
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) }
+ | ^^^^
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
+ | ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/must_outlive_least_region_or_bound.rs:37:69
+ |
+LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
+ | ------- this data with lifetime `'a`... ^ ...is captured here...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/must_outlive_least_region_or_bound.rs:37:34
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
- | ------- -------------------------------- ^ ...and is captured here
- | | |
- | | ...is required to be `'static` by this...
- | data with this lifetime...
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
|
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 12:15
+LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x }
+ | ^^
+help: alternatively, add an explicit `'static` bound to this reference
|
-LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static + 'a { x }
- | ^^^^
+LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x }
+ | ^^^^^^^^^^^^
error[E0623]: lifetime mismatch
- --> $DIR/must_outlive_least_region_or_bound.rs:17:61
+ --> $DIR/must_outlive_least_region_or_bound.rs:42:61
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
| ------- ^^^^^^^^^^^^^^^^
| this parameter and the return type are declared with different lifetimes...
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:22:51
+ --> $DIR/must_outlive_least_region_or_bound.rs:47:51
|
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
| -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
| |
| help: consider adding an explicit lifetime bound...: `T: 'static +`
-error: aborting due to 5 previous errors
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+ |
+LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+ | ---- ^ ...is captured here, requiring it to live as long as `'static`
+ | |
+ | this data with an anonymous lifetime `'_`...
+ |
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn elided3(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) }
+ | ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/must_outlive_least_region_or_bound.rs:21:59
+ |
+LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
+ | ------- ^ ...is captured here, requiring it to live as long as `'static`
+ | |
+ | this data with lifetime `'a`...
+ |
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound
+ |
+LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) }
+ | ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/must_outlive_least_region_or_bound.rs:24:60
+ |
+LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
+ | ---- ^ ...is captured here, requiring it to live as long as `'static`
+ | |
+ | this data with an anonymous lifetime `'_`...
+ |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
+ |
+LL | fn elided4(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) }
+ | ^^
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn elided4(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) }
+ | ^^^^^^^^^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/must_outlive_least_region_or_bound.rs:27:69
+ |
+LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
+ | ------- this data with lifetime `'a`... ^ ...is captured here, requiring it to live as long as `'static`
+ |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
+ |
+LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) }
+ | ^^
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn explicit4<'a>(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) }
+ | ^^^^^^^^^^^^
+
+error: aborting due to 14 previous errors
-Some errors have detailed explanations: E0310, E0623.
+Some errors have detailed explanations: E0310, E0621, E0623, E0759.
For more information about an error, try `rustc --explain E0310`.
error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&char>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:32:43
|
-LL | fn method(&self) {}
- | ------
- | |
- | the method is available for `std::boxed::Box<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
- | the method is available for `std::pin::Pin<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
- | the method is available for `std::sync::Arc<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
- | the method is available for `std::rc::Rc<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
-...
LL | std::rc::Rc::new(&mut Box::new(&'a')).method();
| ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&char>>`
|
|
LL | std::rc::Rc::new(&mut Box::new(&1i32)).method();
| ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&i32>>`
- |
- ::: $DIR/auxiliary/no_method_suggested_traits.rs:8:12
- |
-LL | fn method(&self) {}
- | ------
- | |
- | the method is available for `std::boxed::Box<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here
- | the method is available for `std::pin::Pin<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here
- | the method is available for `std::sync::Arc<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here
- | the method is available for `std::rc::Rc<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-direct.rs:5:14
|
LL | fn test() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: type resolves to itself
+ | ^^^^^^^^^^ recursive opaque type
+LL |
+LL | test()
+ | ------ returning here with type `impl Sized`
error: aborting due to previous error
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:7:22
|
LL | fn option(i: i32) -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `std::option::Option<(impl Sized, i32)>`
+ | ^^^^^^^^^^ recursive opaque type
+LL |
+LL | if i < 0 { None } else { Some((option(i - 1), i)) }
+ | ---- ------------------------ returning here with type `std::option::Option<(impl Sized, i32)>`
+ | |
+ | returning here with type `std::option::Option<(impl Sized, i32)>`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:12:15
|
LL | fn tuple() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `(impl Sized,)`
+ | ^^^^^^^^^^ recursive opaque type
+LL |
+LL | (tuple(),)
+ | ---------- returning here with type `(impl Sized,)`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:17:15
|
LL | fn array() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `[impl Sized; 1]`
+ | ^^^^^^^^^^ recursive opaque type
+LL |
+LL | [array()]
+ | --------- returning here with type `[impl Sized; 1]`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:22:13
|
LL | fn ptr() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `*const impl Sized`
+ | ^^^^^^^^^^ recursive opaque type
+LL |
+LL | &ptr() as *const _
+ | ------------------ returning here with type `*const impl Sized`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:27:16
|
LL | fn fn_ptr() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `fn() -> impl Sized`
+ | ^^^^^^^^^^ recursive opaque type
+LL |
+LL | fn_ptr as fn() -> _
+ | ------------------- returning here with type `fn() -> impl Sized`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:32:25
|
-LL | fn closure_capture() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6 x:impl Sized]`
+LL | fn closure_capture() -> impl Sized {
+ | ^^^^^^^^^^ recursive opaque type
+...
+LL | / move || {
+LL | | x;
+LL | | }
+ | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6 x:impl Sized]`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:40:29
|
-LL | fn closure_ref_capture() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6 x:impl Sized]`
+LL | fn closure_ref_capture() -> impl Sized {
+ | ^^^^^^^^^^ recursive opaque type
+...
+LL | / move || {
+LL | | &x;
+LL | | }
+ | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6 x:impl Sized]`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:48:21
|
LL | fn closure_sig() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:21]`
+ | ^^^^^^^^^^ recursive opaque type
+LL |
+LL | || closure_sig()
+ | ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:21]`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:53:23
|
LL | fn generator_sig() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:23]`
+ | ^^^^^^^^^^ recursive opaque type
+LL |
+LL | || generator_sig()
+ | ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:23]`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:58:27
|
-LL | fn generator_capture() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 x:impl Sized {()}]`
+LL | fn generator_capture() -> impl Sized {
+ | ^^^^^^^^^^ recursive opaque type
+...
+LL | / move || {
+LL | | yield;
+LL | | x;
+LL | | }
+ | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 x:impl Sized {()}]`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:67:35
|
LL | fn substs_change<T: 'static>() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `(impl Sized,)`
+ | ^^^^^^^^^^ recursive opaque type
+LL |
+LL | (substs_change::<&T>(),)
+ | ------------------------ returning here with type `(impl Sized,)`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:72:24
|
-LL | fn generator_hold() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6 {impl Sized, ()}]`
+LL | fn generator_hold() -> impl Sized {
+ | ^^^^^^^^^^ recursive opaque type
+LL |
+LL | / move || {
+LL | | let x = generator_hold();
+LL | | yield;
+LL | | x;
+LL | | }
+ | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6 {impl Sized, ()}]`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:86:26
|
LL | fn mutual_recursion() -> impl Sync {
- | ^^^^^^^^^ expands to a recursive type
- |
- = note: type resolves to itself
+ | ^^^^^^^^^ recursive opaque type
+LL |
+LL | mutual_recursion_b()
+ | -------------------- returning here with type `impl Sized`
+...
+LL | fn mutual_recursion_b() -> impl Sized {
+ | ---------- returning this opaque type `impl Sized`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:91:28
|
+LL | fn mutual_recursion() -> impl Sync {
+ | --------- returning this opaque type `impl std::marker::Sync`
+...
LL | fn mutual_recursion_b() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: type resolves to itself
+ | ^^^^^^^^^^ recursive opaque type
+LL |
+LL | mutual_recursion()
+ | ------------------ returning here with type `impl std::marker::Sync`
error: aborting due to 14 previous errors
fn id<T>(t: T) -> impl Sized { t }
-fn recursive_id() -> impl Sized { //~ ERROR opaque type expands to a recursive type
+fn recursive_id() -> impl Sized { //~ ERROR cannot resolve opaque type
id(recursive_id2())
}
-fn recursive_id2() -> impl Sized { //~ ERROR opaque type expands to a recursive type
+fn recursive_id2() -> impl Sized { //~ ERROR cannot resolve opaque type
id(recursive_id())
}
fn wrap<T>(t: T) -> impl Sized { (t,) }
-fn recursive_wrap() -> impl Sized { //~ ERROR opaque type expands to a recursive type
+fn recursive_wrap() -> impl Sized { //~ ERROR cannot resolve opaque type
wrap(recursive_wrap2())
}
-fn recursive_wrap2() -> impl Sized { //~ ERROR opaque type expands to a recursive type
+fn recursive_wrap2() -> impl Sized { //~ ERROR cannot resolve opaque type
wrap(recursive_wrap())
}
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-through-non-recursive.rs:7:22
|
+LL | fn id<T>(t: T) -> impl Sized { t }
+ | ---------- returning this opaque type `impl Sized`
+LL |
LL | fn recursive_id() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: type resolves to itself
+ | ^^^^^^^^^^ recursive opaque type
+LL | id(recursive_id2())
+ | ------------------- returning here with type `impl Sized`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-through-non-recursive.rs:11:23
|
+LL | fn id<T>(t: T) -> impl Sized { t }
+ | ---------- returning this opaque type `impl Sized`
+...
LL | fn recursive_id2() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: type resolves to itself
+ | ^^^^^^^^^^ recursive opaque type
+LL | id(recursive_id())
+ | ------------------ returning here with type `impl Sized`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-through-non-recursive.rs:17:24
|
+LL | fn wrap<T>(t: T) -> impl Sized { (t,) }
+ | ---------- returning this opaque type `impl Sized`
+LL |
LL | fn recursive_wrap() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `((impl Sized,),)`
+ | ^^^^^^^^^^ recursive opaque type
+LL | wrap(recursive_wrap2())
+ | ----------------------- returning here with type `impl Sized`
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-through-non-recursive.rs:21:25
|
+LL | fn wrap<T>(t: T) -> impl Sized { (t,) }
+ | ---------- returning this opaque type `impl Sized`
+...
LL | fn recursive_wrap2() -> impl Sized {
- | ^^^^^^^^^^ expands to a recursive type
- |
- = note: expanded type is `((impl Sized,),)`
+ | ^^^^^^^^^^ recursive opaque type
+LL | wrap(recursive_wrap())
+ | ---------------------- returning here with type `impl Sized`
error: aborting due to 4 previous errors
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
--> $DIR/static-return-lifetime-infered.rs:7:16
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
- | ----- ----------------------- ...is required to be `'static` by this...
- | |
- | data with this lifetime...
+ | ----- this data with an anonymous lifetime `'_`...
LL | self.x.iter().map(|a| a.0)
| ------ ^^^^
| |
- | ...and is captured here
+ | ...is captured here...
|
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the method body at 6:5
+note: ...and is required to live as long as `'static` here
+ --> $DIR/static-return-lifetime-infered.rs:6:35
+ |
+LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
| ^^^^
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
--> $DIR/static-return-lifetime-infered.rs:11:16
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
- | -------- ----------------------- ...is required to be `'static` by this...
- | |
- | data with this lifetime...
+ | -------- this data with lifetime `'a`...
LL | self.x.iter().map(|a| a.0)
| ------ ^^^^
| |
- | ...and is captured here
+ | ...is captured here...
|
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the method body at 10:20
+note: ...and is required to live as long as `'static` here
+ --> $DIR/static-return-lifetime-infered.rs:10:37
+ |
+LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
| ^^^^
error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0759`.
use std::fmt::Debug;
// Disallowed
-fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
-//~^ ERROR opaque type expands to a recursive type
+fn in_adt_in_return() -> Vec<impl Debug> { panic!() } //~ ERROR cannot resolve opaque type
fn main() {}
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
--> $DIR/where-allowed-2.rs:6:30
|
LL | fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
- | ^^^^^^^^^^ expands to a recursive type
+ | ^^^^^^^^^^ -------- this returned value is of `!` type
+ | |
+ | cannot resolve opaque type
|
- = note: type resolves to itself
+ = help: this error will resolve once the item's body returns a concrete type
error: aborting due to previous error
-//
-// We get an error message at the top of file (dummy span).
-// This is not helpful, but also kind of annoying to prevent,
-// so for now just live with it.
-// This test case was originally for issue #2258.
-
// build-fail
trait ToOpt: Sized {
}
fn function<T:ToOpt + Clone>(counter: usize, t: T) {
-//~^ ERROR reached the recursion limit while instantiating `function::<std::option::Option<
if counter > 0 {
function(counter - 1, t.to_option());
- // FIXME(#4287) Error message should be here. It should be
- // a type error to instantiate `test` at a type other than T.
+ //~^ ERROR reached the recursion limit while instantiating `function::<std::option::Option<
}
}
error: reached the recursion limit while instantiating `function::<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<usize>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- --> $DIR/infinite-instantiation.rs:25:1
+ --> $DIR/infinite-instantiation.rs:21:9
+ |
+LL | function(counter - 1, t.to_option());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `function` defined here
+ --> $DIR/infinite-instantiation.rs:19:1
|
LL | / fn function<T:ToOpt + Clone>(counter: usize, t: T) {
-LL | |
LL | | if counter > 0 {
LL | | function(counter - 1, t.to_option());
-... |
+LL | |
LL | | }
LL | | }
| |_^
+// Don't allow unstable features in stable functions without `allow_internal_unstable`.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
#![feature(staged_api)]
-#![feature(const_if_match)]
+#![feature(const_transmute, const_fn)]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
-const fn foo() -> i32 {
- if true { 4 } else { 5 } //~ loops and conditional expressions are not stable in const fn
+pub const fn foo() -> i32 {
+ unsafe { std::mem::transmute(4u32) } //~ ERROR is not stable as `const fn`
}
fn main() {}
-error[E0723]: loops and conditional expressions are not stable in const fn
- --> $DIR/internal-unstable-const.rs:7:5
+error[E0723]: can only call other `const fn` within a `const fn`, but `const std::intrinsics::transmute::<u32, i32>` is not stable as `const fn`
+ --> $DIR/internal-unstable-const.rs:11:14
|
-LL | if true { 4 } else { 5 }
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe { std::mem::transmute(4u32) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
= help: add `#![feature(const_fn)]` to the crate attributes to enable
fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
- *x //~^ ERROR the trait bound `u32: std::future::Future` is not satisfied
+ *x //~^ ERROR `u32` is not a future
}
fn main() {
LL | let _ = test_ref & u;
| ^ not found in this scope
-error[E0277]: the trait bound `u32: std::future::Future` is not satisfied
+error[E0277]: `u32` is not a future
--> $DIR/issues-71798.rs:1:25
|
LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `u32`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
LL | *x
| -- this returned value is of type `u32`
|
+ = help: the trait `std::future::Future` is not implemented for `u32`
= note: the return type of a function must have a statically known size
error: aborting due to 2 previous errors
|
= help: the trait `std::marker::Sized` is not implemented for `str`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider relaxing the implicit `Sized` restriction
+ |
+LL | trait Serializable<'self, T: ?Sized> {
+ | ^^^^^^^^
error: aborting due to 9 previous errors
--> $DIR/issue-10991.rs:3:14
|
LL | let _t = nil as usize;
- | ^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to previous error
}
impl<'a> NoLifetime for Foo<'a> {
- fn get<'p, T : Test<'a>>(&self) -> T {
+ fn get<'p, T: Test<'a> + From<Foo<'a>>>(&self) -> T {
//~^ ERROR E0195
//~| NOTE lifetimes do not match method in trait
return *self as T;
//~^ ERROR non-primitive cast: `Foo<'a>` as `T`
- //~| NOTE an `as` expression can only be used to convert between primitive types.
+ //~| NOTE an `as` expression can only be used to convert between primitive types
}
}
LL | fn get<'p, T : Test<'p>>(&self) -> T;
| ------------------ lifetimes in impl do not match this method in trait
...
-LL | fn get<'p, T : Test<'a>>(&self) -> T {
- | ^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
+LL | fn get<'p, T: Test<'a> + From<Foo<'a>>>(&self) -> T {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
error[E0605]: non-primitive cast: `Foo<'a>` as `T`
--> $DIR/issue-16048.rs:24:16
|
LL | return *self as T;
- | ^^^^^^^^^^
+ | ^^^^^^^^^^ help: consider using the `From` trait instead: `T::from(*self)`
|
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to 2 previous errors
struct Empty;
// This used to cause an ICE
+#[allow(improper_ctypes_definitions)]
extern "C" fn ice(_a: Empty) {}
fn main() {
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
--> $DIR/issue-16922.rs:4:14
|
LL | fn foo<T: Any>(value: &T) -> Box<dyn Any> {
- | -- data with this lifetime...
+ | -- this data with an anonymous lifetime `'_`...
LL | Box::new(value) as Box<dyn Any>
- | ---------^^^^^-
- | | |
- | | ...and is captured here
- | ...is required to be `'static` by this...
+ | ^^^^^ ...is captured here, requiring it to live as long as `'static`
|
-help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1
+help: to declare that the trait object captures data from argument `value`, you can add an explicit `'_` lifetime bound
|
LL | fn foo<T: Any>(value: &T) -> Box<dyn Any + '_> {
| ^^^^
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0759`.
LL | let _bar = Box::new(1_usize) as dyn std::fmt::Debug;
| ^^^^^^^^^^^^^^^^^^^^^-------------------
| |
- | help: try casting to a `Box` instead: `Box<dyn std::fmt::Debug>`
+ | help: you can cast to a `Box` instead: `Box<dyn std::fmt::Debug>`
error[E0620]: cast to unsized type: `usize` as `dyn std::fmt::Debug`
--> $DIR/issue-17441.rs:8:16
const C1: &'static mut [usize] = &mut [];
-//~^ ERROR: references in constants may only refer to immutable values
+//~^ ERROR: mutable references are not allowed in constants
static mut S: usize = 3;
const C2: &'static mut usize = unsafe { &mut S };
//~^ ERROR: constants cannot refer to statics
//~| ERROR: constants cannot refer to statics
-//~| ERROR: references in constants may only refer to immutable values
+//~| ERROR: mutable references are not allowed in constants
fn main() {}
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
--> $DIR/issue-17718-const-bad-values.rs:1:34
|
LL | const C1: &'static mut [usize] = &mut [];
- | ^^^^^^^ constants require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^^ `&mut` is only allowed in `const fn`
error[E0013]: constants cannot refer to statics
--> $DIR/issue-17718-const-bad-values.rs:5:46
|
= help: consider extracting the value of the `static` to a `const`, and referring to that
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
--> $DIR/issue-17718-const-bad-values.rs:5:41
|
LL | const C2: &'static mut usize = unsafe { &mut S };
- | ^^^^^^ constants require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^ `&mut` is only allowed in `const fn`
error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0013, E0658.
+Some errors have detailed explanations: E0013, E0764.
For more information about an error, try `rustc --explain E0013`.
// build-pass
#![allow(dead_code)]
#![allow(non_camel_case_types)]
+#![warn(clashing_extern_declarations)]
// pretty-expanded FIXME #23616
use super::rust_task;
extern {
pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
+ //~^ WARN `rust_task_is_unwinding` redeclared with a different signature
}
}
}
--- /dev/null
+warning: `rust_task_is_unwinding` redeclared with a different signature
+ --> $DIR/issue-1866.rs:23:13
+ |
+LL | pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
+ | ------------------------------------------------------------ `rust_task_is_unwinding` previously declared here
+...
+LL | pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ |
+note: the lint level is defined here
+ --> $DIR/issue-1866.rs:4:9
+ |
+LL | #![warn(clashing_extern_declarations)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `unsafe extern "C" fn(*const usize) -> bool`
+ found `unsafe extern "C" fn(*const bool) -> bool`
+
+warning: 1 warning emitted
+
|
= help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+ --> $DIR/issue-18919.rs:7:13
+ |
+LL | enum Option<T> {
+ | ^ this could be changed to `T: ?Sized`...
+LL | Some(T),
+ | - ...if indirection was used here: `Box<T>`
error: aborting due to previous error
--> $DIR/issue-22289.rs:2:5
|
LL | 0 as &dyn std::any::Any;
- | ^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
|
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+help: borrow the value for the cast to be valid
+ |
+LL | &0 as &dyn std::any::Any;
+ | ^
error: aborting due to previous error
use std::ops::Index;
-pub trait Array2D: Index<usize> {
+pub trait Array2D: Index<usize> + Sized {
fn rows(&self) -> usize;
fn columns(&self) -> usize;
fn get<'a>(&'a self, y: usize, x: usize) -> Option<&'a <Self as Index<usize>>::Output> {
--> $DIR/issue-22312.rs:11:24
|
LL | let indexer = &(*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
|
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+help: borrow the value for the cast to be valid
+ |
+LL | let indexer = &(&*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>);
+ | ^
error: aborting due to previous error
}
fn main() {
- let ex = |x| { //~ ERROR type annotations needed
- let_(add(x,x), |y| {
+ let ex = |x| {
+ let_(add(x,x), |y| { //~ ERROR type annotations needed
let_(add(x, x), |x|x)})};
}
-error[E0282]: type annotations needed for `Expr<'_, VAR>`
- --> $DIR/issue-23046.rs:17:15
+error[E0282]: type annotations needed for the closure `fn(Expr<'_, _>) -> Expr<'_, _>`
+ --> $DIR/issue-23046.rs:18:9
|
-LL | let ex = |x| {
- | ^ consider giving this closure parameter the explicit type `Expr<'_, VAR>`, where the type parameter `VAR` is specified
+LL | let_(add(x,x), |y| {
+ | ^^^^ cannot infer type for type parameter `VAR` declared on the function `let_`
+ |
+help: give this closure an explicit return type without `_` placeholders
+ |
+LL | let_(add(x, x), |x|-> Expr<'_, _> { x })})};
+ | ^^^^^^^^^^^^^^^^ ^
error: aborting due to previous error
+++ /dev/null
-//~ ERROR
-
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-unsafe auto trait Trait {
- type Output; //~ ERROR E0380
-}
-
-fn call_method<T: Trait>(x: T) {}
-
-fn main() {
- // ICE
- call_method(());
-}
+++ /dev/null
-error[E0380]: auto traits cannot have methods or associated items
- --> $DIR/issue-23080-2.rs:7:10
- |
-LL | unsafe auto trait Trait {
- | ----- auto trait cannot have items
-LL | type Output;
- | ^^^^^^
-
-error[E0275]: overflow evaluating the requirement `<() as Trait>::Output`
- |
- = note: required because of the requirements on the impl of `Trait` for `()`
- = note: required because of the requirements on the impl of `Trait` for `()`
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0275, E0380.
-For more information about an error, try `rustc --explain E0275`.
+++ /dev/null
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-unsafe auto trait Trait {
- fn method(&self) { //~ ERROR E0380
- println!("Hello");
- }
-}
-
-fn call_method<T: Trait>(x: T) {
- x.method();
-}
-
-fn main() {
- // ICE
- call_method(());
-}
+++ /dev/null
-error[E0380]: auto traits cannot have methods or associated items
- --> $DIR/issue-23080.rs:5:8
- |
-LL | unsafe auto trait Trait {
- | ----- auto trait cannot have items
-LL | fn method(&self) {
- | ^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0380`.
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+ --> $DIR/issue-23281.rs:8:12
+ |
+LL | struct Vec<T> {
+ | ^ this could be changed to `T: ?Sized`...
+LL | t: T,
+ | - ...if indirection was used here: `Box<T>`
error: aborting due to previous error
fn id<T>(t: T) -> T { t }
fn main() {
const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
- //~^ ERROR comparing raw pointers inside constant
+ //~^ ERROR pointers cannot be reliably compared during const eval
println!("{}", A);
}
-error[E0658]: comparing raw pointers inside constant
+error: pointers cannot be reliably compared during const eval.
--> $DIR/issue-25826.rs:3:30
|
LL | const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
- = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+mod foo {
+ pub struct B(pub ());
+}
+
+mod baz {
+ fn foo() {
+ B(());
+ //~^ ERROR cannot find function, tuple struct or tuple variant `B` in this scope [E0425]
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0425]: cannot find function, tuple struct or tuple variant `B` in this scope
+ --> $DIR/issue-26545.rs:7:9
+ |
+LL | B(());
+ | ^ not found in this scope
+ |
+help: consider importing this tuple struct
+ |
+LL | use foo::B;
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
}
impl Foo {
+ #[allow(improper_ctypes_definitions)]
pub extern fn foo_new() -> Foo {
Foo { x: 21, y: 33 }
}
impl Test {
#[allow(dead_code)]
#[allow(unused_variables)]
+ #[allow(improper_ctypes_definitions)]
pub extern fn test(val: &str) {
}
--> $DIR/issue-2995.rs:2:22
|
LL | let _q: &isize = p as &isize;
- | ^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to previous error
// check-pass
#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
fn main() {}
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-35376.rs:2:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
| -^- &T
| |
| &T
+ |
+help: consider restricting type parameter `T`
+ |
+LL | fn func<'a, T: std::ops::Mul<Output = &T>>(a: &'a [T]) -> impl Iterator<Item=&'a T> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
fn main() {}
mod x {
- enum Enum {
+ pub enum Enum {
Variant1,
Variant2(),
Variant3(usize),
-// run-pass
#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
trait Iterate<'a> {
type Ty: Valid;
}
impl<'a, T> Iterate<'a> for T where T: Check {
default type Ty = ();
+ //~^ ERROR the trait bound `(): Valid` is not satisfied
default fn iterate(self) {}
}
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-38091.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+error[E0277]: the trait bound `(): Valid` is not satisfied
+ --> $DIR/issue-38091.rs:9:5
+ |
+LL | type Ty: Valid;
+ | --------------- required by `Iterate::Ty`
+...
+LL | default type Ty = ();
+ | ^^^^^^^^^^^^^^^^^^^^^ the trait `Valid` is not implemented for `()`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
pub struct Foo(i128);
#[no_mangle]
+#[allow(improper_ctypes_definitions)]
pub extern "C" fn foo(x: Foo) -> Foo { x }
fn main() {
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/issue-40000.rs:6:9
+ |
+LL | foo(bar);
+ | ^^^
+
+error: aborting due to previous error
+
--> $DIR/issue-40000.rs:6:9
|
LL | foo(bar);
- | ^^^ expected concrete lifetime, found bound lifetime parameter
+ | ^^^ one type is more general than the other
|
- = note: expected struct `std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r i32) + 'static)>`
- found struct `std::boxed::Box<dyn std::ops::Fn(_)>`
+ = note: expected trait object `dyn for<'r> std::ops::Fn(&'r i32)`
+ found trait object `dyn std::ops::Fn(&i32)`
error: aborting due to previous error
mod foo {
- pub struct B(());
+ pub struct Bx(());
}
mod bar {
- use foo::B;
+ use foo::Bx;
fn foo() {
- B(());
- //~^ ERROR expected function, tuple struct or tuple variant, found struct `B` [E0423]
+ Bx(());
+ //~^ ERROR expected function, tuple struct or tuple variant, found struct `Bx` [E0423]
}
}
mod baz {
fn foo() {
- B(());
- //~^ ERROR cannot find function, tuple struct or tuple variant `B` in this scope [E0425]
+ Bx(());
+ //~^ ERROR cannot find function, tuple struct or tuple variant `Bx` in this scope [E0425]
}
}
-error[E0423]: expected function, tuple struct or tuple variant, found struct `B`
+error[E0423]: expected function, tuple struct or tuple variant, found struct `Bx`
--> $DIR/issue-42944.rs:9:9
|
-LL | B(());
- | ^ constructor is not visible here due to private fields
+LL | Bx(());
+ | ^^ constructor is not visible here due to private fields
-error[E0425]: cannot find function, tuple struct or tuple variant `B` in this scope
+error[E0425]: cannot find function, tuple struct or tuple variant `Bx` in this scope
--> $DIR/issue-42944.rs:16:9
|
-LL | B(());
- | ^ not found in this scope
+LL | Bx(());
+ | ^^ not found in this scope
|
help: consider importing this tuple struct
|
-LL | use foo::B;
+LL | use foo::Bx;
|
error: aborting due to 2 previous errors
}
pub fn break_me<T, F>(f: F)
-where T: for<'b> Trait<'b>,
- F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
+where
+ T: for<'b> Trait<'b>,
+ F: for<'b> FnMut(<T as Trait<'b>>::Assoc),
+{
break_me::<Type, fn(_)>;
//~^ ERROR: type mismatch in function arguments
- //~| ERROR: type mismatch resolving
}
fn main() {}
error[E0631]: type mismatch in function arguments
- --> $DIR/issue-43623.rs:14:5
+ --> $DIR/issue-43623.rs:16:5
|
LL | pub fn break_me<T, F>(f: F)
| -------- required by a bound in this
-LL | where T: for<'b> Trait<'b>,
-LL | F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
- | -------------------------------------- required by this bound in `break_me`
+...
+LL | F: for<'b> FnMut(<T as Trait<'b>>::Assoc),
+ | ------------------------------ required by this bound in `break_me`
+LL | {
LL | break_me::<Type, fn(_)>;
| ^^^^^^^^^^^^^^^^^^^^^^^
| |
- | expected signature of `for<'b> fn(<Type as Trait<'b>>::Assoc) -> _`
- | found signature of `fn(_) -> _`
+ | expected signature of `fn(<Type as Trait<'b>>::Assoc) -> _`
+ | found signature of `fn(()) -> _`
-error[E0271]: type mismatch resolving `for<'b> <fn(_) as std::ops::FnOnce<(<Type as Trait<'b>>::Assoc,)>>::Output == ()`
- --> $DIR/issue-43623.rs:14:5
- |
-LL | pub fn break_me<T, F>(f: F)
- | -------- required by a bound in this
-LL | where T: for<'b> Trait<'b>,
-LL | F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
- | ------------------------------ required by this bound in `break_me`
-LL | break_me::<Type, fn(_)>;
- | ^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'b, found concrete lifetime
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0631`.
LL | foo();
| ^^^ not a function
|
-help: consider importing one of these items instead
+help: consider importing this function instead
|
LL | use foo::foo;
|
-LL | use m1::foo;
- |
error: aborting due to 2 previous errors
LL | fn sub() -> isize { foo(); 1 }
| ^^^ not found in this scope
|
-help: consider importing one of these items
+help: consider importing this function
|
LL | use foo::foo;
|
-LL | use m1::foo;
- |
error: aborting due to previous error
-error: unterminated double quote string
+error[E0765]: unterminated double quote string
--> $DIR/issue-44078.rs:2:8
|
LL | "😊"";
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0765`.
error[E0641]: cannot cast to a pointer of an unknown kind
- --> $DIR/issue-45730.rs:3:23
+ --> $DIR/issue-45730.rs:3:28
|
LL | let x: *const _ = 0 as _;
- | ^^^^^-
- | |
- | help: consider giving more type information
+ | ^ needs more type information
|
= note: the type information given here is insufficient to check whether the pointer cast is valid
error[E0641]: cannot cast to a pointer of an unknown kind
- --> $DIR/issue-45730.rs:5:23
+ --> $DIR/issue-45730.rs:5:28
|
LL | let x: *const _ = 0 as *const _;
- | ^^^^^--------
- | |
- | help: consider giving more type information
+ | ^^^^^^^^ needs more type information
|
= note: the type information given here is insufficient to check whether the pointer cast is valid
error[E0641]: cannot cast to a pointer of an unknown kind
- --> $DIR/issue-45730.rs:8:13
+ --> $DIR/issue-45730.rs:8:44
|
LL | let x = 0 as *const i32 as *const _ as *mut _;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------
- | |
- | help: consider giving more type information
+ | ^^^^^^ needs more type information
|
= note: the type information given here is insufficient to check whether the pointer cast is valid
-static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR E0658
+static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR E0764
fn write<T: AsRef<[u8]>>(buffer: T) { }
fn main() {
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
--> $DIR/issue-46604.rs:1:25
|
LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7];
- | ^^^^^^^^^^^^^^^^^^^^ statics require immutable values
- |
- = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
- = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+ | ^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn`
error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item
--> $DIR/issue-46604.rs:6:5
error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0594, E0658.
+Some errors have detailed explanations: E0594, E0764.
For more information about an error, try `rustc --explain E0594`.
// ignore-asmjs wasm2js does not support source maps yet
#![feature(non_ascii_idents)]
-#[allow(uncommon_codepoints)]
+#![allow(uncommon_codepoints)]
#[path = "issue-48508-aux.rs"]
mod other_file;
[(); return while let Some(n) = Some(0) {}];
//~^ ERROR return statement outside of function body
- //~| ERROR `while` is not allowed in a `const`
}
-error[E0658]: `while` is not allowed in a `const`
- --> $DIR/issue-51714.rs:11:17
- |
-LL | [(); return while let Some(n) = Some(0) {}];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
- = help: add `#![feature(const_loop)]` to the crate attributes to enable
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
error[E0572]: return statement outside of function body
--> $DIR/issue-51714.rs:2:14
|
LL | [(); return while let Some(n) = Some(0) {}];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0572, E0658.
-For more information about an error, try `rustc --explain E0572`.
+For more information about this error, try `rustc --explain E0572`.
struct Bar;
impl Foo for Bar {
+ #[allow(improper_ctypes_definitions)]
extern fn borrow(&self) {}
+ #[allow(improper_ctypes_definitions)]
extern fn take(self: Box<Self>) {}
}
| |
| cannot use `+=` on type `&isize`
|
-help: `+=` can be used on 'isize', you can dereference `x`
+help: `+=` can be used on `isize`, you can dereference `x`
|
LL | let x = |ref x: isize| { *x += 1; };
- | ^^
+ | ^
error: aborting due to previous error
// run-pass
-
#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
pub trait Foo {
fn abc() -> u32;
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-55380.rs:2:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
LL | let x = <fn (&())>::make_g();
| ^^^^^^ function or associated item not found in `for<'r> fn(&'r ())`
|
+ = note: the method `make_g` exists but the following trait bounds were not satisfied:
+ `for<'r> fn(&'r ()): X`
= help: items from traits can only be used if the trait is implemented and in scope
note: `X` defines an item `make_g`, perhaps you need to implement it
--> $DIR/issue-57362-2.rs:8:1
// run-pass
#![allow(dead_code)]
+#![warn(clashing_extern_declarations)]
// pretty-expanded FIXME #23616
extern {
#[link_name = "malloc"]
fn malloc1(len: i32) -> *const u8;
#[link_name = "malloc"]
+ //~^ WARN `malloc2` redeclares `malloc` with a different signature
fn malloc2(len: i32, foo: i32) -> *const u8;
}
--- /dev/null
+warning: `malloc2` redeclares `malloc` with a different signature
+ --> $DIR/issue-5791.rs:9:5
+ |
+LL | / #[link_name = "malloc"]
+LL | | fn malloc1(len: i32) -> *const u8;
+ | |______________________________________- `malloc` previously declared here
+LL | / #[link_name = "malloc"]
+LL | |
+LL | | fn malloc2(len: i32, foo: i32) -> *const u8;
+ | |________________________________________________^ this signature doesn't match the previous declaration
+ |
+note: the lint level is defined here
+ --> $DIR/issue-5791.rs:3:9
+ |
+LL | #![warn(clashing_extern_declarations)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `unsafe extern "C" fn(i32) -> *const u8`
+ found `unsafe extern "C" fn(i32, i32) -> *const u8`
+
+warning: 1 warning emitted
+
--- /dev/null
+// check-pass
+trait Service {
+ type S;
+}
+
+trait Framing {
+ type F;
+}
+
+impl Framing for () {
+ type F = ();
+}
+
+trait HttpService<F: Framing>: Service<S = F::F> {}
+
+type BoxService = Box<dyn HttpService<(), S = ()>>;
+
+fn build_server<F: FnOnce() -> BoxService>(_: F) {}
+
+fn make_server<F: Framing>() -> Box<dyn HttpService<F, S = F::F>> {
+ unimplemented!()
+}
+
+fn main() {
+ build_server(|| make_server())
+}
}
pub fn foo<T, F>(_: T, _: F)
-where T: for<'a> Trait<'a>,
- F: for<'a> FnMut(<T as Trait<'a>>::Item) {}
+where
+ T: for<'a> Trait<'a>,
+ F: for<'a> FnMut(<T as Trait<'a>>::Item),
+{
+}
fn main() {
foo((), drop)
//~^ ERROR type mismatch in function arguments
- //~| ERROR type mismatch resolving
}
error[E0631]: type mismatch in function arguments
- --> $DIR/issue-60283.rs:14:13
+ --> $DIR/issue-60283.rs:17:13
|
LL | pub fn foo<T, F>(_: T, _: F)
| --- required by a bound in this
-LL | where T: for<'a> Trait<'a>,
-LL | F: for<'a> FnMut(<T as Trait<'a>>::Item) {}
- | ------------------------------------- required by this bound in `foo`
+...
+LL | F: for<'a> FnMut(<T as Trait<'a>>::Item),
+ | ----------------------------- required by this bound in `foo`
...
LL | foo((), drop)
| ^^^^
| |
- | expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _`
- | found signature of `fn(_) -> _`
-
-error[E0271]: type mismatch resolving `for<'a> <fn(_) {std::mem::drop::<_>} as std::ops::FnOnce<(<() as Trait<'a>>::Item,)>>::Output == ()`
- --> $DIR/issue-60283.rs:14:5
- |
-LL | pub fn foo<T, F>(_: T, _: F)
- | --- required by a bound in this
-LL | where T: for<'a> Trait<'a>,
-LL | F: for<'a> FnMut(<T as Trait<'a>>::Item) {}
- | ----------------------------- required by this bound in `foo`
-...
-LL | foo((), drop)
- | ^^^ expected bound lifetime parameter 'a, found concrete lifetime
+ | expected signature of `fn(<() as Trait<'a>>::Item) -> _`
+ | found signature of `fn(()) -> _`
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0631`.
fn d() {
[0; match [|f @ &ref _| () ] {} ]
//~^ ERROR expected identifier, found reserved identifier `_`
- //~| ERROR `match` is not allowed in a `const`
//~| ERROR mismatched types
}
LL | [0; match [|f @ &ref _| () ] {} ]
| ^ expected identifier, found reserved identifier
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/issue-66706.rs:20:9
- |
-LL | [0; match [|f @ &ref _| () ] {} ]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
error[E0282]: type annotations needed
--> $DIR/issue-66706.rs:2:11
|
LL | [0; match [|f @ &ref _| () ] {} ]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]`
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
-Some errors have detailed explanations: E0282, E0308, E0658.
+Some errors have detailed explanations: E0282, E0308.
For more information about an error, try `rustc --explain E0282`.
}
fn rec<T>(mut it: T)
-//~^ ERROR reached the recursion limit while instantiating
where
T: Iterator,
{
T::count(it);
} else {
rec(identity(&mut it))
+ //~^ ERROR reached the recursion limit while instantiating
}
}
error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Empty>`
+ --> $DIR/issue-67552.rs:27:9
+ |
+LL | rec(identity(&mut it))
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `rec` defined here
--> $DIR/issue-67552.rs:20:1
|
LL | / fn rec<T>(mut it: T)
-LL | |
LL | | where
LL | | T: Iterator,
+LL | | {
... |
LL | | }
LL | | }
--- /dev/null
+fn no_err() {
+ |x: String| x;
+ let _ = String::from("x");
+}
+
+fn err() {
+ String::from("x".as_ref()); //~ ERROR type annotations needed
+}
+
+fn arg_pat_closure_err() {
+ |x| String::from("x".as_ref()); //~ ERROR type annotations needed
+}
+
+fn local_pat_closure_err() {
+ let _ = "x".as_ref(); //~ ERROR type annotations needed
+}
+
+fn err_first_arg_pat() {
+ String::from("x".as_ref()); //~ ERROR type annotations needed
+ |x: String| x;
+}
+
+fn err_second_arg_pat() {
+ |x: String| x;
+ String::from("x".as_ref()); //~ ERROR type annotations needed
+}
+
+fn err_mid_arg_pat() {
+ |x: String| x;
+ |x: String| x;
+ |x: String| x;
+ |x: String| x;
+ String::from("x".as_ref()); //~ ERROR type annotations needed
+ |x: String| x;
+ |x: String| x;
+ |x: String| x;
+ |x: String| x;
+}
+
+fn err_first_local_pat() {
+ String::from("x".as_ref()); //~ ERROR type annotations needed
+ let _ = String::from("x");
+}
+
+fn err_second_local_pat() {
+ let _ = String::from("x");
+ String::from("x".as_ref()); //~ ERROR type annotations needed
+}
+
+fn err_mid_local_pat() {
+ let _ = String::from("x");
+ let _ = String::from("x");
+ let _ = String::from("x");
+ let _ = String::from("x");
+ String::from("x".as_ref()); //~ ERROR type annotations needed
+ let _ = String::from("x");
+ let _ = String::from("x");
+ let _ = String::from("x");
+ let _ = String::from("x");
+}
+
+fn main() {}
--- /dev/null
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:7:5
+ |
+LL | String::from("x".as_ref());
+ | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
+ |
+ = note: cannot satisfy `std::string::String: std::convert::From<&_>`
+ = note: required by `std::convert::From::from`
+
+error[E0282]: type annotations needed
+ --> $DIR/issue-72690.rs:11:6
+ |
+LL | |x| String::from("x".as_ref());
+ | ^ consider giving this closure parameter a type
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:15:17
+ |
+LL | let _ = "x".as_ref();
+ | ^^^^^^ cannot infer type for type `str`
+ |
+ = note: cannot satisfy `str: std::convert::AsRef<_>`
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:19:5
+ |
+LL | String::from("x".as_ref());
+ | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
+ |
+ = note: cannot satisfy `std::string::String: std::convert::From<&_>`
+ = note: required by `std::convert::From::from`
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:25:5
+ |
+LL | String::from("x".as_ref());
+ | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
+ |
+ = note: cannot satisfy `std::string::String: std::convert::From<&_>`
+ = note: required by `std::convert::From::from`
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:33:5
+ |
+LL | String::from("x".as_ref());
+ | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
+ |
+ = note: cannot satisfy `std::string::String: std::convert::From<&_>`
+ = note: required by `std::convert::From::from`
+
+error[E0283]: type annotations needed for `std::string::String`
+ --> $DIR/issue-72690.rs:41:5
+ |
+LL | String::from("x".as_ref());
+ | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
+LL | let _ = String::from("x");
+ | - consider giving this pattern a type
+ |
+ = note: cannot satisfy `std::string::String: std::convert::From<&_>`
+ = note: required by `std::convert::From::from`
+
+error[E0283]: type annotations needed for `std::string::String`
+ --> $DIR/issue-72690.rs:47:5
+ |
+LL | let _ = String::from("x");
+ | - consider giving this pattern a type
+LL | String::from("x".as_ref());
+ | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
+ |
+ = note: cannot satisfy `std::string::String: std::convert::From<&_>`
+ = note: required by `std::convert::From::from`
+
+error[E0283]: type annotations needed for `std::string::String`
+ --> $DIR/issue-72690.rs:55:5
+ |
+LL | let _ = String::from("x");
+ | - consider giving this pattern a type
+...
+LL | String::from("x".as_ref());
+ | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
+ |
+ = note: cannot satisfy `std::string::String: std::convert::From<&_>`
+ = note: required by `std::convert::From::from`
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
--> $DIR/issue-8460-const.rs:14:36
|
LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow
|
= note: `#[deny(arithmetic_overflow)]` on by default
--> $DIR/issue-8460-const.rs:16:36
|
LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:18:36
|
LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:20:36
|
LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:22:36
|
LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:24:36
|
LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:26:36
|
LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
- | ^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^ attempt to divide 1_isize by zero
|
= note: `#[deny(unconditional_panic)]` on by default
--> $DIR/issue-8460-const.rs:28:36
|
LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
- | ^^^^^^^ attempt to divide by zero
+ | ^^^^^^^ attempt to divide 1_i8 by zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:30:36
|
LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^ attempt to divide 1_i16 by zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:32:36
|
LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^ attempt to divide 1_i32 by zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:34:36
|
LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^ attempt to divide 1_i64 by zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:36:36
|
LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
- | ^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^ attempt to divide 1_i128 by zero
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:38:36
|
LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:40:36
|
LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:42:36
|
LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:44:36
|
LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:46:36
|
LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:48:36
|
LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:50:36
|
LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
- | ^^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:52:36
|
LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
- | ^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:54:36
|
LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:56:36
|
LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:58:36
|
LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:60:36
|
LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
- | ^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero
error: aborting due to 24 previous errors
--> $DIR/issue-8460-const.rs:14:36
|
LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow
|
= note: `#[deny(arithmetic_overflow)]` on by default
--> $DIR/issue-8460-const.rs:16:36
|
LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:18:36
|
LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:20:36
|
LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:22:36
|
LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:24:36
|
LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:26:36
|
LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
- | ^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^ attempt to divide 1_isize by zero
|
= note: `#[deny(unconditional_panic)]` on by default
--> $DIR/issue-8460-const.rs:28:36
|
LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
- | ^^^^^^^ attempt to divide by zero
+ | ^^^^^^^ attempt to divide 1_i8 by zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:30:36
|
LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^ attempt to divide 1_i16 by zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:32:36
|
LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^ attempt to divide 1_i32 by zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:34:36
|
LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^ attempt to divide 1_i64 by zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:36:36
|
LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
- | ^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^ attempt to divide 1_i128 by zero
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:38:36
|
LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:40:36
|
LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:42:36
|
LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:44:36
|
LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:46:36
|
LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:48:36
|
LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:50:36
|
LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
- | ^^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:52:36
|
LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
- | ^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:54:36
|
LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:56:36
|
LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:58:36
|
LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:60:36
|
LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
- | ^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero
error: aborting due to 24 previous errors
--> $DIR/issue-8460-const.rs:14:36
|
LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow
|
= note: `#[deny(arithmetic_overflow)]` on by default
--> $DIR/issue-8460-const.rs:16:36
|
LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:18:36
|
LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:20:36
|
LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:22:36
|
LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:24:36
|
LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
- | ^^^^^^^^^^^^^^ attempt to divide with overflow
+ | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:26:36
|
LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
- | ^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^ attempt to divide 1_isize by zero
|
= note: `#[deny(unconditional_panic)]` on by default
--> $DIR/issue-8460-const.rs:28:36
|
LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
- | ^^^^^^^ attempt to divide by zero
+ | ^^^^^^^ attempt to divide 1_i8 by zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:30:36
|
LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^ attempt to divide 1_i16 by zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:32:36
|
LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^ attempt to divide 1_i32 by zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:34:36
|
LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^ attempt to divide 1_i64 by zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:36:36
|
LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
- | ^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^ attempt to divide 1_i128 by zero
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:38:36
|
LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:40:36
|
LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:42:36
|
LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:44:36
|
LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:46:36
|
LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow
error: this arithmetic operation will overflow
--> $DIR/issue-8460-const.rs:48:36
|
LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
- | ^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+ | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:50:36
|
LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
- | ^^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:52:36
|
LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
- | ^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:54:36
|
LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:56:36
|
LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:58:36
|
LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero
error: this operation will panic at runtime
--> $DIR/issue-8460-const.rs:60:36
|
LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
- | ^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero
error: aborting due to 24 previous errors
// build-fail
-fn generic<T>() {
+fn generic<T>() { //~ WARN function cannot return without recursing
generic::<Option<T>>();
}
-//~^^^ ERROR reached the recursion limit while instantiating `generic::<std::option::Option<
-//~| WARN function cannot return without recursing
-
+//~^^ ERROR reached the recursion limit while instantiating `generic::<std::option::Option<
fn main () {
= help: a `loop` may express intention better if this is on purpose
error: reached the recursion limit while instantiating `generic::<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+ --> $DIR/issue-8727.rs:7:5
+ |
+LL | generic::<Option<T>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `generic` defined here
--> $DIR/issue-8727.rs:6:1
|
LL | / fn generic<T>() {
],
},
variants: Multiple {
- discr: Scalar {
+ tag: Scalar {
value: Int(
I32,
false,
),
valid_range: 0..=0,
},
- discr_kind: Tag,
- discr_index: 0,
+ tag_encoding: Direct,
+ tag_field: 0,
variants: [
Layout {
fields: Arbitrary {
],
},
variants: Multiple {
- discr: Scalar {
+ tag: Scalar {
value: Int(
I32,
false,
),
valid_range: 0..=1,
},
- discr_kind: Tag,
- discr_index: 0,
+ tag_encoding: Direct,
+ tag_field: 0,
variants: [
Layout {
fields: Arbitrary {
--- /dev/null
+extern {
+ pub fn extern_fn(x: u8);
+}
--- /dev/null
+// check-pass
+// aux-build:external_extern_fn.rs
+#![crate_type = "lib"]
+#![warn(clashing_extern_declarations)]
+
+extern crate external_extern_fn;
+
+extern "C" {
+ fn clash(x: u8);
+ fn no_clash(x: u8);
+}
+
+fn redeclared_different_signature() {
+ extern "C" {
+ fn clash(x: u64); //~ WARN `clash` redeclared with a different signature
+ }
+
+ unsafe {
+ clash(123);
+ no_clash(123);
+ }
+}
+
+fn redeclared_same_signature() {
+ extern "C" {
+ fn no_clash(x: u8);
+ }
+ unsafe {
+ no_clash(123);
+ }
+}
+
+extern "C" {
+ fn extern_fn(x: u64);
+}
+
+fn extern_clash() {
+ extern "C" {
+ fn extern_fn(x: u32); //~ WARN `extern_fn` redeclared with a different signature
+ }
+ unsafe {
+ extern_fn(123);
+ }
+}
+
+fn extern_no_clash() {
+ unsafe {
+ external_extern_fn::extern_fn(123);
+ crate::extern_fn(123);
+ }
+}
+extern "C" {
+ fn some_other_new_name(x: i16);
+
+ #[link_name = "extern_link_name"]
+ fn some_new_name(x: i16);
+
+ #[link_name = "link_name_same"]
+ fn both_names_different(x: i16);
+}
+
+fn link_name_clash() {
+ extern "C" {
+ fn extern_link_name(x: u32);
+ //~^ WARN `extern_link_name` redeclared with a different signature
+
+ #[link_name = "some_other_new_name"]
+ //~^ WARN `some_other_extern_link_name` redeclares `some_other_new_name` with a different
+ fn some_other_extern_link_name(x: u32);
+
+ #[link_name = "link_name_same"]
+ //~^ WARN `other_both_names_different` redeclares `link_name_same` with a different
+ fn other_both_names_different(x: u32);
+ }
+}
+
+mod a {
+ extern "C" {
+ fn different_mod(x: u8);
+ }
+}
+mod b {
+ extern "C" {
+ fn different_mod(x: u64); //~ WARN `different_mod` redeclared with a different signature
+ }
+}
+
+extern "C" {
+ fn variadic_decl(x: u8, ...);
+}
+
+fn variadic_clash() {
+ extern "C" {
+ fn variadic_decl(x: u8); //~ WARN `variadic_decl` redeclared with a different signature
+ }
+}
+
+#[no_mangle]
+fn no_mangle_name(x: u8) {}
+
+extern "C" {
+ #[link_name = "unique_link_name"]
+ fn link_name_specified(x: u8);
+}
+
+fn tricky_no_clash() {
+ extern "C" {
+ // Shouldn't warn, because the declaration above actually declares a different symbol (and
+ // Rust's name resolution rules around shadowing will handle this gracefully).
+ fn link_name_specified() -> u32;
+
+ // The case of a no_mangle name colliding with an extern decl (see #28179) is related but
+ // shouldn't be reported by ClashingExternDeclarations, because this is an example of
+ // unmangled name clash causing bad behaviour in functions with a defined body.
+ fn no_mangle_name() -> u32;
+ }
+}
+
+mod banana {
+ mod one {
+ #[repr(C)]
+ struct Banana {
+ weight: u32,
+ length: u16,
+ }
+ extern "C" {
+ fn weigh_banana(count: *const Banana) -> u64;
+ }
+ }
+
+ mod two {
+ #[repr(C)]
+ struct Banana {
+ weight: u32,
+ length: u16,
+ } // note: distinct type
+ extern "C" {
+ // This should not trigger the lint because two::Banana is structurally equivalent to
+ // one::Banana.
+ fn weigh_banana(count: *const Banana) -> u64;
+ }
+ }
+
+ mod three {
+ // This _should_ trigger the lint, because repr(packed) should generate a struct that has a
+ // different layout.
+ #[repr(packed)]
+ struct Banana {
+ weight: u32,
+ length: u16,
+ }
+ #[allow(improper_ctypes)]
+ extern "C" {
+ fn weigh_banana(count: *const Banana) -> u64;
+ //~^ WARN `weigh_banana` redeclared with a different signature
+ }
+ }
+}
+
+mod sameish_members {
+ mod a {
+ #[repr(C)]
+ struct Point {
+ x: i16,
+ y: i16,
+ }
+
+ extern "C" {
+ fn draw_point(p: Point);
+ }
+ }
+ mod b {
+ #[repr(C)]
+ struct Point {
+ coordinates: [i16; 2],
+ }
+
+ // It's possible we are overconservative for this case, as accessing the elements of the
+ // coordinates array might end up correctly accessing `.x` and `.y`. However, this may not
+ // always be the case, for every architecture and situation. This is also a really odd
+ // thing to do anyway.
+ extern "C" {
+ fn draw_point(p: Point); //~ WARN `draw_point` redeclared with a different
+ }
+ }
+}
--- /dev/null
+warning: `clash` redeclared with a different signature
+ --> $DIR/clashing-extern-fn.rs:15:9
+ |
+LL | fn clash(x: u8);
+ | ---------------- `clash` previously declared here
+...
+LL | fn clash(x: u64);
+ | ^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ |
+note: the lint level is defined here
+ --> $DIR/clashing-extern-fn.rs:4:9
+ |
+LL | #![warn(clashing_extern_declarations)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `unsafe extern "C" fn(u8)`
+ found `unsafe extern "C" fn(u64)`
+
+warning: `extern_fn` redeclared with a different signature
+ --> $DIR/clashing-extern-fn.rs:39:9
+ |
+LL | fn extern_fn(x: u64);
+ | --------------------- `extern_fn` previously declared here
+...
+LL | fn extern_fn(x: u32);
+ | ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ |
+ = note: expected `unsafe extern "C" fn(u64)`
+ found `unsafe extern "C" fn(u32)`
+
+warning: `extern_link_name` redeclared with a different signature
+ --> $DIR/clashing-extern-fn.rs:64:9
+ |
+LL | / #[link_name = "extern_link_name"]
+LL | | fn some_new_name(x: i16);
+ | |_____________________________- `extern_link_name` previously declared here
+...
+LL | fn extern_link_name(x: u32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ |
+ = note: expected `unsafe extern "C" fn(i16)`
+ found `unsafe extern "C" fn(u32)`
+
+warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature
+ --> $DIR/clashing-extern-fn.rs:67:9
+ |
+LL | fn some_other_new_name(x: i16);
+ | ------------------------------- `some_other_new_name` previously declared here
+...
+LL | / #[link_name = "some_other_new_name"]
+LL | |
+LL | | fn some_other_extern_link_name(x: u32);
+ | |_______________________________________________^ this signature doesn't match the previous declaration
+ |
+ = note: expected `unsafe extern "C" fn(i16)`
+ found `unsafe extern "C" fn(u32)`
+
+warning: `other_both_names_different` redeclares `link_name_same` with a different signature
+ --> $DIR/clashing-extern-fn.rs:71:9
+ |
+LL | / #[link_name = "link_name_same"]
+LL | | fn both_names_different(x: i16);
+ | |____________________________________- `link_name_same` previously declared here
+...
+LL | / #[link_name = "link_name_same"]
+LL | |
+LL | | fn other_both_names_different(x: u32);
+ | |______________________________________________^ this signature doesn't match the previous declaration
+ |
+ = note: expected `unsafe extern "C" fn(i16)`
+ found `unsafe extern "C" fn(u32)`
+
+warning: `different_mod` redeclared with a different signature
+ --> $DIR/clashing-extern-fn.rs:84:9
+ |
+LL | fn different_mod(x: u8);
+ | ------------------------ `different_mod` previously declared here
+...
+LL | fn different_mod(x: u64);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ |
+ = note: expected `unsafe extern "C" fn(u8)`
+ found `unsafe extern "C" fn(u64)`
+
+warning: `variadic_decl` redeclared with a different signature
+ --> $DIR/clashing-extern-fn.rs:94:9
+ |
+LL | fn variadic_decl(x: u8, ...);
+ | ----------------------------- `variadic_decl` previously declared here
+...
+LL | fn variadic_decl(x: u8);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ |
+ = note: expected `unsafe extern "C" fn(u8, ...)`
+ found `unsafe extern "C" fn(u8)`
+
+warning: `weigh_banana` redeclared with a different signature
+ --> $DIR/clashing-extern-fn.rs:154:13
+ |
+LL | fn weigh_banana(count: *const Banana) -> u64;
+ | --------------------------------------------- `weigh_banana` previously declared here
+...
+LL | fn weigh_banana(count: *const Banana) -> u64;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ |
+ = note: expected `unsafe extern "C" fn(*const banana::one::Banana) -> u64`
+ found `unsafe extern "C" fn(*const banana::three::Banana) -> u64`
+
+warning: `draw_point` redeclared with a different signature
+ --> $DIR/clashing-extern-fn.rs:183:13
+ |
+LL | fn draw_point(p: Point);
+ | ------------------------ `draw_point` previously declared here
+...
+LL | fn draw_point(p: Point);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ |
+ = note: expected `unsafe extern "C" fn(sameish_members::a::Point)`
+ found `unsafe extern "C" fn(sameish_members::b::Point)`
+
+warning: 9 warnings emitted
+
--- /dev/null
+#![deny(uncommon_codepoints, unused_attributes)]
+
+mod foo {
+#![allow(uncommon_codepoints)]
+//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+
+#[allow(uncommon_codepoints)]
+//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+const BAR: f64 = 0.000001;
+
+}
+
+#[allow(uncommon_codepoints)]
+//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+fn main() {
+}
--- /dev/null
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:4:10
+ |
+LL | #![allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/crate_level_only_lint.rs:1:30
+ |
+LL | #![deny(uncommon_codepoints, unused_attributes)]
+ | ^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:9:9
+ |
+LL | #[allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:17:9
+ |
+LL | #[allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:4:10
+ |
+LL | #![allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:9:9
+ |
+LL | #[allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:17:9
+ |
+LL | #[allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:4:10
+ |
+LL | #![allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:9:9
+ |
+LL | #[allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:17:9
+ |
+LL | #[allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
#![allow(unused_variables)]
#![allow(non_camel_case_types)]
+#![allow(clashing_extern_declarations)]
#![deny(dead_code)]
#![crate_type="lib"]
error: struct is never constructed: `Foo`
- --> $DIR/lint-dead-code-3.rs:13:8
+ --> $DIR/lint-dead-code-3.rs:14:8
|
LL | struct Foo;
| ^^^
|
note: the lint level is defined here
- --> $DIR/lint-dead-code-3.rs:3:9
+ --> $DIR/lint-dead-code-3.rs:4:9
|
LL | #![deny(dead_code)]
| ^^^^^^^^^
error: associated function is never used: `foo`
- --> $DIR/lint-dead-code-3.rs:15:8
+ --> $DIR/lint-dead-code-3.rs:16:8
|
LL | fn foo(&self) {
| ^^^
error: function is never used: `bar`
- --> $DIR/lint-dead-code-3.rs:20:4
+ --> $DIR/lint-dead-code-3.rs:21:4
|
LL | fn bar() {
| ^^^
error: enum is never used: `c_void`
- --> $DIR/lint-dead-code-3.rs:59:6
+ --> $DIR/lint-dead-code-3.rs:60:6
|
LL | enum c_void {}
| ^^^^^^
error: function is never used: `free`
- --> $DIR/lint-dead-code-3.rs:61:5
+ --> $DIR/lint-dead-code-3.rs:62:5
|
LL | fn free(p: *const c_void);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
--- /dev/null
+// check-pass
+#![deny(improper_ctypes)]
+
+pub trait Foo {
+ type Assoc: 'static;
+}
+
+impl Foo for () {
+ type Assoc = u32;
+}
+
+extern "C" {
+ pub fn lint_me(x: Bar<()>);
+}
+
+#[repr(transparent)]
+pub struct Bar<T: Foo> {
+ value: &'static <T as Foo>::Assoc,
+}
+
+fn main() {}
--- /dev/null
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait Baz { }
+
+impl Baz for () { }
+
+type Qux = impl Baz;
+
+fn assign() -> Qux {}
+
+pub trait Foo {
+ type Assoc: 'static;
+}
+
+impl Foo for () {
+ type Assoc = Qux;
+}
+
+#[repr(transparent)]
+pub struct A<T: Foo> {
+ x: &'static <T as Foo>::Assoc,
+}
+
+extern "C" {
+ pub fn lint_me() -> A<()>; //~ ERROR: uses type `impl Baz`
+}
+
+fn main() {}
--- /dev/null
+error: `extern` block uses type `impl Baz`, which is not FFI-safe
+ --> $DIR/lint-ctypes-73249-2.rs:26:25
+ |
+LL | pub fn lint_me() -> A<()>;
+ | ^^^^^ not FFI-safe
+ |
+note: the lint level is defined here
+ --> $DIR/lint-ctypes-73249-2.rs:2:9
+ |
+LL | #![deny(improper_ctypes)]
+ | ^^^^^^^^^^^^^^^
+ = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait Baz { }
+
+impl Baz for u32 { }
+
+type Qux = impl Baz;
+
+fn assign() -> Qux { 3 }
+
+#[repr(C)]
+pub struct A {
+ x: Qux,
+}
+
+extern "C" {
+ pub fn lint_me() -> A; //~ ERROR: uses type `impl Baz`
+}
+
+fn main() {}
--- /dev/null
+error: `extern` block uses type `impl Baz`, which is not FFI-safe
+ --> $DIR/lint-ctypes-73249-3.rs:18:25
+ |
+LL | pub fn lint_me() -> A;
+ | ^ not FFI-safe
+ |
+note: the lint level is defined here
+ --> $DIR/lint-ctypes-73249-3.rs:2:9
+ |
+LL | #![deny(improper_ctypes)]
+ | ^^^^^^^^^^^^^^^
+ = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+#![deny(improper_ctypes)]
+
+use std::marker::PhantomData;
+
+trait Foo {
+ type Assoc;
+}
+
+impl Foo for () {
+ type Assoc = PhantomData<()>;
+}
+
+#[repr(transparent)]
+struct Wow<T> where T: Foo<Assoc = PhantomData<T>> {
+ x: <T as Foo>::Assoc,
+ v: u32,
+}
+
+extern "C" {
+ fn test(v: Wow<()>);
+}
+
+fn main() {}
--- /dev/null
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait Baz { }
+
+impl Baz for u32 { }
+
+type Qux = impl Baz;
+
+fn assign() -> Qux { 3 }
+
+#[repr(transparent)]
+pub struct A {
+ x: Qux,
+}
+
+extern "C" {
+ pub fn lint_me() -> A; //~ ERROR: uses type `impl Baz`
+}
+
+fn main() {}
--- /dev/null
+error: `extern` block uses type `impl Baz`, which is not FFI-safe
+ --> $DIR/lint-ctypes-73249-5.rs:18:25
+ |
+LL | pub fn lint_me() -> A;
+ | ^ not FFI-safe
+ |
+note: the lint level is defined here
+ --> $DIR/lint-ctypes-73249-5.rs:2:9
+ |
+LL | #![deny(improper_ctypes)]
+ | ^^^^^^^^^^^^^^^
+ = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+#![deny(improper_ctypes)]
+
+pub trait Foo {
+ type Assoc;
+}
+
+impl Foo for () {
+ type Assoc = u32;
+}
+
+extern "C" {
+ pub fn lint_me(x: Bar<()>);
+}
+
+#[repr(transparent)]
+pub struct Bar<T: Foo> {
+ value: <T as Foo>::Assoc,
+}
+
+fn main() {}
--- /dev/null
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait Baz { }
+
+impl Baz for u32 { }
+
+type Qux = impl Baz;
+
+pub trait Foo {
+ type Assoc;
+}
+
+impl Foo for u32 {
+ type Assoc = Qux;
+}
+
+fn assign() -> Qux { 1 }
+
+extern "C" {
+ pub fn lint_me() -> <u32 as Foo>::Assoc; //~ ERROR: uses type `impl Baz`
+}
+
+fn main() {}
--- /dev/null
+error: `extern` block uses type `impl Baz`, which is not FFI-safe
+ --> $DIR/lint-ctypes-73251-1.rs:21:25
+ |
+LL | pub fn lint_me() -> <u32 as Foo>::Assoc;
+ | ^^^^^^^^^^^^^^^^^^^ not FFI-safe
+ |
+note: the lint level is defined here
+ --> $DIR/lint-ctypes-73251-1.rs:2:9
+ |
+LL | #![deny(improper_ctypes)]
+ | ^^^^^^^^^^^^^^^
+ = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait TraitA {
+ type Assoc;
+}
+
+impl TraitA for u32 {
+ type Assoc = u32;
+}
+
+pub trait TraitB {
+ type Assoc;
+}
+
+impl<T> TraitB for T where T: TraitA {
+ type Assoc = <T as TraitA>::Assoc;
+}
+
+type AliasA = impl TraitA<Assoc = u32>;
+
+type AliasB = impl TraitB<Assoc = AliasA>;
+
+fn use_of_a() -> AliasA { 3 }
+
+fn use_of_b() -> AliasB { 3 }
+
+extern "C" {
+ pub fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `impl TraitA`
+}
+
+fn main() {}
--- /dev/null
+error: `extern` block uses type `impl TraitA`, which is not FFI-safe
+ --> $DIR/lint-ctypes-73251-2.rs:29:25
+ |
+LL | pub fn lint_me() -> <AliasB as TraitB>::Assoc;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+ |
+note: the lint level is defined here
+ --> $DIR/lint-ctypes-73251-2.rs:2:9
+ |
+LL | #![deny(improper_ctypes)]
+ | ^^^^^^^^^^^^^^^
+ = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait Foo {
+ type Assoc;
+}
+
+impl Foo for () {
+ type Assoc = u32;
+}
+
+type Bar = impl Foo<Assoc = u32>;
+
+fn assign() -> Bar {}
+
+extern "C" {
+ pub fn lint_me() -> <Bar as Foo>::Assoc;
+}
+
+fn main() {}
--- /dev/null
+#![feature(rustc_private)]
+
+#![allow(private_in_public)]
+#![deny(improper_ctypes_definitions)]
+
+extern crate libc;
+
+use std::default::Default;
+use std::marker::PhantomData;
+
+trait Mirror { type It: ?Sized; }
+
+impl<T: ?Sized> Mirror for T { type It = Self; }
+
+#[repr(C)]
+pub struct StructWithProjection(*mut <StructWithProjection as Mirror>::It);
+
+#[repr(C)]
+pub struct StructWithProjectionAndLifetime<'a>(
+ &'a mut <StructWithProjectionAndLifetime<'a> as Mirror>::It
+);
+
+pub type I32Pair = (i32, i32);
+
+#[repr(C)]
+pub struct ZeroSize;
+
+pub type RustFn = fn();
+
+pub type RustBadRet = extern fn() -> Box<u32>;
+
+pub type CVoidRet = ();
+
+pub struct Foo;
+
+#[repr(transparent)]
+pub struct TransparentI128(i128);
+
+#[repr(transparent)]
+pub struct TransparentStr(&'static str);
+
+#[repr(transparent)]
+pub struct TransparentBadFn(RustBadRet);
+
+#[repr(transparent)]
+pub struct TransparentInt(u32);
+
+#[repr(transparent)]
+pub struct TransparentRef<'a>(&'a TransparentInt);
+
+#[repr(transparent)]
+pub struct TransparentLifetime<'a>(*const u8, PhantomData<&'a ()>);
+
+#[repr(transparent)]
+pub struct TransparentUnit<U>(f32, PhantomData<U>);
+
+#[repr(transparent)]
+pub struct TransparentCustomZst(i32, ZeroSize);
+
+#[repr(C)]
+pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
+
+pub extern "C" fn ptr_type1(size: *const Foo) { }
+
+pub extern "C" fn ptr_type2(size: *const Foo) { }
+
+pub extern "C" fn slice_type(p: &[u32]) { }
+//~^ ERROR: uses type `[u32]`
+
+pub extern "C" fn str_type(p: &str) { }
+//~^ ERROR: uses type `str`
+
+pub extern "C" fn box_type(p: Box<u32>) { }
+//~^ ERROR uses type `std::boxed::Box<u32>`
+
+pub extern "C" fn char_type(p: char) { }
+//~^ ERROR uses type `char`
+
+pub extern "C" fn i128_type(p: i128) { }
+//~^ ERROR uses type `i128`
+
+pub extern "C" fn u128_type(p: u128) { }
+//~^ ERROR uses type `u128`
+
+pub extern "C" fn tuple_type(p: (i32, i32)) { }
+//~^ ERROR uses type `(i32, i32)`
+
+pub extern "C" fn tuple_type2(p: I32Pair) { }
+//~^ ERROR uses type `(i32, i32)`
+
+pub extern "C" fn zero_size(p: ZeroSize) { }
+//~^ ERROR uses type `ZeroSize`
+
+pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
+//~^ ERROR uses type `ZeroSizeWithPhantomData`
+
+pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
+//~^ ERROR uses type `std::marker::PhantomData<bool>`
+ Default::default()
+}
+
+pub extern "C" fn fn_type(p: RustFn) { }
+//~^ ERROR uses type `fn()`
+
+pub extern "C" fn fn_type2(p: fn()) { }
+//~^ ERROR uses type `fn()`
+
+pub extern "C" fn fn_contained(p: RustBadRet) { }
+//~^ ERROR: uses type `std::boxed::Box<u32>`
+
+pub extern "C" fn transparent_i128(p: TransparentI128) { }
+//~^ ERROR: uses type `i128`
+
+pub extern "C" fn transparent_str(p: TransparentStr) { }
+//~^ ERROR: uses type `str`
+
+pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
+//~^ ERROR: uses type `std::boxed::Box<u32>`
+
+pub extern "C" fn good3(fptr: Option<extern fn()>) { }
+
+pub extern "C" fn good4(aptr: &[u8; 4 as usize]) { }
+
+pub extern "C" fn good5(s: StructWithProjection) { }
+
+pub extern "C" fn good6(s: StructWithProjectionAndLifetime) { }
+
+pub extern "C" fn good7(fptr: extern fn() -> ()) { }
+
+pub extern "C" fn good8(fptr: extern fn() -> !) { }
+
+pub extern "C" fn good9() -> () { }
+
+pub extern "C" fn good10() -> CVoidRet { }
+
+pub extern "C" fn good11(size: isize) { }
+
+pub extern "C" fn good12(size: usize) { }
+
+pub extern "C" fn good13(n: TransparentInt) { }
+
+pub extern "C" fn good14(p: TransparentRef) { }
+
+pub extern "C" fn good15(p: TransparentLifetime) { }
+
+pub extern "C" fn good16(p: TransparentUnit<ZeroSize>) { }
+
+pub extern "C" fn good17(p: TransparentCustomZst) { }
+
+#[allow(improper_ctypes_definitions)]
+pub extern "C" fn good18(_: &String) { }
+
+#[cfg(not(target_arch = "wasm32"))]
+pub extern "C" fn good1(size: *const libc::c_int) { }
+
+#[cfg(not(target_arch = "wasm32"))]
+pub extern "C" fn good2(size: *const libc::c_uint) { }
+
+pub extern "C" fn unused_generic1<T>(size: *const Foo) { }
+
+pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
+//~^ ERROR uses type `std::marker::PhantomData<bool>`
+ Default::default()
+}
+
+pub extern "C" fn used_generic1<T>(x: T) { }
+
+pub extern "C" fn used_generic2<T>(x: T, size: *const Foo) { }
+
+pub extern "C" fn used_generic3<T: Default>() -> T {
+ Default::default()
+}
+
+pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
+//~^ ERROR: uses type `std::vec::Vec<T>`
+
+pub extern "C" fn used_generic5<T>() -> Vec<T> {
+//~^ ERROR: uses type `std::vec::Vec<T>`
+ Default::default()
+}
+
+fn main() {}
--- /dev/null
+error: `extern` fn uses type `[u32]`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:67:33
+ |
+LL | pub extern "C" fn slice_type(p: &[u32]) { }
+ | ^^^^^^ not FFI-safe
+ |
+note: the lint level is defined here
+ --> $DIR/lint-ctypes-fn.rs:4:9
+ |
+LL | #![deny(improper_ctypes_definitions)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: consider using a raw pointer instead
+ = note: slices have no C equivalent
+
+error: `extern` fn uses type `str`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:70:31
+ |
+LL | pub extern "C" fn str_type(p: &str) { }
+ | ^^^^ not FFI-safe
+ |
+ = help: consider using `*const u8` and a length instead
+ = note: string slices have no C equivalent
+
+error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:73:31
+ |
+LL | pub extern "C" fn box_type(p: Box<u32>) { }
+ | ^^^^^^^^ not FFI-safe
+ |
+ = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+ = note: this struct has unspecified layout
+
+error: `extern` fn uses type `char`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:76:32
+ |
+LL | pub extern "C" fn char_type(p: char) { }
+ | ^^^^ not FFI-safe
+ |
+ = help: consider using `u32` or `libc::wchar_t` instead
+ = note: the `char` type has no C equivalent
+
+error: `extern` fn uses type `i128`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:79:32
+ |
+LL | pub extern "C" fn i128_type(p: i128) { }
+ | ^^^^ not FFI-safe
+ |
+ = note: 128-bit integers don't currently have a known stable ABI
+
+error: `extern` fn uses type `u128`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:82:32
+ |
+LL | pub extern "C" fn u128_type(p: u128) { }
+ | ^^^^ not FFI-safe
+ |
+ = note: 128-bit integers don't currently have a known stable ABI
+
+error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:85:33
+ |
+LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
+ | ^^^^^^^^^^ not FFI-safe
+ |
+ = help: consider using a struct instead
+ = note: tuples have unspecified layout
+
+error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:88:34
+ |
+LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
+ | ^^^^^^^ not FFI-safe
+ |
+ = help: consider using a struct instead
+ = note: tuples have unspecified layout
+
+error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:91:32
+ |
+LL | pub extern "C" fn zero_size(p: ZeroSize) { }
+ | ^^^^^^^^ not FFI-safe
+ |
+ = help: consider adding a member to this struct
+ = note: this struct has no fields
+note: the type is defined here
+ --> $DIR/lint-ctypes-fn.rs:26:1
+ |
+LL | pub struct ZeroSize;
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:94:40
+ |
+LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+ |
+ = note: composed only of `PhantomData`
+note: the type is defined here
+ --> $DIR/lint-ctypes-fn.rs:61:1
+ |
+LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `extern` fn uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:97:51
+ |
+LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
+ | ^^^^^^^^^^^^^^^^^ not FFI-safe
+ |
+ = note: composed only of `PhantomData`
+
+error: `extern` fn uses type `fn()`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:102:30
+ |
+LL | pub extern "C" fn fn_type(p: RustFn) { }
+ | ^^^^^^ not FFI-safe
+ |
+ = help: consider using an `extern fn(...) -> ...` function pointer instead
+ = note: this function pointer has Rust-specific calling convention
+
+error: `extern` fn uses type `fn()`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:105:31
+ |
+LL | pub extern "C" fn fn_type2(p: fn()) { }
+ | ^^^^ not FFI-safe
+ |
+ = help: consider using an `extern fn(...) -> ...` function pointer instead
+ = note: this function pointer has Rust-specific calling convention
+
+error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:108:35
+ |
+LL | pub extern "C" fn fn_contained(p: RustBadRet) { }
+ | ^^^^^^^^^^ not FFI-safe
+ |
+ = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+ = note: this struct has unspecified layout
+
+error: `extern` fn uses type `i128`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:111:39
+ |
+LL | pub extern "C" fn transparent_i128(p: TransparentI128) { }
+ | ^^^^^^^^^^^^^^^ not FFI-safe
+ |
+ = note: 128-bit integers don't currently have a known stable ABI
+
+error: `extern` fn uses type `str`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:114:38
+ |
+LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
+ | ^^^^^^^^^^^^^^ not FFI-safe
+ |
+ = help: consider using `*const u8` and a length instead
+ = note: string slices have no C equivalent
+
+error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:117:37
+ |
+LL | pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
+ | ^^^^^^^^^^^^^^^^ not FFI-safe
+ |
+ = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+ = note: this struct has unspecified layout
+
+error: `extern` fn uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:161:43
+ |
+LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
+ | ^^^^^^^^^^^^^^^^^ not FFI-safe
+ |
+ = note: composed only of `PhantomData`
+
+error: `extern` fn uses type `std::vec::Vec<T>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:174:39
+ |
+LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
+ | ^^^^^^ not FFI-safe
+ |
+ = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+ = note: this struct has unspecified layout
+
+error: `extern` fn uses type `std::vec::Vec<T>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:177:41
+ |
+LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
+ | ^^^^^^ not FFI-safe
+ |
+ = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+ = note: this struct has unspecified layout
+
+error: aborting due to 20 previous errors
+
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:17:20
+ --> $DIR/lint-exceeding-bitshifts.rs:18:20
|
LL | const N: i32 = T::N << 42;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow
|
note: the lint level is defined here
- --> $DIR/lint-exceeding-bitshifts.rs:9:9
+ --> $DIR/lint-exceeding-bitshifts.rs:10:9
|
LL | #![warn(arithmetic_overflow, const_err)]
| ^^^^^^^^^^^^^^^^^^^
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:21:13
+ --> $DIR/lint-exceeding-bitshifts.rs:22:13
|
LL | let _ = x << 42;
- | ^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^ attempt to shift left by 42_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:26:15
+ --> $DIR/lint-exceeding-bitshifts.rs:27:15
|
LL | let n = 1u8 << 8;
- | ^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:28:15
+ --> $DIR/lint-exceeding-bitshifts.rs:29:15
|
LL | let n = 1u16 << 16;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:30:15
+ --> $DIR/lint-exceeding-bitshifts.rs:31:15
|
LL | let n = 1u32 << 32;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:32:15
+ --> $DIR/lint-exceeding-bitshifts.rs:33:15
|
LL | let n = 1u64 << 64;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:34:15
+ --> $DIR/lint-exceeding-bitshifts.rs:35:15
|
LL | let n = 1i8 << 8;
- | ^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:36:15
+ --> $DIR/lint-exceeding-bitshifts.rs:37:15
|
LL | let n = 1i16 << 16;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:38:15
+ --> $DIR/lint-exceeding-bitshifts.rs:39:15
|
LL | let n = 1i32 << 32;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:40:15
+ --> $DIR/lint-exceeding-bitshifts.rs:41:15
|
LL | let n = 1i64 << 64;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:43:15
+ --> $DIR/lint-exceeding-bitshifts.rs:44:15
|
LL | let n = 1u8 >> 8;
- | ^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:45:15
+ --> $DIR/lint-exceeding-bitshifts.rs:46:15
|
LL | let n = 1u16 >> 16;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:47:15
+ --> $DIR/lint-exceeding-bitshifts.rs:48:15
|
LL | let n = 1u32 >> 32;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:49:15
+ --> $DIR/lint-exceeding-bitshifts.rs:50:15
|
LL | let n = 1u64 >> 64;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:51:15
+ --> $DIR/lint-exceeding-bitshifts.rs:52:15
|
LL | let n = 1i8 >> 8;
- | ^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:53:15
+ --> $DIR/lint-exceeding-bitshifts.rs:54:15
|
LL | let n = 1i16 >> 16;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:55:15
+ --> $DIR/lint-exceeding-bitshifts.rs:56:15
|
LL | let n = 1i32 >> 32;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:57:15
+ --> $DIR/lint-exceeding-bitshifts.rs:58:15
|
LL | let n = 1i64 >> 64;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:61:15
+ --> $DIR/lint-exceeding-bitshifts.rs:62:15
|
LL | let n = n << 8;
- | ^^^^^^ attempt to shift left with overflow
+ | ^^^^^^ attempt to shift left by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:63:15
+ --> $DIR/lint-exceeding-bitshifts.rs:64:15
|
LL | let n = 1u8 << -8;
- | ^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:68:15
+ --> $DIR/lint-exceeding-bitshifts.rs:69:15
|
LL | let n = 1u8 << (4+4);
- | ^^^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:70:15
+ --> $DIR/lint-exceeding-bitshifts.rs:71:15
|
LL | let n = 1i64 >> [64][0];
- | ^^^^^^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:76:15
+ --> $DIR/lint-exceeding-bitshifts.rs:77:15
|
LL | let n = 1_isize << BITS;
- | ^^^^^^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:77:15
+ --> $DIR/lint-exceeding-bitshifts.rs:78:15
|
LL | let n = 1_usize << BITS;
- | ^^^^^^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
warning: 24 warnings emitted
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:17:20
+ --> $DIR/lint-exceeding-bitshifts.rs:18:20
|
LL | const N: i32 = T::N << 42;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow
|
note: the lint level is defined here
- --> $DIR/lint-exceeding-bitshifts.rs:9:9
+ --> $DIR/lint-exceeding-bitshifts.rs:10:9
|
LL | #![warn(arithmetic_overflow, const_err)]
| ^^^^^^^^^^^^^^^^^^^
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:21:13
+ --> $DIR/lint-exceeding-bitshifts.rs:22:13
|
LL | let _ = x << 42;
- | ^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^ attempt to shift left by 42_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:26:15
+ --> $DIR/lint-exceeding-bitshifts.rs:27:15
|
LL | let n = 1u8 << 8;
- | ^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:28:15
+ --> $DIR/lint-exceeding-bitshifts.rs:29:15
|
LL | let n = 1u16 << 16;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:30:15
+ --> $DIR/lint-exceeding-bitshifts.rs:31:15
|
LL | let n = 1u32 << 32;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:32:15
+ --> $DIR/lint-exceeding-bitshifts.rs:33:15
|
LL | let n = 1u64 << 64;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:34:15
+ --> $DIR/lint-exceeding-bitshifts.rs:35:15
|
LL | let n = 1i8 << 8;
- | ^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:36:15
+ --> $DIR/lint-exceeding-bitshifts.rs:37:15
|
LL | let n = 1i16 << 16;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:38:15
+ --> $DIR/lint-exceeding-bitshifts.rs:39:15
|
LL | let n = 1i32 << 32;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:40:15
+ --> $DIR/lint-exceeding-bitshifts.rs:41:15
|
LL | let n = 1i64 << 64;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:43:15
+ --> $DIR/lint-exceeding-bitshifts.rs:44:15
|
LL | let n = 1u8 >> 8;
- | ^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:45:15
+ --> $DIR/lint-exceeding-bitshifts.rs:46:15
|
LL | let n = 1u16 >> 16;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:47:15
+ --> $DIR/lint-exceeding-bitshifts.rs:48:15
|
LL | let n = 1u32 >> 32;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:49:15
+ --> $DIR/lint-exceeding-bitshifts.rs:50:15
|
LL | let n = 1u64 >> 64;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:51:15
+ --> $DIR/lint-exceeding-bitshifts.rs:52:15
|
LL | let n = 1i8 >> 8;
- | ^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:53:15
+ --> $DIR/lint-exceeding-bitshifts.rs:54:15
|
LL | let n = 1i16 >> 16;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:55:15
+ --> $DIR/lint-exceeding-bitshifts.rs:56:15
|
LL | let n = 1i32 >> 32;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:57:15
+ --> $DIR/lint-exceeding-bitshifts.rs:58:15
|
LL | let n = 1i64 >> 64;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:61:15
+ --> $DIR/lint-exceeding-bitshifts.rs:62:15
|
LL | let n = n << 8;
- | ^^^^^^ attempt to shift left with overflow
+ | ^^^^^^ attempt to shift left by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:63:15
+ --> $DIR/lint-exceeding-bitshifts.rs:64:15
|
LL | let n = 1u8 << -8;
- | ^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:68:15
+ --> $DIR/lint-exceeding-bitshifts.rs:69:15
|
LL | let n = 1u8 << (4+4);
- | ^^^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:70:15
+ --> $DIR/lint-exceeding-bitshifts.rs:71:15
|
LL | let n = 1i64 >> [64][0];
- | ^^^^^^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:76:15
+ --> $DIR/lint-exceeding-bitshifts.rs:77:15
|
LL | let n = 1_isize << BITS;
- | ^^^^^^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:77:15
+ --> $DIR/lint-exceeding-bitshifts.rs:78:15
|
LL | let n = 1_usize << BITS;
- | ^^^^^^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
warning: 24 warnings emitted
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:17:20
+ --> $DIR/lint-exceeding-bitshifts.rs:18:20
|
LL | const N: i32 = T::N << 42;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow
|
note: the lint level is defined here
- --> $DIR/lint-exceeding-bitshifts.rs:9:9
+ --> $DIR/lint-exceeding-bitshifts.rs:10:9
|
LL | #![warn(arithmetic_overflow, const_err)]
| ^^^^^^^^^^^^^^^^^^^
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:21:13
+ --> $DIR/lint-exceeding-bitshifts.rs:22:13
|
LL | let _ = x << 42;
- | ^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^ attempt to shift left by 42_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:26:15
+ --> $DIR/lint-exceeding-bitshifts.rs:27:15
|
LL | let n = 1u8 << 8;
- | ^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:28:15
+ --> $DIR/lint-exceeding-bitshifts.rs:29:15
|
LL | let n = 1u16 << 16;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:30:15
+ --> $DIR/lint-exceeding-bitshifts.rs:31:15
|
LL | let n = 1u32 << 32;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:32:15
+ --> $DIR/lint-exceeding-bitshifts.rs:33:15
|
LL | let n = 1u64 << 64;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:34:15
+ --> $DIR/lint-exceeding-bitshifts.rs:35:15
|
LL | let n = 1i8 << 8;
- | ^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:36:15
+ --> $DIR/lint-exceeding-bitshifts.rs:37:15
|
LL | let n = 1i16 << 16;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:38:15
+ --> $DIR/lint-exceeding-bitshifts.rs:39:15
|
LL | let n = 1i32 << 32;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:40:15
+ --> $DIR/lint-exceeding-bitshifts.rs:41:15
|
LL | let n = 1i64 << 64;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:43:15
+ --> $DIR/lint-exceeding-bitshifts.rs:44:15
|
LL | let n = 1u8 >> 8;
- | ^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:45:15
+ --> $DIR/lint-exceeding-bitshifts.rs:46:15
|
LL | let n = 1u16 >> 16;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:47:15
+ --> $DIR/lint-exceeding-bitshifts.rs:48:15
|
LL | let n = 1u32 >> 32;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:49:15
+ --> $DIR/lint-exceeding-bitshifts.rs:50:15
|
LL | let n = 1u64 >> 64;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:51:15
+ --> $DIR/lint-exceeding-bitshifts.rs:52:15
|
LL | let n = 1i8 >> 8;
- | ^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:53:15
+ --> $DIR/lint-exceeding-bitshifts.rs:54:15
|
LL | let n = 1i16 >> 16;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:55:15
+ --> $DIR/lint-exceeding-bitshifts.rs:56:15
|
LL | let n = 1i32 >> 32;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:57:15
+ --> $DIR/lint-exceeding-bitshifts.rs:58:15
|
LL | let n = 1i64 >> 64;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:61:15
+ --> $DIR/lint-exceeding-bitshifts.rs:62:15
|
LL | let n = n << 8;
- | ^^^^^^ attempt to shift left with overflow
+ | ^^^^^^ attempt to shift left by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:63:15
+ --> $DIR/lint-exceeding-bitshifts.rs:64:15
|
LL | let n = 1u8 << -8;
- | ^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:68:15
+ --> $DIR/lint-exceeding-bitshifts.rs:69:15
|
LL | let n = 1u8 << (4+4);
- | ^^^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:70:15
+ --> $DIR/lint-exceeding-bitshifts.rs:71:15
|
LL | let n = 1i64 >> [64][0];
- | ^^^^^^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:76:15
+ --> $DIR/lint-exceeding-bitshifts.rs:77:15
|
LL | let n = 1_isize << BITS;
- | ^^^^^^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
warning: this arithmetic operation will overflow
- --> $DIR/lint-exceeding-bitshifts.rs:77:15
+ --> $DIR/lint-exceeding-bitshifts.rs:78:15
|
LL | let n = 1_usize << BITS;
- | ^^^^^^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
warning: 24 warnings emitted
//[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O
// build-pass
// ignore-pass (test emits codegen-time warnings and verifies that they are not errors)
+// normalize-stderr-test "shift left by (64|32)_usize which" -> "shift left by %BITS% which"
#![crate_type="lib"]
#![warn(arithmetic_overflow, const_err)]
#![deny(confusable_idents)]
#![allow(uncommon_codepoints, non_upper_case_globals)]
-const s: usize = 42; //~ ERROR identifier pair considered confusable
+const s: usize = 42;
fn main() {
- let s = "rust";
+ let s = "rust"; //~ ERROR identifier pair considered confusable
+ not_affected();
+}
+
+fn not_affected() {
+ let s1 = 1;
+ let sl = 'l';
}
-error: identifier pair considered confusable between `s` and `s`
- --> $DIR/lint-confusable-idents.rs:5:7
+error: identifier pair considered confusable between `s` and `s`
+ --> $DIR/lint-confusable-idents.rs:8:9
|
LL | const s: usize = 42;
- | ^^
+ | -- this is where the previous identifier occurred
...
LL | let s = "rust";
- | - this is where the previous identifier occurred
+ | ^
|
note: the lint level is defined here
--> $DIR/lint-confusable-idents.rs:2:9
--- /dev/null
+// check-pass
+#![feature(non_ascii_idents)]
+#![deny(mixed_script_confusables)]
+
+struct ΑctuallyNotLatin;
+
+fn main() {
+ let λ = 42; // this usage of Greek confirms that Greek is used intentionally.
+}
+
+mod роре {
+ const エ: &'static str = "アイウ";
+
+ // this usage of Katakana confirms that Katakana is used intentionally.
+ fn ニャン() {
+ let д: usize = 100; // this usage of Cyrillic confirms that Cyrillic is used intentionally.
+
+ println!("meow!");
+ }
+}
--- /dev/null
+#![feature(non_ascii_idents)]
+#![deny(mixed_script_confusables)]
+
+struct ΑctuallyNotLatin;
+//~^ ERROR The usage of Script Group `Greek` in this crate consists solely of
+
+fn main() {
+ let v = ΑctuallyNotLatin;
+}
+
+mod роре {
+//~^ ERROR The usage of Script Group `Cyrillic` in this crate consists solely of
+ const エ: &'static str = "アイウ";
+ //~^ ERROR The usage of Script Group `Japanese, Katakana` in this crate consists solely of
+}
--- /dev/null
+error: The usage of Script Group `Greek` in this crate consists solely of mixed script confusables
+ --> $DIR/lint-mixed-script-confusables.rs:4:8
+ |
+LL | struct ΑctuallyNotLatin;
+ | ^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/lint-mixed-script-confusables.rs:2:9
+ |
+LL | #![deny(mixed_script_confusables)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: The usage includes 'Α' (U+0391).
+ = note: Please recheck to make sure their usages are indeed what you want.
+
+error: The usage of Script Group `Cyrillic` in this crate consists solely of mixed script confusables
+ --> $DIR/lint-mixed-script-confusables.rs:11:5
+ |
+LL | mod роре {
+ | ^^^^
+ |
+ = note: The usage includes 'е' (U+0435), 'о' (U+043E), 'р' (U+0440).
+ = note: Please recheck to make sure their usages are indeed what you want.
+
+error: The usage of Script Group `Japanese, Katakana` in this crate consists solely of mixed script confusables
+ --> $DIR/lint-mixed-script-confusables.rs:13:11
+ |
+LL | const エ: &'static str = "アイウ";
+ | ^^
+ |
+ = note: The usage includes 'エ' (U+30A8).
+ = note: Please recheck to make sure their usages are indeed what you want.
+
+error: aborting due to 3 previous errors
+
fn main() {
let naïveté = 2; //~ ERROR identifier contains non-ASCII characters
- println!("{}", naïveté); //~ ERROR identifier contains non-ASCII characters
+
+ // using the same identifier the second time won't trigger the lint.
+ println!("{}", naïveté);
}
LL | let naïveté = 2;
| ^^^^^^^
-error: identifier contains non-ASCII characters
- --> $DIR/lint-non-ascii-idents.rs:10:20
- |
-LL | println!("{}", naïveté);
- | ^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
fn main() {
let ㇻㇲㇳ = "rust"; //~ ERROR identifier contains uncommon Unicode codepoints
- println!("{}", ㇻㇲㇳ); //~ ERROR identifier contains uncommon Unicode codepoints
+
+ // using the same identifier the second time won't trigger the lint.
+ println!("{}", ㇻㇲㇳ);
}
LL | let ㇻㇲㇳ = "rust";
| ^^^^^^
-error: identifier contains uncommon Unicode codepoints
- --> $DIR/lint-uncommon-codepoints.rs:10:20
- |
-LL | println!("{}", ㇻㇲㇳ);
- | ^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
--- /dev/null
+// Test that we give a note when the old LUB/GLB algorithm would have
+// succeeded but the new code (which requires equality) gives an
+// error. However, now that we handle subtyping correctly, we no
+// longer get an error, because we recognize these two types as
+// equivalent!
+//
+// check-pass
+
+fn foo(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) {
+ // The two types above are actually equivalent. With the older
+ // leak check, though, we didn't consider them as equivalent, and
+ // hence we gave errors. But now we've fixed that.
+ let z = match 22 {
+ 0 => x,
+ _ => y,
+ };
+}
+
+fn foo_cast(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) {
+ let z = match 22 {
+ // No error with an explicit cast:
+ 0 => x as for<'a> fn(&'a u8, &'a u8),
+ _ => y,
+ };
+}
+
+fn main() {}
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/old-lub-glb-hr-noteq1.rs:11:14
+ |
+LL | _ => y,
+ | ^
+
+error: aborting due to previous error
+
--- /dev/null
+// Test taking the LUB of two function types that are not equatable but where one is more
+// general than the other. Test the case where the more general type (`x`) is the first
+// match arm specifically.
+
+fn foo(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+ // The two types above are not equivalent. With the older LUB/GLB
+ // algorithm, this may have worked (I don't remember), but now it
+ // doesn't because we require equality.
+ let z = match 22 {
+ 0 => x,
+ _ => y, //~ ERROR `match` arms have incompatible types
+ };
+}
+
+fn foo_cast(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+ // But we can *upcast* explicitly the type of `x` and figure
+ // things out:
+ let z = match 22 {
+ 0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8,
+ _ => y,
+ };
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: `match` arms have incompatible types
+ --> $DIR/old-lub-glb-hr-noteq1.rs:11:14
+ |
+LL | let z = match 22 {
+ | _____________-
+LL | | 0 => x,
+ | | - this is found to be of type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
+LL | | _ => y,
+ | | ^ one type is more general than the other
+LL | | };
+ | |_____- `match` arms have incompatible types
+ |
+ = note: expected fn pointer `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
+ found fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// Test taking the LUB of two function types that are not equatable but where
+// one is more general than the other. Test the case where the more general type
+// (`x`) is the second match arm specifically.
+//
+// FIXME(#73154) Skip for compare-mode because the pure NLL checker accepts this
+// test. (Note that it still errors in old-lub-glb-hr-noteq1.rs). What happens
+// is that, due to the ordering of the match arms, we pick the correct "more
+// general" fn type, and we ignore the errors from the non-NLL type checker that
+// requires equality. The NLL type checker only requires a subtyping
+// relationship, and that holds.
+//
+// ignore-compare-mode-nll
+
+fn foo(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+ // The two types above are not equivalent. With the older LUB/GLB
+ // algorithm, this may have worked (I don't remember), but now it
+ // doesn't because we require equality.
+ let z = match 22 {
+ 0 => y,
+ _ => x, //~ ERROR `match` arms have incompatible types
+ };
+}
+
+fn foo_cast(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+ // But we can *upcast* explicitly the type of `x` and figure
+ // things out:
+ let z = match 22 {
+ 0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8,
+ _ => y,
+ };
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: `match` arms have incompatible types
+ --> $DIR/old-lub-glb-hr-noteq2.rs:20:14
+ |
+LL | let z = match 22 {
+ | _____________-
+LL | | 0 => y,
+ | | - this is found to be of type `for<'a> fn(&'a u8, &'a u8) -> &'a u8`
+LL | | _ => x,
+ | | ^ one type is more general than the other
+LL | | };
+ | |_____- `match` arms have incompatible types
+ |
+ = note: expected fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8`
+ found fn pointer `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// Test that we give a note when the old LUB/GLB algorithm would have
-// succeeded but the new code (which requires equality) gives an
-// error. However, now that we handle subtyping correctly, we no
-// longer get an error, because we recognize these two types as
-// equivalent!
-//
-// Whoops -- now that we reinstituted the leak-check, we get an error
-// again.
-
-fn foo(
- x: fn(&u8, &u8),
- y: for<'a> fn(&'a u8, &'a u8),
-) {
- let z = match 22 {
- 0 => x,
- _ => y, //~ ERROR `match` arms have incompatible types
- };
-}
-
-fn bar(
- x: fn(&u8, &u8),
- y: for<'a> fn(&'a u8, &'a u8),
-) {
- let z = match 22 {
- // No error with an explicit cast:
- 0 => x as for<'a> fn(&'a u8, &'a u8),
- _ => y,
- };
-}
-
-fn main() {
-}
+++ /dev/null
-error[E0308]: `match` arms have incompatible types
- --> $DIR/old-lub-glb-hr.rs:16:14
- |
-LL | let z = match 22 {
- | _____________-
-LL | | 0 => x,
- | | - this is found to be of type `for<'r, 's> fn(&'r u8, &'s u8)`
-LL | | _ => y,
- | | ^ expected bound lifetime parameter, found concrete lifetime
-LL | | };
- | |_____- `match` arms have incompatible types
- |
- = note: expected type `for<'r, 's> fn(&'r u8, &'s u8)`
- found fn pointer `for<'a> fn(&'a u8, &'a u8)`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/old-lub-glb-object.rs:10:14
+ |
+LL | _ => y,
+ | ^
+
+error: higher-ranked subtype error
+ --> $DIR/old-lub-glb-object.rs:10:14
+ |
+LL | _ => y,
+ | ^
+
+error: aborting due to 2 previous errors
+
// Test that we give a note when the old LUB/GLB algorithm would have
// succeeded but the new code (which is stricter) gives an error.
-trait Foo<T, U> { }
+trait Foo<T, U> {}
-fn foo(
- x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>,
- y: &dyn for<'a> Foo<&'a u8, &'a u8>,
-) {
+fn foo(x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, y: &dyn for<'a> Foo<&'a u8, &'a u8>) {
let z = match 22 {
+ //~^ ERROR mismatched types
0 => x,
- _ => y, //~ ERROR `match` arms have incompatible types
+ _ => y,
};
}
-fn bar(
- x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>,
- y: &dyn for<'a> Foo<&'a u8, &'a u8>,
-) {
+fn bar(x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, y: &dyn for<'a> Foo<&'a u8, &'a u8>) {
// Accepted with explicit case:
let z = match 22 {
0 => x as &dyn for<'a> Foo<&'a u8, &'a u8>,
};
}
-fn main() {
-}
+fn main() {}
-error[E0308]: `match` arms have incompatible types
- --> $DIR/old-lub-glb-object.rs:12:14
+error[E0308]: mismatched types
+ --> $DIR/old-lub-glb-object.rs:7:13
|
LL | let z = match 22 {
- | _____________-
+ | _____________^
+LL | |
LL | | 0 => x,
- | | - this is found to be of type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
LL | | _ => y,
- | | ^ expected bound lifetime parameter 'a, found concrete lifetime
LL | | };
- | |_____- `match` arms have incompatible types
+ | |_____^ one type is more general than the other
|
- = note: expected type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
- found reference `&dyn for<'a> Foo<&'a u8, &'a u8>`
+ = note: expected trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
+ found trait object `dyn for<'a> Foo<&'a u8, &'a u8>`
error: aborting due to previous error
--- /dev/null
+#![feature(core_intrinsics, rustc_attrs)]
+
+use std::intrinsics::rustc_peek;
+
+#[rustc_mir(rustc_peek_liveness, stop_after_dataflow)]
+fn foo() {
+ {
+ let mut x: (i32, i32) = (42, 0);
+
+ // Assignment to a projection does not cause `x` to become live
+ unsafe { rustc_peek(x); } //~ ERROR bit not set
+ x.1 = 42;
+
+ x = (0, 42);
+
+ // ...but a read from a projection does.
+ unsafe { rustc_peek(x); }
+ println!("{}", x.1);
+ }
+
+ {
+ let mut x = 42;
+
+ // Derefs are treated like a read of a local even if they are on the LHS of an assignment.
+ let p = &mut x;
+ unsafe { rustc_peek(&p); }
+ *p = 24;
+ unsafe { rustc_peek(&p); } //~ ERROR bit not set
+ }
+}
+
+fn main() {}
--- /dev/null
+error: rustc_peek: bit not set
+ --> $DIR/liveness-projection.rs:11:18
+ |
+LL | unsafe { rustc_peek(x); }
+ | ^^^^^^^^^^^^^
+
+error: rustc_peek: bit not set
+ --> $DIR/liveness-projection.rs:28:18
+ |
+LL | unsafe { rustc_peek(&p); }
+ | ^^^^^^^^^^^^^^
+
+error: stop_after_dataflow ended compilation
+
+error: aborting due to 3 previous errors
+
// run-pass
+#[allow(improper_ctypes_definitions)]
pub extern "C" fn tuple2() -> (u16, u8) {
(1, 2)
}
+#[allow(improper_ctypes_definitions)]
pub extern "C" fn tuple3() -> (u8, u8, u8) {
(1, 2, 3)
}
Two::two()
}
+#[allow(improper_ctypes_definitions)]
extern fn simple_extern(x: u32, y: (u32, u32)) -> u32 {
x + y.0 * y.1
}
fn oob_error_for_slices() {
let a: *const [_] = &[1, 2, 3];
unsafe {
- let _b = (*a)[3]; //~ ERROR this operation will panic at runtime [unconditional_panic]
+ let _b = (*a)[3];
}
}
--> $DIR/mir_detects_invalid_ops.rs:11:14
|
LL | let _z = 1 / y;
- | ^^^^^ attempt to divide by zero
+ | ^^^^^ attempt to divide 1_i32 by zero
|
= note: `#[deny(unconditional_panic)]` on by default
--> $DIR/mir_detects_invalid_ops.rs:16:14
|
LL | let _z = 1 % y;
- | ^^^^^ attempt to calculate the remainder with a divisor of zero
+ | ^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero
-error: this operation will panic at runtime
- --> $DIR/mir_detects_invalid_ops.rs:22:18
- |
-LL | let _b = (*a)[3];
- | ^^^^^^^ index out of bounds: the len is 3 but the index is 3
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
--> $DIR/cast-rfc0401.rs:29:13
|
LL | let _ = v as &u8;
- | ^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0605]: non-primitive cast: `*const u8` as `E`
--> $DIR/cast-rfc0401.rs:30:13
|
LL | let _ = v as E;
- | ^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0605]: non-primitive cast: `*const u8` as `fn()`
--> $DIR/cast-rfc0401.rs:31:13
|
LL | let _ = v as fn();
- | ^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^ invalid cast
error[E0605]: non-primitive cast: `*const u8` as `(u32,)`
--> $DIR/cast-rfc0401.rs:32:13
|
LL | let _ = v as (u32,);
- | ^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0605]: non-primitive cast: `std::option::Option<&*const u8>` as `*const u8`
--> $DIR/cast-rfc0401.rs:33:13
|
LL | let _ = Some(&v) as *const u8;
- | ^^^^^^^^^^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0606]: casting `*const u8` as `f32` is invalid
--> $DIR/cast-rfc0401.rs:35:13
--> $DIR/cast-rfc0401.rs:41:13
|
LL | let _ = 0x61u32 as char;
- | ^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^ invalid cast
error[E0606]: casting `bool` as `f32` is invalid
--> $DIR/cast-rfc0401.rs:43:13
--- /dev/null
+error[E0631]: type mismatch in closure arguments
+ --> $DIR/closure-arg-type-mismatch.rs:3:14
+ |
+LL | a.iter().map(|_: (u32, u32)| 45);
+ | ^^^ ------------------ found signature of `fn((u32, u32)) -> _`
+ | |
+ | expected signature of `fn(&(u32, u32)) -> _`
+
+error[E0631]: type mismatch in closure arguments
+ --> $DIR/closure-arg-type-mismatch.rs:4:14
+ |
+LL | a.iter().map(|_: &(u16, u16)| 45);
+ | ^^^ ------------------- found signature of `for<'r> fn(&'r (u16, u16)) -> _`
+ | |
+ | expected signature of `fn(&(u32, u32)) -> _`
+
+error[E0631]: type mismatch in closure arguments
+ --> $DIR/closure-arg-type-mismatch.rs:5:14
+ |
+LL | a.iter().map(|_: (u16, u16)| 45);
+ | ^^^ ------------------ found signature of `fn((u16, u16)) -> _`
+ | |
+ | expected signature of `fn(&(u32, u32)) -> _`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0631`.
fn baz<F: Fn(*mut &u32)>(_: F) {}
fn _test<'a>(f: fn(*mut &'a u32)) {
- baz(f); //~ ERROR type mismatch
- //~| ERROR type mismatch
+ baz(f);
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
}
| |
| expected signature of `fn(&(u32, u32)) -> _`
-error[E0631]: type mismatch in function arguments
- --> $DIR/closure-arg-type-mismatch.rs:10:9
+error[E0308]: mismatched types
+ --> $DIR/closure-arg-type-mismatch.rs:10:5
|
-LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
- | ------------- required by this bound in `baz`
-LL | fn _test<'a>(f: fn(*mut &'a u32)) {
LL | baz(f);
- | ^
- | |
- | expected signature of `for<'r> fn(*mut &'r u32) -> _`
- | found signature of `fn(*mut &'a u32) -> _`
+ | ^^^ one type is more general than the other
+ |
+ = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>`
+ found type `std::ops::Fn<(*mut &'a u32,)>`
+
+error[E0308]: mismatched types
+ --> $DIR/closure-arg-type-mismatch.rs:10:5
+ |
+LL | baz(f);
+ | ^^^ one type is more general than the other
+ |
+ = note: expected type `std::ops::FnOnce<(*mut &u32,)>`
+ found type `std::ops::FnOnce<(*mut &'a u32,)>`
-error[E0271]: type mismatch resolving `for<'r> <fn(*mut &'a u32) as std::ops::FnOnce<(*mut &'r u32,)>>::Output == ()`
+error[E0308]: mismatched types
--> $DIR/closure-arg-type-mismatch.rs:10:5
|
-LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
- | ------------- required by this bound in `baz`
-LL | fn _test<'a>(f: fn(*mut &'a u32)) {
LL | baz(f);
- | ^^^ expected bound lifetime parameter, found concrete lifetime
+ | ^^^ one type is more general than the other
+ |
+ = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>`
+ found type `std::ops::Fn<(*mut &'a u32,)>`
+
+error[E0308]: mismatched types
+ --> $DIR/closure-arg-type-mismatch.rs:10:5
+ |
+LL | baz(f);
+ | ^^^ one type is more general than the other
+ |
+ = note: expected type `std::ops::FnOnce<(*mut &u32,)>`
+ found type `std::ops::FnOnce<(*mut &'a u32,)>`
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+Some errors have detailed explanations: E0308, E0631.
+For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/closure-mismatch.rs:8:5
+ |
+LL | baz(|_| ());
+ | ^^^^^^^^^^^
+
+error: higher-ranked subtype error
+ --> $DIR/closure-mismatch.rs:8:5
+ |
+LL | baz(|_| ());
+ | ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
fn baz<T: Foo>(_: T) {}
fn main() {
- baz(|_| ()); //~ ERROR type mismatch
- //~^ ERROR type mismatch
+ baz(|_| ()); //~ ERROR mismatched types
}
-error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.rs:8:9: 8:15] as std::ops::FnOnce<(&'r (),)>>::Output == ()`
+error[E0308]: mismatched types
--> $DIR/closure-mismatch.rs:8:5
|
-LL | fn baz<T: Foo>(_: T) {}
- | --- required by this bound in `baz`
-...
LL | baz(|_| ());
- | ^^^ expected bound lifetime parameter, found concrete lifetime
+ | ^^^ one type is more general than the other
|
- = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]`
+ = note: expected type `for<'r> std::ops::Fn<(&'r (),)>`
+ found type `std::ops::Fn<(&(),)>`
-error[E0631]: type mismatch in closure arguments
- --> $DIR/closure-mismatch.rs:8:5
- |
-LL | fn baz<T: Foo>(_: T) {}
- | --- required by this bound in `baz`
-...
-LL | baz(|_| ());
- | ^^^ ------ found signature of `fn(_) -> _`
- | |
- | expected signature of `for<'r> fn(&'r ()) -> _`
- |
- = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
--> $DIR/issue-26480.rs:22:19
|
LL | ($x:expr) => ($x as ())
- | ^^^^^^^^
+ | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
...
LL | cast!(2);
| --------- in this macro invocation
|
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
--- /dev/null
+// Regression test for issue #46099
+// Tests that we don't emit spurious
+// 'value moved in previous iteration of loop' message
+
+macro_rules! test {
+ ($v:expr) => {{
+ drop(&$v);
+ $v
+ }}
+}
+
+fn main() {
+ let b = Box::new(true);
+ test!({b}); //~ ERROR use of moved value
+}
--- /dev/null
+error[E0382]: use of moved value: `b`
+ --> $DIR/issue-46099-move-in-macro.rs:14:12
+ |
+LL | let b = Box::new(true);
+ | - move occurs because `b` has type `std::boxed::Box<bool>`, which does not implement the `Copy` trait
+LL | test!({b});
+ | ^
+ | |
+ | value moved here
+ | value used here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
| - move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
...
LL | (_, 2) if take(x) => (),
- | ^ value moved here, in previous iteration of loop
+ | ^
+ | |
+ | value moved here
+ | value used here after move
error: aborting due to previous error
| ^^^^ value used here after partial move
|
= note: move occurs because value has type `std::boxed::Box<List>`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `node.next.0`
+ |
+LL | Some(ref right) => consume(right),
+ | ^^^
error: aborting due to previous error
|
LL | use m2::S;
|
-LL | use namespace_mix::xm2::S;
+LL | use xm2::S;
|
error[E0423]: expected value, found type alias `xm1::S`
|
LL | use m2::S;
|
-LL | use namespace_mix::xm2::S;
+LL | use xm2::S;
|
error[E0423]: expected value, found struct variant `m7::V`
|
LL | use m8::V;
|
-LL | use namespace_mix::xm8::V;
+LL | use xm8::V;
|
error[E0423]: expected value, found struct variant `xm7::V`
|
LL | use m8::V;
|
-LL | use namespace_mix::xm8::V;
+LL | use xm8::V;
|
error[E0277]: the trait bound `c::Item: Impossible` is not satisfied
--- /dev/null
+#![feature(never_type, specialization)]
+#![allow(incomplete_features)]
+
+use std::iter::{self, Empty};
+
+trait Trait {
+ type Out: Iterator<Item = u32>;
+
+ fn f(&self) -> Option<Self::Out>;
+}
+
+impl<T> Trait for T {
+ default type Out = !; //~ ERROR: `!` is not an iterator
+
+ default fn f(&self) -> Option<Self::Out> {
+ None
+ }
+}
+
+struct X;
+
+impl Trait for X {
+ type Out = Empty<u32>;
+
+ fn f(&self) -> Option<Self::Out> {
+ Some(iter::empty())
+ }
+}
+
+fn f<T: Trait>(a: T) {
+ if let Some(iter) = a.f() {
+ println!("Some");
+ for x in iter {
+ println!("x = {}", x);
+ }
+ }
+}
+
+pub fn main() {
+ f(10);
+}
--- /dev/null
+error[E0277]: `!` is not an iterator
+ --> $DIR/issue-51506.rs:13:5
+ |
+LL | type Out: Iterator<Item = u32>;
+ | ------------------------------- required by `Trait::Out`
+...
+LL | default type Out = !;
+ | ^^^^^^^^^^^^^^^^^^^^^ `!` is not an iterator
+ |
+ = help: the trait `std::iter::Iterator` is not implemented for `!`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
| ^^^^^ value moved here, in previous iteration of loop
|
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `maybe.0`
+ |
+LL | if let Some(ref thing) = maybe {
+ | ^^^
error: aborting due to previous error
--- /dev/null
+// run-rustfix
+
+#[derive(Debug)]
+struct Foo {
+ x: isize
+}
+
+impl From<Foo> for isize {
+ fn from(val: Foo) -> isize {
+ val.x
+ }
+}
+
+fn main() {
+ println!("{}", isize::from(Foo { x: 1 })); //~ non-primitive cast: `Foo` as `isize` [E0605]
+}
+// run-rustfix
+
#[derive(Debug)]
struct Foo {
x: isize
}
+impl From<Foo> for isize {
+ fn from(val: Foo) -> isize {
+ val.x
+ }
+}
+
fn main() {
println!("{}", Foo { x: 1 } as isize); //~ non-primitive cast: `Foo` as `isize` [E0605]
}
error[E0605]: non-primitive cast: `Foo` as `isize`
- --> $DIR/nonscalar-cast.rs:7:20
+ --> $DIR/nonscalar-cast.rs:15:20
|
LL | println!("{}", Foo { x: 1 } as isize);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(Foo { x: 1 })`
|
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to previous error
--> $DIR/overflowing-lsh-1.rs:7:14
|
LL | let _x = 1_i32 << 32;
- | ^^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
|
note: the lint level is defined here
--> $DIR/overflowing-lsh-1.rs:4:9
--> $DIR/overflowing-lsh-2.rs:7:14
|
LL | let _x = 1 << -1;
- | ^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^ attempt to shift left by -1_i32 which would overflow
|
note: the lint level is defined here
--> $DIR/overflowing-lsh-2.rs:4:9
--> $DIR/overflowing-lsh-3.rs:7:14
|
LL | let _x = 1_u64 << 64;
- | ^^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
|
note: the lint level is defined here
--> $DIR/overflowing-lsh-3.rs:4:9
--> $DIR/overflowing-lsh-4.rs:11:13
|
LL | let x = 1_i8 << 17;
- | ^^^^^^^^^^ attempt to shift left with overflow
+ | ^^^^^^^^^^ attempt to shift left by 17_i32 which would overflow
|
note: the lint level is defined here
--> $DIR/overflowing-lsh-4.rs:7:9
--> $DIR/overflowing-rsh-1.rs:7:14
|
LL | let _x = -1_i32 >> 32;
- | ^^^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
|
note: the lint level is defined here
--> $DIR/overflowing-rsh-1.rs:4:9
--> $DIR/overflowing-rsh-2.rs:7:14
|
LL | let _x = -1_i32 >> -1;
- | ^^^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^^^ attempt to shift right by -1_i32 which would overflow
|
note: the lint level is defined here
--> $DIR/overflowing-rsh-2.rs:4:9
--> $DIR/overflowing-rsh-3.rs:7:14
|
LL | let _x = -1_i64 >> 64;
- | ^^^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
|
note: the lint level is defined here
--> $DIR/overflowing-rsh-3.rs:4:9
--> $DIR/overflowing-rsh-4.rs:11:13
|
LL | let x = 2_i8 >> 17;
- | ^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^ attempt to shift right by 17_i32 which would overflow
|
note: the lint level is defined here
--> $DIR/overflowing-rsh-4.rs:7:9
--> $DIR/overflowing-rsh-5.rs:7:14
|
LL | let _n = 1i64 >> [64][0];
- | ^^^^^^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
|
note: the lint level is defined here
--> $DIR/overflowing-rsh-5.rs:4:9
--> $DIR/overflowing-rsh-6.rs:7:14
|
LL | let _n = 1i64 >> [64][0];
- | ^^^^^^^^^^^^^^^ attempt to shift right with overflow
+ | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
|
note: the lint level is defined here
--> $DIR/overflowing-rsh-6.rs:4:9
--- /dev/null
+#[allow(unused_must_use)]
+fn main() {
+ let x_usize: usize = 1;
+ let x_u128: u128 = 2;
+ let x_u64: u64 = 3;
+ let x_u32: u32 = 4;
+ let x_u16: u16 = 5;
+ let x_u8: u8 = 6;
+
+ x_usize > -1_isize;
+ //~^ ERROR mismatched types
+ x_u128 > -1_isize;
+ //~^ ERROR mismatched types
+ x_u64 > -1_isize;
+ //~^ ERROR mismatched types
+ x_u32 > -1_isize;
+ //~^ ERROR mismatched types
+ x_u16 > -1_isize;
+ //~^ ERROR mismatched types
+ x_u8 > -1_isize;
+ //~^ ERROR mismatched types
+
+ x_usize > -1_i128;
+ //~^ ERROR mismatched types
+ x_u128 > -1_i128;
+ //~^ ERROR mismatched types
+ x_u64 > -1_i128;
+ //~^ ERROR mismatched types
+ x_u32 > -1_i128;
+ //~^ ERROR mismatched types
+ x_u16 > -1_i128;
+ //~^ ERROR mismatched types
+ x_u8 > -1_i128;
+ //~^ ERROR mismatched types
+
+ x_usize > -1_i64;
+ //~^ ERROR mismatched types
+ x_u128 > -1_i64;
+ //~^ ERROR mismatched types
+ x_u64 > -1_i64;
+ //~^ ERROR mismatched types
+ x_u32 > -1_i64;
+ //~^ ERROR mismatched types
+ x_u16 > -1_i64;
+ //~^ ERROR mismatched types
+ x_u8 > -1_i64;
+ //~^ ERROR mismatched types
+
+ x_usize > -1_i32;
+ //~^ ERROR mismatched types
+ x_u128 > -1_i32;
+ //~^ ERROR mismatched types
+ x_u64 > -1_i32;
+ //~^ ERROR mismatched types
+ x_u32 > -1_i32;
+ //~^ ERROR mismatched types
+ x_u16 > -1_i32;
+ //~^ ERROR mismatched types
+ x_u8 > -1_i32;
+ //~^ ERROR mismatched types
+
+ x_usize > -1_i16;
+ //~^ ERROR mismatched types
+ x_u128 > -1_i16;
+ //~^ ERROR mismatched types
+ x_u64 > -1_i16;
+ //~^ ERROR mismatched types
+ x_u32 > -1_i16;
+ //~^ ERROR mismatched types
+ x_u16 > -1_i16;
+ //~^ ERROR mismatched types
+ x_u8 > -1_i16;
+ //~^ ERROR mismatched types
+
+ x_usize > -1_i8;
+ //~^ ERROR mismatched types
+ x_u128 > -1_i8;
+ //~^ ERROR mismatched types
+ x_u64 > -1_i8;
+ //~^ ERROR mismatched types
+ x_u32 > -1_i8;
+ //~^ ERROR mismatched types
+ x_u16 > -1_i8;
+ //~^ ERROR mismatched types
+ x_u8 > -1_i8;
+ //~^ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:10:15
+ |
+LL | x_usize > -1_isize;
+ | ^^^^^^^^ expected `usize`, found `isize`
+ |
+ = note: `-1_isize` cannot fit into type `usize`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:12:14
+ |
+LL | x_u128 > -1_isize;
+ | ^^^^^^^^ expected `u128`, found `isize`
+ |
+ = note: `-1_isize` cannot fit into type `u128`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:14:13
+ |
+LL | x_u64 > -1_isize;
+ | ^^^^^^^^ expected `u64`, found `isize`
+ |
+ = note: `-1_isize` cannot fit into type `u64`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:16:13
+ |
+LL | x_u32 > -1_isize;
+ | ^^^^^^^^ expected `u32`, found `isize`
+ |
+ = note: `-1_isize` cannot fit into type `u32`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:18:13
+ |
+LL | x_u16 > -1_isize;
+ | ^^^^^^^^ expected `u16`, found `isize`
+ |
+ = note: `-1_isize` cannot fit into type `u16`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:20:12
+ |
+LL | x_u8 > -1_isize;
+ | ^^^^^^^^ expected `u8`, found `isize`
+ |
+help: you can convert `x_u8` from `u8` to `isize`, matching the type of `-1_isize`
+ |
+LL | isize::from(x_u8) > -1_isize;
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:23:15
+ |
+LL | x_usize > -1_i128;
+ | ^^^^^^^ expected `usize`, found `i128`
+ |
+ = note: `-1_i128` cannot fit into type `usize`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:25:14
+ |
+LL | x_u128 > -1_i128;
+ | ^^^^^^^ expected `u128`, found `i128`
+ |
+ = note: `-1_i128` cannot fit into type `u128`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:27:13
+ |
+LL | x_u64 > -1_i128;
+ | ^^^^^^^ expected `u64`, found `i128`
+ |
+help: you can convert `x_u64` from `u64` to `i128`, matching the type of `-1_i128`
+ |
+LL | i128::from(x_u64) > -1_i128;
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:29:13
+ |
+LL | x_u32 > -1_i128;
+ | ^^^^^^^ expected `u32`, found `i128`
+ |
+help: you can convert `x_u32` from `u32` to `i128`, matching the type of `-1_i128`
+ |
+LL | i128::from(x_u32) > -1_i128;
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:31:13
+ |
+LL | x_u16 > -1_i128;
+ | ^^^^^^^ expected `u16`, found `i128`
+ |
+help: you can convert `x_u16` from `u16` to `i128`, matching the type of `-1_i128`
+ |
+LL | i128::from(x_u16) > -1_i128;
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:33:12
+ |
+LL | x_u8 > -1_i128;
+ | ^^^^^^^ expected `u8`, found `i128`
+ |
+help: you can convert `x_u8` from `u8` to `i128`, matching the type of `-1_i128`
+ |
+LL | i128::from(x_u8) > -1_i128;
+ | ^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:36:15
+ |
+LL | x_usize > -1_i64;
+ | ^^^^^^ expected `usize`, found `i64`
+ |
+ = note: `-1_i64` cannot fit into type `usize`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:38:14
+ |
+LL | x_u128 > -1_i64;
+ | ^^^^^^ expected `u128`, found `i64`
+ |
+ = note: `-1_i64` cannot fit into type `u128`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:40:13
+ |
+LL | x_u64 > -1_i64;
+ | ^^^^^^ expected `u64`, found `i64`
+ |
+ = note: `-1_i64` cannot fit into type `u64`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:42:13
+ |
+LL | x_u32 > -1_i64;
+ | ^^^^^^ expected `u32`, found `i64`
+ |
+help: you can convert `x_u32` from `u32` to `i64`, matching the type of `-1_i64`
+ |
+LL | i64::from(x_u32) > -1_i64;
+ | ^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:44:13
+ |
+LL | x_u16 > -1_i64;
+ | ^^^^^^ expected `u16`, found `i64`
+ |
+help: you can convert `x_u16` from `u16` to `i64`, matching the type of `-1_i64`
+ |
+LL | i64::from(x_u16) > -1_i64;
+ | ^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:46:12
+ |
+LL | x_u8 > -1_i64;
+ | ^^^^^^ expected `u8`, found `i64`
+ |
+help: you can convert `x_u8` from `u8` to `i64`, matching the type of `-1_i64`
+ |
+LL | i64::from(x_u8) > -1_i64;
+ | ^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:49:15
+ |
+LL | x_usize > -1_i32;
+ | ^^^^^^ expected `usize`, found `i32`
+ |
+ = note: `-1_i32` cannot fit into type `usize`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:51:14
+ |
+LL | x_u128 > -1_i32;
+ | ^^^^^^ expected `u128`, found `i32`
+ |
+ = note: `-1_i32` cannot fit into type `u128`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:53:13
+ |
+LL | x_u64 > -1_i32;
+ | ^^^^^^ expected `u64`, found `i32`
+ |
+ = note: `-1_i32` cannot fit into type `u64`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:55:13
+ |
+LL | x_u32 > -1_i32;
+ | ^^^^^^ expected `u32`, found `i32`
+ |
+ = note: `-1_i32` cannot fit into type `u32`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:57:13
+ |
+LL | x_u16 > -1_i32;
+ | ^^^^^^ expected `u16`, found `i32`
+ |
+help: you can convert `x_u16` from `u16` to `i32`, matching the type of `-1_i32`
+ |
+LL | i32::from(x_u16) > -1_i32;
+ | ^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:59:12
+ |
+LL | x_u8 > -1_i32;
+ | ^^^^^^ expected `u8`, found `i32`
+ |
+help: you can convert `x_u8` from `u8` to `i32`, matching the type of `-1_i32`
+ |
+LL | i32::from(x_u8) > -1_i32;
+ | ^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:62:15
+ |
+LL | x_usize > -1_i16;
+ | ^^^^^^ expected `usize`, found `i16`
+ |
+ = note: `-1_i16` cannot fit into type `usize`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:64:14
+ |
+LL | x_u128 > -1_i16;
+ | ^^^^^^ expected `u128`, found `i16`
+ |
+ = note: `-1_i16` cannot fit into type `u128`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:66:13
+ |
+LL | x_u64 > -1_i16;
+ | ^^^^^^ expected `u64`, found `i16`
+ |
+ = note: `-1_i16` cannot fit into type `u64`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:68:13
+ |
+LL | x_u32 > -1_i16;
+ | ^^^^^^ expected `u32`, found `i16`
+ |
+ = note: `-1_i16` cannot fit into type `u32`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:70:13
+ |
+LL | x_u16 > -1_i16;
+ | ^^^^^^ expected `u16`, found `i16`
+ |
+ = note: `-1_i16` cannot fit into type `u16`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:72:12
+ |
+LL | x_u8 > -1_i16;
+ | ^^^^^^ expected `u8`, found `i16`
+ |
+help: you can convert `x_u8` from `u8` to `i16`, matching the type of `-1_i16`
+ |
+LL | i16::from(x_u8) > -1_i16;
+ | ^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:75:15
+ |
+LL | x_usize > -1_i8;
+ | ^^^^^ expected `usize`, found `i8`
+ |
+ = note: `-1_i8` cannot fit into type `usize`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:77:14
+ |
+LL | x_u128 > -1_i8;
+ | ^^^^^ expected `u128`, found `i8`
+ |
+ = note: `-1_i8` cannot fit into type `u128`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:79:13
+ |
+LL | x_u64 > -1_i8;
+ | ^^^^^ expected `u64`, found `i8`
+ |
+ = note: `-1_i8` cannot fit into type `u64`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:81:13
+ |
+LL | x_u32 > -1_i8;
+ | ^^^^^ expected `u32`, found `i8`
+ |
+ = note: `-1_i8` cannot fit into type `u32`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:83:13
+ |
+LL | x_u16 > -1_i8;
+ | ^^^^^ expected `u16`, found `i8`
+ |
+ = note: `-1_i8` cannot fit into type `u16`
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-no-fix.rs:85:12
+ |
+LL | x_u8 > -1_i8;
+ | ^^^^^ expected `u8`, found `i8`
+ |
+ = note: `-1_i8` cannot fit into type `u8`
+
+error: aborting due to 36 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
--> $DIR/object-lifetime-default-from-box-error.rs:18:5
|
LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> {
- | --------------- data with this lifetime...
+ | --------------- this data with an anonymous lifetime `'_`...
...
LL | ss.r
- | ^^^^ ...is captured and required to be `'static` here
+ | ^^^^ ...is captured and required to live as long as `'static` here
|
-help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #2 defined on the function body at 14:1
+help: to declare that the trait object captures data from argument `ss`, you can add an explicit `'_` lifetime bound
|
LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait + '_> {
| ^^^^
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0621`.
+Some errors have detailed explanations: E0621, E0759.
+For more information about an error, try `rustc --explain E0621`.
--- /dev/null
+// check-pass
+#![feature(or_patterns)]
+
+const fn foo((Ok(a) | Err(a)): Result<i32, i32>) {
+ let x = Ok(3);
+ let Ok(y) | Err(y) = x;
+}
+
+const X: () = {
+ let x = Ok(3);
+ let Ok(y) | Err(y) = x;
+};
+
+static Y: () = {
+ let x = Ok(3);
+ let Ok(y) | Err(y) = x;
+};
+
+static mut Z: () = {
+ let x = Ok(3);
+ let Ok(y) | Err(y) = x;
+};
+
+fn main() {
+ let _: [(); {
+ let x = Ok(3);
+ let Ok(y) | Err(y) = x;
+ 2
+ }];
+}
// We wrap patterns in a tuple because top-level or-patterns were special-cased.
fn main() {
match (0u8, 0u8) {
- //~^ ERROR non-exhaustive patterns: `(2u8..=u8::MAX, _)`
+ //~^ ERROR non-exhaustive patterns: `(2_u8..=u8::MAX, _)`
(0 | 1, 2 | 3) => {}
}
match ((0u8,),) {
- //~^ ERROR non-exhaustive patterns: `((4u8..=u8::MAX))`
+ //~^ ERROR non-exhaustive patterns: `((4_u8..=u8::MAX))`
((0 | 1,) | (2 | 3,),) => {}
}
match (Some(0u8),) {
- //~^ ERROR non-exhaustive patterns: `(Some(2u8..=u8::MAX))`
+ //~^ ERROR non-exhaustive patterns: `(Some(2_u8..=u8::MAX))`
(None | Some(0 | 1),) => {}
}
}
-error[E0004]: non-exhaustive patterns: `(2u8..=u8::MAX, _)` not covered
+error[E0004]: non-exhaustive patterns: `(2_u8..=u8::MAX, _)` not covered
--> $DIR/exhaustiveness-non-exhaustive.rs:6:11
|
LL | match (0u8, 0u8) {
- | ^^^^^^^^^^ pattern `(2u8..=u8::MAX, _)` not covered
+ | ^^^^^^^^^^ pattern `(2_u8..=u8::MAX, _)` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(u8, u8)`
-error[E0004]: non-exhaustive patterns: `((4u8..=u8::MAX))` not covered
+error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX))` not covered
--> $DIR/exhaustiveness-non-exhaustive.rs:10:11
|
LL | match ((0u8,),) {
- | ^^^^^^^^^ pattern `((4u8..=u8::MAX))` not covered
+ | ^^^^^^^^^ pattern `((4_u8..=u8::MAX))` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `((u8,),)`
-error[E0004]: non-exhaustive patterns: `(Some(2u8..=u8::MAX))` not covered
+error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` not covered
--> $DIR/exhaustiveness-non-exhaustive.rs:14:11
|
LL | match (Some(0u8),) {
- | ^^^^^^^^^^^^ pattern `(Some(2u8..=u8::MAX))` not covered
+ | ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX))` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(std::option::Option<u8>,)`
+++ /dev/null
-#![feature(or_patterns)]
-
-const fn foo((Ok(a) | Err(a)): Result<i32, i32>) {
- //~^ ERROR or-pattern is not allowed in a `const fn`
- let x = Ok(3);
- let Ok(y) | Err(y) = x;
- //~^ ERROR or-pattern is not allowed in a `const fn`
-}
-
-const X: () = {
- let x = Ok(3);
- let Ok(y) | Err(y) = x;
- //~^ ERROR or-pattern is not allowed in a `const`
-};
-
-static Y: () = {
- let x = Ok(3);
- let Ok(y) | Err(y) = x;
- //~^ ERROR or-pattern is not allowed in a `static`
-};
-
-static mut Z: () = {
- let x = Ok(3);
- let Ok(y) | Err(y) = x;
- //~^ ERROR or-pattern is not allowed in a `static mut`
-};
-
-fn main() {
- let _: [(); {
- let x = Ok(3);
- let Ok(y) | Err(y) = x;
- //~^ ERROR or-pattern is not allowed in a `const`
- 2
- }];
-}
+++ /dev/null
-error[E0658]: or-pattern is not allowed in a `const fn`
- --> $DIR/feature-gate-const-fn.rs:3:15
- |
-LL | const fn foo((Ok(a) | Err(a)): Result<i32, i32>) {
- | ^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: or-pattern is not allowed in a `const fn`
- --> $DIR/feature-gate-const-fn.rs:6:9
- |
-LL | let Ok(y) | Err(y) = x;
- | ^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: or-pattern is not allowed in a `const`
- --> $DIR/feature-gate-const-fn.rs:12:9
- |
-LL | let Ok(y) | Err(y) = x;
- | ^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: or-pattern is not allowed in a `static`
- --> $DIR/feature-gate-const-fn.rs:18:9
- |
-LL | let Ok(y) | Err(y) = x;
- | ^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: or-pattern is not allowed in a `static mut`
- --> $DIR/feature-gate-const-fn.rs:24:9
- |
-LL | let Ok(y) | Err(y) = x;
- | ^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: or-pattern is not allowed in a `const`
- --> $DIR/feature-gate-const-fn.rs:31:13
- |
-LL | let Ok(y) | Err(y) = x;
- | ^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `3i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
--> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:4:9
|
LL | let 0 | (1 | 2) = 0;
- | ^^^^^^^^^^^ patterns `i32::MIN..=-1i32` and `3i32..=i32::MAX` not covered
+ | ^^^^^^^^^^^ patterns `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
LL | if let 0 | (1 | 2) = 0 { /* */ }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0004]: non-exhaustive patterns: `i32::MIN..=-1i32` and `3i32..=i32::MAX` not covered
+error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
--> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:5:11
|
LL | match 0 {
- | ^ patterns `i32::MIN..=-1i32` and `3i32..=i32::MAX` not covered
+ | ^ patterns `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
error[E0641]: cannot cast to a pointer of an unknown kind
- --> $DIR/order-dependent-cast-inference.rs:5:17
+ --> $DIR/order-dependent-cast-inference.rs:5:22
|
LL | let mut y = 0 as *const _;
- | ^^^^^--------
- | |
- | help: consider giving more type information
+ | ^^^^^^^^ needs more type information
|
= note: the type information given here is insufficient to check whether the pointer cast is valid
// run-pass
#![feature(marker_trait_attr)]
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
#[marker]
trait MyMarker {}
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/overlap-doesnt-conflict-with-specialization.rs:4:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// Semantically, we do not allow e.g., `static X: u8 = 0;` as an associated item.
#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
fn main() {}
error: associated `static` items are not allowed
- --> $DIR/assoc-static-semantic-fail.rs:9:5
+ --> $DIR/assoc-static-semantic-fail.rs:10:5
|
LL | static IA: u8 = 0;
| ^^^^^^^^^^^^^^^^^^
error: associated `static` items are not allowed
- --> $DIR/assoc-static-semantic-fail.rs:11:5
+ --> $DIR/assoc-static-semantic-fail.rs:12:5
|
LL | static IB: u8;
| ^^^^^^^^^^^^^^
error: a static item cannot be `default`
- --> $DIR/assoc-static-semantic-fail.rs:14:5
+ --> $DIR/assoc-static-semantic-fail.rs:15:5
|
LL | default static IC: u8 = 0;
| ^^^^^^^ `default` because of this
= note: only associated `fn`, `const`, and `type` items can be `default`
error: associated `static` items are not allowed
- --> $DIR/assoc-static-semantic-fail.rs:14:5
+ --> $DIR/assoc-static-semantic-fail.rs:15:5
|
LL | default static IC: u8 = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: a static item cannot be `default`
- --> $DIR/assoc-static-semantic-fail.rs:17:16
+ --> $DIR/assoc-static-semantic-fail.rs:18:16
|
LL | pub(crate) default static ID: u8;
| ^^^^^^^ `default` because of this
= note: only associated `fn`, `const`, and `type` items can be `default`
error: associated `static` items are not allowed
- --> $DIR/assoc-static-semantic-fail.rs:17:5
+ --> $DIR/assoc-static-semantic-fail.rs:18:5
|
LL | pub(crate) default static ID: u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: associated `static` items are not allowed
- --> $DIR/assoc-static-semantic-fail.rs:24:5
+ --> $DIR/assoc-static-semantic-fail.rs:25:5
|
LL | static TA: u8 = 0;
| ^^^^^^^^^^^^^^^^^^
error: associated `static` items are not allowed
- --> $DIR/assoc-static-semantic-fail.rs:26:5
+ --> $DIR/assoc-static-semantic-fail.rs:27:5
|
LL | static TB: u8;
| ^^^^^^^^^^^^^^
error: a static item cannot be `default`
- --> $DIR/assoc-static-semantic-fail.rs:28:5
+ --> $DIR/assoc-static-semantic-fail.rs:29:5
|
LL | default static TC: u8 = 0;
| ^^^^^^^ `default` because of this
= note: only associated `fn`, `const`, and `type` items can be `default`
error: associated `static` items are not allowed
- --> $DIR/assoc-static-semantic-fail.rs:28:5
+ --> $DIR/assoc-static-semantic-fail.rs:29:5
|
LL | default static TC: u8 = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: a static item cannot be `default`
- --> $DIR/assoc-static-semantic-fail.rs:31:16
+ --> $DIR/assoc-static-semantic-fail.rs:32:16
|
LL | pub(crate) default static TD: u8;
| ^^^^^^^ `default` because of this
= note: only associated `fn`, `const`, and `type` items can be `default`
error: associated `static` items are not allowed
- --> $DIR/assoc-static-semantic-fail.rs:31:5
+ --> $DIR/assoc-static-semantic-fail.rs:32:5
|
LL | pub(crate) default static TD: u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: associated `static` items are not allowed
- --> $DIR/assoc-static-semantic-fail.rs:38:5
+ --> $DIR/assoc-static-semantic-fail.rs:39:5
|
LL | static TA: u8 = 0;
| ^^^^^^^^^^^^^^^^^^
error: associated `static` items are not allowed
- --> $DIR/assoc-static-semantic-fail.rs:40:5
+ --> $DIR/assoc-static-semantic-fail.rs:41:5
|
LL | static TB: u8;
| ^^^^^^^^^^^^^^
error: a static item cannot be `default`
- --> $DIR/assoc-static-semantic-fail.rs:43:5
+ --> $DIR/assoc-static-semantic-fail.rs:44:5
|
LL | default static TC: u8 = 0;
| ^^^^^^^ `default` because of this
= note: only associated `fn`, `const`, and `type` items can be `default`
error: associated `static` items are not allowed
- --> $DIR/assoc-static-semantic-fail.rs:43:5
+ --> $DIR/assoc-static-semantic-fail.rs:44:5
|
LL | default static TC: u8 = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: a static item cannot be `default`
- --> $DIR/assoc-static-semantic-fail.rs:46:9
+ --> $DIR/assoc-static-semantic-fail.rs:47:9
|
LL | pub default static TD: u8;
| ^^^^^^^ `default` because of this
= note: only associated `fn`, `const`, and `type` items can be `default`
error: associated `static` items are not allowed
- --> $DIR/assoc-static-semantic-fail.rs:46:5
+ --> $DIR/assoc-static-semantic-fail.rs:47:5
|
LL | pub default static TD: u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: associated constant in `impl` without body
- --> $DIR/assoc-static-semantic-fail.rs:11:5
+ --> $DIR/assoc-static-semantic-fail.rs:12:5
|
LL | static IB: u8;
| ^^^^^^^^^^^^^-
| help: provide a definition for the constant: `= <expr>;`
error: associated constant in `impl` without body
- --> $DIR/assoc-static-semantic-fail.rs:17:5
+ --> $DIR/assoc-static-semantic-fail.rs:18:5
|
LL | pub(crate) default static ID: u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: provide a definition for the constant: `= <expr>;`
error[E0449]: unnecessary visibility qualifier
- --> $DIR/assoc-static-semantic-fail.rs:31:5
+ --> $DIR/assoc-static-semantic-fail.rs:32:5
|
LL | pub(crate) default static TD: u8;
| ^^^^^^^^^^
error: associated constant in `impl` without body
- --> $DIR/assoc-static-semantic-fail.rs:40:5
+ --> $DIR/assoc-static-semantic-fail.rs:41:5
|
LL | static TB: u8;
| ^^^^^^^^^^^^^-
| help: provide a definition for the constant: `= <expr>;`
error: associated constant in `impl` without body
- --> $DIR/assoc-static-semantic-fail.rs:46:5
+ --> $DIR/assoc-static-semantic-fail.rs:47:5
|
LL | pub default static TD: u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: provide a definition for the constant: `= <expr>;`
error[E0449]: unnecessary visibility qualifier
- --> $DIR/assoc-static-semantic-fail.rs:46:5
+ --> $DIR/assoc-static-semantic-fail.rs:47:5
|
LL | pub default static TD: u8;
| ^^^ `pub` not permitted here because it's implied
-error: aborting due to 24 previous errors
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/assoc-static-semantic-fail.rs:3:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+error: aborting due to 24 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0449`.
b' '; //~ ERROR byte constant must be escaped
b'''; //~ ERROR byte constant must be escaped
b'é'; //~ ERROR byte constant must be ASCII
- b'a //~ ERROR unterminated byte constant
+ b'a //~ ERROR unterminated byte constant [E0763]
}
LL | b'é';
| ^
-error: unterminated byte constant
+error[E0763]: unterminated byte constant
--> $DIR/byte-literals.rs:11:6
|
LL | b'a
error: aborting due to 7 previous errors
+For more information about this error, try `rustc --explain E0763`.
LL | b"é";
| ^
-error: unterminated double quote byte string
+error[E0766]: unterminated double quote byte string
--> $DIR/byte-string-literals.rs:7:6
|
LL | b"a
error: aborting due to 5 previous errors
+For more information about this error, try `rustc --explain E0766`.
// Test successful and unsuccessful parsing of the `default` contextual keyword
#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
trait Foo {
fn foo<T: Default>() -> T;
error: `default` is not followed by an item
- --> $DIR/default.rs:22:5
+ --> $DIR/default.rs:23:5
|
LL | default pub fn foo<T: Default>() -> T { T::default() }
| ^^^^^^^ the `default` qualifier
= note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`
error: non-item in item list
- --> $DIR/default.rs:22:13
+ --> $DIR/default.rs:23:13
|
LL | impl Foo for u32 {
| - item list starts here
| - item list ends here
error[E0449]: unnecessary visibility qualifier
- --> $DIR/default.rs:16:5
+ --> $DIR/default.rs:17:5
|
LL | pub default fn foo<T: Default>() -> T {
| ^^^ `pub` not permitted here because it's implied
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/default.rs:3:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0046]: not all trait items implemented, missing: `foo`
- --> $DIR/default.rs:21:1
+ --> $DIR/default.rs:22:1
|
LL | fn foo<T: Default>() -> T;
| -------------------------- `foo` from trait
LL | impl Foo for u32 {
| ^^^^^^^^^^^^^^^^ missing `foo` in implementation
-error: aborting due to 4 previous errors
+error: aborting due to 4 previous errors; 1 warning emitted
Some errors have detailed explanations: E0046, E0449.
For more information about an error, try `rustc --explain E0046`.
+#![allow(clashing_extern_declarations)]
// check-pass
// In this test we check that the parser accepts an ABI string when it
// ignore-tidy-trailing-newlines
// error-pattern: aborting due to 3 previous errors
+#![allow(uncommon_codepoints)]
+
y![
Ϥ,
\ No newline at end of file
error: this file contains an unclosed delimiter
- --> $DIR/issue-62524.rs:4:3
+ --> $DIR/issue-62524.rs:6:3
|
LL | y![
| - unclosed delimiter
| ^
error: macros that expand to items must be delimited with braces or followed by a semicolon
- --> $DIR/issue-62524.rs:3:3
+ --> $DIR/issue-62524.rs:5:3
|
LL | y![
| ___^
| ^
error: cannot find macro `y` in this scope
- --> $DIR/issue-62524.rs:3:1
+ --> $DIR/issue-62524.rs:5:1
|
LL | y![
| ^
--- /dev/null
+fn main() {
+ let a: i8 *= 1; //~ ERROR can't reassign to an uninitialized variable
+ let _ = a;
+ let b += 1; //~ ERROR can't reassign to an uninitialized variable
+ let _ = b;
+ let c *= 1; //~ ERROR can't reassign to an uninitialized variable
+ let _ = c;
+}
--- /dev/null
+error: can't reassign to an uninitialized variable
+ --> $DIR/let-binop.rs:2:15
+ |
+LL | let a: i8 *= 1;
+ | ^^ help: initialize the variable
+
+error: can't reassign to an uninitialized variable
+ --> $DIR/let-binop.rs:4:11
+ |
+LL | let b += 1;
+ | ^^ help: initialize the variable
+
+error: can't reassign to an uninitialized variable
+ --> $DIR/let-binop.rs:6:11
+ |
+LL | let c *= 1;
+ | ^^ help: initialize the variable
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+#!
+
+// check-pass
+fn main() {}
--- /dev/null
+#!
+
+// check-pass
+// ignore-tidy-end-whitespace
+fn main() {}
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
fn main() {}
| |
| `default` because of this
-error: aborting due to 6 previous errors
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/trait-item-with-defaultness-fail-semantic.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+error: aborting due to 6 previous errors; 1 warning emitted
-error: unterminated double quote string
+error[E0765]: unterminated double quote string
--> $DIR/unbalanced-doublequote.rs:5:5
|
LL | / "
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0765`.
| value moved here
|
= note: move occurs because value has type `X`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `x.0`
+ |
+LL | Some(ref _z @ ref _y) => {}
+ | ^^^
error[E0382]: borrow of moved value
--> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:19
| value moved here
|
= note: move occurs because value has type `X`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `x.0`
+ |
+LL | Some(ref _z @ ref mut _y) => {}
+ | ^^^
error: aborting due to 6 previous errors
| value moved here
|
= note: move occurs because value has type `main::U`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving the value
+ |
+LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
+ | ^^^
error[E0382]: use of moved value
--> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38
| value moved here
|
= note: move occurs because value has type `main::U`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving the value
+ |
+LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
+ | ^^^
error[E0382]: borrow of moved value
--> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:30
| value moved here
|
= note: move occurs because value has type `main::U`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving the value
+ |
+LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
+ | ^^^
error[E0382]: use of moved value
--> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38
| value moved here
|
= note: move occurs because value has type `main::U`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving the value
+ |
+LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
+ | ^^^
error[E0382]: borrow of moved value
--> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:30
LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^
-error[E0004]: non-exhaustive patterns: `128u8..=u8::MAX` not covered
+error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered
--> $DIR/exhaustive_integer_patterns.rs:28:11
|
LL | match x {
- | ^ pattern `128u8..=u8::MAX` not covered
+ | ^ pattern `128_u8..=u8::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
-error[E0004]: non-exhaustive patterns: `11u8..=19u8`, `31u8..=34u8`, `36u8..=69u8` and 1 more not covered
+error[E0004]: non-exhaustive patterns: `11_u8..=19_u8`, `31_u8..=34_u8`, `36_u8..=69_u8` and 1 more not covered
--> $DIR/exhaustive_integer_patterns.rs:33:11
|
LL | match x {
- | ^ patterns `11u8..=19u8`, `31u8..=34u8`, `36u8..=69u8` and 1 more not covered
+ | ^ patterns `11_u8..=19_u8`, `31_u8..=34_u8`, `36_u8..=69_u8` and 1 more not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
LL | -2..=20 => {}
| ^^^^^^^
-error[E0004]: non-exhaustive patterns: `i8::MIN..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered
+error[E0004]: non-exhaustive patterns: `i8::MIN..=-8_i8`, `-6_i8`, `121_i8..=124_i8` and 1 more not covered
--> $DIR/exhaustive_integer_patterns.rs:41:11
|
LL | match x {
- | ^ patterns `i8::MIN..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered
+ | ^ patterns `i8::MIN..=-8_i8`, `-6_i8`, `121_i8..=124_i8` and 1 more not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
-error[E0004]: non-exhaustive patterns: `0i16` not covered
+error[E0004]: non-exhaustive patterns: `0_i16` not covered
--> $DIR/exhaustive_integer_patterns.rs:91:11
|
LL | match 0i16 {
- | ^^^^ pattern `0i16` not covered
+ | ^^^^ pattern `0_i16` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
-error[E0004]: non-exhaustive patterns: `128u8..=u8::MAX` not covered
+error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered
--> $DIR/exhaustive_integer_patterns.rs:109:11
|
LL | match 0u8 {
- | ^^^ pattern `128u8..=u8::MAX` not covered
+ | ^^^ pattern `128_u8..=u8::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
-error[E0004]: non-exhaustive patterns: `(0u8, Some(_))` and `(2u8..=u8::MAX, Some(_))` not covered
+error[E0004]: non-exhaustive patterns: `(0_u8, Some(_))` and `(2_u8..=u8::MAX, Some(_))` not covered
--> $DIR/exhaustive_integer_patterns.rs:121:11
|
LL | match (0u8, Some(())) {
- | ^^^^^^^^^^^^^^^ patterns `(0u8, Some(_))` and `(2u8..=u8::MAX, Some(_))` not covered
+ | ^^^^^^^^^^^^^^^ patterns `(0_u8, Some(_))` and `(2_u8..=u8::MAX, Some(_))` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(u8, std::option::Option<()>)`
-error[E0004]: non-exhaustive patterns: `(126u8..=127u8, false)` not covered
+error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered
--> $DIR/exhaustive_integer_patterns.rs:126:11
|
LL | match (0u8, true) {
- | ^^^^^^^^^^^ pattern `(126u8..=127u8, false)` not covered
+ | ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(u8, bool)`
--> $DIR/exhaustive_integer_patterns.rs:141:9
|
LL | 0 .. 2 => {}
- | ------ this range overlaps on `1u8`
+ | ------ this range overlaps on `1_u8`
LL | 1 ..= 2 => {}
| ^^^^^^^ overlapping patterns
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
-error[E0004]: non-exhaustive patterns: `5u128..=u128::MAX` not covered
+error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
--> $DIR/exhaustive_integer_patterns.rs:150:11
|
LL | match 0u128 {
- | ^^^^^ pattern `5u128..=u128::MAX` not covered
+ | ^^^^^ pattern `5_u128..=u128::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
-error[E0004]: non-exhaustive patterns: `0u128..=3u128` not covered
+error[E0004]: non-exhaustive patterns: `0_u128..=3_u128` not covered
--> $DIR/exhaustive_integer_patterns.rs:154:11
|
LL | match 0u128 {
- | ^^^^^ pattern `0u128..=3u128` not covered
+ | ^^^^^ pattern `0_u128..=3_u128` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
--> $DIR/issue-43253.rs:16:9
|
LL | 1..10 => {},
- | ----- this range overlaps on `9i32`
+ | ----- this range overlaps on `9_i32`
LL | 9..=10 => {},
| ^^^^^^ overlapping patterns
|
-error[E0004]: non-exhaustive patterns: `&[0u8..=64u8, _, _, _]` and `&[66u8..=u8::MAX, _, _, _]` not covered
+error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
--> $DIR/match-byte-array-patterns-2.rs:4:11
|
LL | match buf {
- | ^^^ patterns `&[0u8..=64u8, _, _, _]` and `&[66u8..=u8::MAX, _, _, _]` not covered
+ | ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[u8; 4]`
-error[E0004]: non-exhaustive patterns: `i32::MIN..=0i32` and `2i32..=i32::MAX` not covered
+error[E0004]: non-exhaustive patterns: `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered
--> $DIR/match-non-exhaustive.rs:2:11
|
LL | match 0 { 1 => () }
- | ^ patterns `i32::MIN..=0i32` and `2i32..=i32::MAX` not covered
+ | ^ patterns `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
match Some(10) { //~ ERROR non-exhaustive patterns: `Some(_)` not covered
None => {}
}
- match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, i32::MIN..=3i32)`
- // and `(_, _, 5i32..=i32::MAX)` not covered
+ match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)`
+ // and `(_, _, 5_i32..=i32::MAX)` not covered
(_, _, 4) => {}
}
match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` not covered
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `std::option::Option<i32>`
-error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3i32)` and `(_, _, 5i32..=i32::MAX)` not covered
+error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
--> $DIR/non-exhaustive-match.rs:14:11
|
LL | match (2, 3, 4) {
- | ^^^^^^^^^ patterns `(_, _, i32::MIN..=3i32)` and `(_, _, 5i32..=i32::MAX)` not covered
+ | ^^^^^^^^^ patterns `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(i32, i32, i32)`
fn main() {
let (1, (Some(1), 2..=3)) = (1, (None, 2));
- //~^ ERROR refutable pattern in local binding: `(i32::MIN..=0i32, _)` and `(2i32..=i32::MAX, _)` not covered
+ //~^ ERROR refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
}
|
= note: the matched value is of type `(isize, (std::option::Option<isize>, isize))`
-error[E0005]: refutable pattern in local binding: `(i32::MIN..=0i32, _)` and `(2i32..=i32::MAX, _)` not covered
+error[E0005]: refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
--> $DIR/refutable-pattern-errors.rs:7:9
|
LL | let (1, (Some(1), 2..=3)) = (1, (None, 2));
- | ^^^^^^^^^^^^^^^^^^^^^ patterns `(i32::MIN..=0i32, _)` and `(2i32..=i32::MAX, _)` not covered
+ | ^^^^^^^^^^^^^^^^^^^^^ patterns `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-error[E0004]: non-exhaustive patterns: `isize::MIN..=-6isize` and `21isize..=isize::MAX` not covered
+error[E0004]: non-exhaustive patterns: `isize::MIN..=-6_isize` and `21_isize..=isize::MAX` not covered
--> $DIR/precise_pointer_size_matching.rs:24:11
|
LL | match 0isize {
- | ^^^^^^ patterns `isize::MIN..=-6isize` and `21isize..=isize::MAX` not covered
+ | ^^^^^^ patterns `isize::MIN..=-6_isize` and `21_isize..=isize::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
-error[E0004]: non-exhaustive patterns: `0usize` and `21usize..=usize::MAX` not covered
+error[E0004]: non-exhaustive patterns: `0_usize` and `21_usize..=usize::MAX` not covered
--> $DIR/precise_pointer_size_matching.rs:29:11
|
LL | match 0usize {
- | ^^^^^^ patterns `0usize` and `21usize..=usize::MAX` not covered
+ | ^^^^^^ patterns `0_usize` and `21_usize..=usize::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
|
LL | Baz();
| ^^^
-help: consider importing one of these items instead
- |
-LL | use foo1::Bar;
+help: consider importing this function instead
|
LL | use foo2::Bar;
|
-LL | use foo3::Bar;
- |
error[E0425]: cannot find function, tuple struct or tuple variant `Bar` in this scope
--> $DIR/privacy-ns1.rs:51:5
|
LL | Baz();
| ^^^
-help: consider importing one of these items
- |
-LL | use foo1::Bar;
+help: consider importing this function
|
LL | use foo2::Bar;
|
-LL | use foo3::Bar;
- |
error[E0412]: cannot find type `Bar` in this scope
--> $DIR/privacy-ns1.rs:52:17
|
LL | let _x: Box<Baz>;
| ^^^
-help: consider importing one of these items
+help: consider importing this trait
|
LL | use foo1::Bar;
|
-LL | use foo2::Bar;
- |
-LL | use foo3::Bar;
- |
error[E0107]: wrong number of const arguments: expected 0, found 1
--> $DIR/privacy-ns1.rs:35:17
LL | Bar();
| ^^^ not a function, tuple struct or tuple variant
|
-help: consider importing one of these items instead
- |
-LL | use foo1::Bar;
+help: consider importing this function instead
|
LL | use foo2::Bar;
|
-LL | use foo3::Bar;
- |
error[E0423]: expected function, tuple struct or tuple variant, found trait `Bar`
--> $DIR/privacy-ns2.rs:26:5
|
LL | Baz();
| ^^^
-help: consider importing one of these items instead
- |
-LL | use foo1::Bar;
+help: consider importing this function instead
|
LL | use foo2::Bar;
|
-LL | use foo3::Bar;
- |
error[E0573]: expected type, found function `Bar`
--> $DIR/privacy-ns2.rs:43:14
|
LL | let _x = Bar();
| ^
-help: consider importing one of these items instead
+help: consider importing this trait instead
|
LL | use foo1::Bar;
|
-LL | use foo2::Bar;
- |
-LL | use foo3::Bar;
- |
error[E0603]: trait `Bar` is private
--> $DIR/privacy-ns2.rs:63:15
--- /dev/null
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Group, Delimiter};
+
+#[proc_macro_attribute]
+pub fn first(_attr: TokenStream, item: TokenStream) -> TokenStream {
+ let tokens: TokenStream = "#[derive(Second)]".parse().unwrap();
+ let wrapped = TokenTree::Group(Group::new(Delimiter::None, item.into_iter().collect()));
+ tokens.into_iter().chain(std::iter::once(wrapped)).collect()
+}
+
+#[proc_macro_derive(Second)]
+pub fn second(item: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
--- /dev/null
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn recollect(tokens: TokenStream) -> TokenStream {
+ tokens.into_iter().collect()
+}
--- /dev/null
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Group};
+
+fn find_my_ident(tokens: TokenStream) -> Option<TokenStream> {
+ for token in tokens {
+ if let TokenTree::Ident(ident) = &token {
+ if ident.to_string() == "hidden_ident" {
+ return Some(vec![token].into_iter().collect())
+ }
+ } else if let TokenTree::Group(g) = token {
+ if let Some(stream) = find_my_ident(g.stream()) {
+ return Some(stream)
+ }
+ }
+ }
+ return None;
+}
+
+
+#[proc_macro_derive(WeirdDerive)]
+pub fn weird_derive(item: TokenStream) -> TokenStream {
+ let my_ident = find_my_ident(item).expect("Missing 'my_ident'!");
+ let tokens: TokenStream = "call_it!();".parse().unwrap();
+ let final_call = tokens.into_iter().map(|tree| {
+ if let TokenTree::Group(g) = tree {
+ return Group::new(g.delimiter(), my_ident.clone()).into()
+ } else {
+ return tree
+ }
+ }).collect();
+ final_call
+}
+
+#[proc_macro]
+pub fn recollect(item: TokenStream) -> TokenStream {
+ item.into_iter().collect()
+}
+
+#[proc_macro_attribute]
+pub fn recollect_attr(_attr: TokenStream, mut item: TokenStream) -> TokenStream {
+ item.into_iter().collect()
+}
--- /dev/null
+// aux-build:test-macros.rs
+// check-pass
+
+extern crate test_macros;
+use test_macros::recollect;
+
+macro_rules! use_expr {
+ ($expr:expr) => {
+ recollect!($expr)
+ }
+}
+
+#[allow(dead_code)]
+struct Foo;
+impl Foo {
+ #[allow(dead_code)]
+ fn use_self(self) {
+ drop(use_expr!(self));
+ }
+}
+
+fn main() {}
--- /dev/null
+// aux-build:first-second.rs
+// FIXME: The spans here are bad, see PR #73084
+
+extern crate first_second;
+use first_second::*;
+
+macro_rules! produce_it {
+ ($name:ident) => {
+ #[first] //~ ERROR cannot find type
+ struct $name {
+ field: MissingType
+ }
+ }
+}
+
+produce_it!(MyName);
+
+fn main() {
+ println!("Hello, world!");
+}
--- /dev/null
+error[E0412]: cannot find type `MissingType` in this scope
+ --> $DIR/macro-rules-derive.rs:9:9
+ |
+LL | #[first]
+ | ^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
--- /dev/null
+// aux-build:weird-hygiene.rs
+// check-pass
+// FIXME: This should actually error, see PR #73084
+
+#![feature(stmt_expr_attributes)]
+#![feature(proc_macro_hygiene)]
+
+extern crate weird_hygiene;
+use weird_hygiene::*;
+
+macro_rules! other {
+ ($tokens:expr) => {
+ macro_rules! call_it {
+ ($outer_ident:ident) => {
+ macro_rules! inner {
+ () => {
+ $outer_ident;
+ }
+ }
+ }
+ }
+
+ #[derive(WeirdDerive)]
+ enum MyEnum {
+ Value = (stringify!($tokens + hidden_ident), 1).1
+ }
+
+ inner!();
+ }
+}
+
+macro_rules! invoke_it {
+ ($token:expr) => {
+ #[recollect_attr] {
+ $token;
+ hidden_ident
+ }
+ }
+}
+
+fn main() {
+ // `other` and `invoke_it` are both macro_rules! macros,
+ // so it should be impossible for them to ever see `hidden_ident`,
+ // even if they invoke a proc macro.
+ let hidden_ident = "Hello1";
+ other!(50);
+ invoke_it!(25);
+}
--- /dev/null
+type Range = std::ops::Range<usize>;
+
+fn demo(r: &Range) {
+ println!("{:?}", r);
+}
+
+fn tell(x: usize) -> usize {
+ x
+}
+
+fn main() {
+ demo(tell(1)..tell(10));
+ //~^ ERROR mismatched types
+ demo(1..10);
+ //~^ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-73553-misinterp-range-literal.rs:12:10
+ |
+LL | demo(tell(1)..tell(10));
+ | ^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::Range`
+ | help: consider borrowing here: `&(tell(1)..tell(10))`
+ |
+ = note: expected reference `&std::ops::Range<usize>`
+ found struct `std::ops::Range<usize>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-73553-misinterp-range-literal.rs:14:10
+ |
+LL | demo(1..10);
+ | ^^^^^
+ | |
+ | expected reference, found struct `std::ops::Range`
+ | help: consider borrowing here: `&(1..10)`
+ |
+ = note: expected reference `&std::ops::Range<usize>`
+ found struct `std::ops::Range<{integer}>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::<S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>> - shim(Some(S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>))`
+ --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ |
+LL | / pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+LL | | // Code here does not matter - this is replaced by the
+LL | | // real drop glue by the compiler.
+LL | | drop_in_place(to_drop)
+LL | | }
+ | |_^
+ |
+note: `std::intrinsics::drop_in_place` defined here
+ --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ |
+LL | / pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+LL | | // Code here does not matter - this is replaced by the
+LL | | // real drop glue by the compiler.
+LL | | drop_in_place(to_drop)
+LL | | }
+ | |_^
error: aborting due to previous error
self.head * other.head + self.tail.dot(other.tail)
}
}
-fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize { //~ ERROR recursion limit
+fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
match n { 0 => {first.dot(second)}
- // FIXME(#4287) Error message should be here. It should be
- // a type error to instantiate `test` at a type other than T.
_ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
+ //~^ ERROR recursion limit
}
}
pub fn main() {
error: reached the recursion limit while instantiating `test::<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Nil>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+ --> $DIR/recursion.rs:17:11
+ |
+LL | _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `test` defined here
--> $DIR/recursion.rs:15:1
|
LL | / fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
LL | | match n { 0 => {first.dot(second)}
-LL | | // FIXME(#4287) Error message should be here. It should be
-LL | | // a type error to instantiate `test` at a type other than T.
LL | | _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
+LL | |
LL | | }
LL | | }
| |_^
| ^ value used here after partial move
|
= note: move occurs because value has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `x.0.0`
+ |
+LL | (Some(ref y), ()) => {},
+ | ^^^
error: aborting due to 3 previous errors
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:5
+ |
+LL | want_G(baz);
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
// Given 'cx, return 'cx
type F = for<'cx> fn(&'cx S) -> &'cx S;
-fn want_F(f: F) { }
+fn want_F(f: F) {}
// Given anything, return 'static
type G = for<'cx> fn(&'cx S) -> &'static S;
-fn want_G(f: G) { }
+fn want_G(f: G) {}
// Should meet both.
fn foo(x: &S) -> &'static S {
}
// Should meet both.
-fn bar<'a,'b>(x: &'a S) -> &'b S {
+fn bar<'a, 'b>(x: &'a S) -> &'b S {
panic!()
}
fn supply_F() {
want_F(foo);
- want_F(bar); //~ ERROR mismatched types
+ want_F(bar);
want_F(baz);
}
want_G(baz); //~ ERROR mismatched types
}
-pub fn main() {
-}
+pub fn main() {}
-error[E0308]: mismatched types
- --> $DIR/regions-fn-subtyping-return-static-fail.rs:40:12
- |
-LL | want_F(bar);
- | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
- |
- = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S`
- found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}`
-
error[E0308]: mismatched types
--> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12
|
LL | want_G(baz);
- | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
+ | ^^^ one type is more general than the other
|
= note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S`
- found fn item `for<'r> fn(&'r S) -> &'r S {baz}`
+ found fn pointer `for<'r> fn(&'r S) -> &'r S`
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
-error[E0308]: mismatched types
- --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43
+error: lifetime may not live long enough
+ --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:8:5
+ |
+LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | // Illegal now because there is no `'b:'a` declaration.
+LL | *x = *y;
+ | ^^^^^^^ assignment requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+ --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:14:5
+ |
+LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | a(x, y);
+ | ^^^^^^^ argument requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: higher-ranked subtype error
+ --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
|
LL | let _: fn(&mut &isize, &mut &isize) = a;
- | ---------------------------- ^ expected concrete lifetime, found bound lifetime parameter
- | |
- | expected due to this
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+ --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
|
- = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
- found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+LL | let _: fn(&mut &isize, &mut &isize) = a;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error: aborting due to 4 previous errors
-For more information about this error, try `rustc --explain E0308`.
--> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43
|
LL | let _: fn(&mut &isize, &mut &isize) = a;
- | ---------------------------- ^ expected concrete lifetime, found bound lifetime parameter
- | |
- | expected due to this
+ | ^ one type is more general than the other
|
= note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
- found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+ found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
error: aborting due to 3 previous errors
-error[E0308]: mismatched types
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56
+error: lifetime may not live long enough
+ --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:9:5
+ |
+LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | // Illegal now because there is no `'b:'a` declaration.
+LL | *x = *y;
+ | ^^^^^^^ assignment requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+ --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:5
+ |
+LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | a(x, y, z);
+ | ^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: higher-ranked subtype error
+ --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
|
LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
- | ----------------------------------------- ^ expected concrete lifetime, found bound lifetime parameter
- | |
- | expected due to this
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+ --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
|
- = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
- found fn item `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}`
+LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+ --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
+ |
+LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error: aborting due to 5 previous errors
-For more information about this error, try `rustc --explain E0308`.
--> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56
|
LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
- | ----------------------------------------- ^ expected concrete lifetime, found bound lifetime parameter
- | |
- | expected due to this
+ | ^ one type is more general than the other
|
= note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
- found fn item `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}`
+ found fn pointer `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)`
error: aborting due to 4 previous errors
-error[E0621]: explicit lifetime required in the type of `v`
+error: lifetime may not live long enough
--> $DIR/region-object-lifetime-in-coercion.rs:8:12
|
LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
- | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+ | - let's call the lifetime of this reference `'1`
LL | let x: Box<dyn Foo + 'static> = Box::new(v);
- | ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
+ | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
-error[E0621]: explicit lifetime required in the type of `v`
- --> $DIR/region-object-lifetime-in-coercion.rs:14:5
+error: lifetime may not live long enough
+ --> $DIR/region-object-lifetime-in-coercion.rs:13:5
|
LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
- | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+ | - let's call the lifetime of this reference `'1`
LL | Box::new(v)
- | ^^^^^^^^^^^ lifetime `'static` required
+ | ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
error: lifetime may not live long enough
- --> $DIR/region-object-lifetime-in-coercion.rs:20:5
+ --> $DIR/region-object-lifetime-in-coercion.rs:19:5
|
LL | fn c(v: &[u8]) -> Box<dyn Foo> {
| - let's call the lifetime of this reference `'1`
| ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
error: lifetime may not live long enough
- --> $DIR/region-object-lifetime-in-coercion.rs:24:5
+ --> $DIR/region-object-lifetime-in-coercion.rs:23:5
|
LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
| -- -- lifetime `'b` defined here
error: aborting due to 4 previous errors
-For more information about this error, try `rustc --explain E0621`.
impl<'a> Foo for &'a [u8] {}
fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
- let x: Box<dyn Foo + 'static> = Box::new(v);
- //~^ ERROR explicit lifetime required in the type of `v` [E0621]
+ let x: Box<dyn Foo + 'static> = Box::new(v); //~ ERROR cannot infer an appropriate lifetime
x
}
fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
- Box::new(v) //~ ERROR explicit lifetime required in the type of `v` [E0621]
+ Box::new(v) //~ ERROR cannot infer an appropriate lifetime
}
fn c(v: &[u8]) -> Box<dyn Foo> {
-error[E0621]: explicit lifetime required in the type of `v`
- --> $DIR/region-object-lifetime-in-coercion.rs:8:37
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/region-object-lifetime-in-coercion.rs:8:46
|
LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
- | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+ | ----- this data with an anonymous lifetime `'_`...
LL | let x: Box<dyn Foo + 'static> = Box::new(v);
- | ^^^^^^^^^^^ lifetime `'static` required
+ | ^ ...is captured here, requiring it to live as long as `'static`
+ |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+ |
+LL | fn a(v: &[u8]) -> Box<dyn Foo + '_> {
+ | ^^
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> {
+ | ^^^^^^^^^^^^^
-error[E0621]: explicit lifetime required in the type of `v`
- --> $DIR/region-object-lifetime-in-coercion.rs:14:5
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/region-object-lifetime-in-coercion.rs:13:14
|
LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
- | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+ | ----- this data with an anonymous lifetime `'_`...
LL | Box::new(v)
- | ^^^^^^^^^^^ lifetime `'static` required
+ | ^ ...is captured here, requiring it to live as long as `'static`
+ |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+ |
+LL | fn b(v: &[u8]) -> Box<dyn Foo + '_> {
+ | ^^
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> {
+ | ^^^^^^^^^^^^^
-error: cannot infer an appropriate lifetime
- --> $DIR/region-object-lifetime-in-coercion.rs:20:14
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/region-object-lifetime-in-coercion.rs:19:14
|
LL | fn c(v: &[u8]) -> Box<dyn Foo> {
- | ----- data with this lifetime...
+ | ----- this data with an anonymous lifetime `'_`...
...
LL | Box::new(v)
- | ---------^-
- | | |
- | | ...and is captured here
- | ...is required to be `'static` by this...
+ | ^ ...is captured here, requiring it to live as long as `'static`
|
-help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 17:1
+help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound
|
LL | fn c(v: &[u8]) -> Box<dyn Foo + '_> {
| ^^^^
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
- --> $DIR/region-object-lifetime-in-coercion.rs:24:14
+ --> $DIR/region-object-lifetime-in-coercion.rs:23:14
|
LL | Box::new(v)
| ^
|
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 23:6...
- --> $DIR/region-object-lifetime-in-coercion.rs:23:6
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:6...
+ --> $DIR/region-object-lifetime-in-coercion.rs:22:6
|
LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
| ^^
note: ...so that the expression is assignable
- --> $DIR/region-object-lifetime-in-coercion.rs:24:14
+ --> $DIR/region-object-lifetime-in-coercion.rs:23:14
|
LL | Box::new(v)
| ^
= note: expected `&[u8]`
found `&'a [u8]`
-note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 23:9...
- --> $DIR/region-object-lifetime-in-coercion.rs:23:9
+note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 22:9...
+ --> $DIR/region-object-lifetime-in-coercion.rs:22:9
|
LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
| ^^
note: ...so that the expression is assignable
- --> $DIR/region-object-lifetime-in-coercion.rs:24:5
+ --> $DIR/region-object-lifetime-in-coercion.rs:23:5
|
LL | Box::new(v)
| ^^^^^^^^^^^
error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0495, E0621.
+Some errors have detailed explanations: E0495, E0759.
For more information about an error, try `rustc --explain E0495`.
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+error[E0759]: cannot infer an appropriate lifetime
--> $DIR/regions-close-object-into-object-2.rs:10:11
|
+LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
+ | ------------------ this data with lifetime `'a`...
LL | box B(&*v) as Box<dyn X>
- | ^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:6...
- --> $DIR/regions-close-object-into-object-2.rs:9:6
+ | ^^^ ...is captured here, requiring it to live as long as `'static`
|
-LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
- | ^^
-note: ...so that the type `(dyn A<T> + 'a)` is not borrowed for too long
- --> $DIR/regions-close-object-into-object-2.rs:10:11
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
|
-LL | box B(&*v) as Box<dyn X>
- | ^^^
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the expression is assignable
- --> $DIR/regions-close-object-into-object-2.rs:10:5
+LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'a> {
+ | ^^
+help: alternatively, add an explicit `'static` bound to this reference
|
-LL | box B(&*v) as Box<dyn X>
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- = note: expected `std::boxed::Box<(dyn X + 'static)>`
- found `std::boxed::Box<dyn X>`
+LL | fn g<'a, T: 'static>(v: std::boxed::Box<(dyn A<T> + 'static)>) -> Box<dyn X + 'static> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+error[E0759]: cannot infer an appropriate lifetime
--> $DIR/regions-close-object-into-object-4.rs:10:11
|
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+ | ---------------- this data with lifetime `'a`...
LL | box B(&*v) as Box<dyn X>
- | ^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:6...
- --> $DIR/regions-close-object-into-object-4.rs:9:6
+ | ^^^ ...is captured here, requiring it to live as long as `'static`
|
-LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
- | ^^
-note: ...so that the type `(dyn A<U> + 'a)` is not borrowed for too long
- --> $DIR/regions-close-object-into-object-4.rs:10:11
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
|
-LL | box B(&*v) as Box<dyn X>
- | ^^^
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the expression is assignable
- --> $DIR/regions-close-object-into-object-4.rs:10:5
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'a> {
+ | ^^
+help: alternatively, add an explicit `'static` bound to this reference
|
-LL | box B(&*v) as Box<dyn X>
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- = note: expected `std::boxed::Box<(dyn X + 'static)>`
- found `std::boxed::Box<dyn X>`
+LL | fn i<'a, T, U>(v: std::boxed::Box<(dyn A<U> + 'static)>) -> Box<dyn X + 'static> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
// *ANY* lifetime and returns a reference with the 'static lifetime.
// This can safely be considered to be an instance of `F` because all
// lifetimes are sublifetimes of 'static.
+//
+// check-pass
#![allow(dead_code)]
#![allow(unused_variables)]
// Given 'cx, return 'cx
type F = for<'cx> fn(&'cx S) -> &'cx S;
-fn want_F(f: F) { }
+fn want_F(f: F) {}
// Given anything, return 'static
type G = for<'cx> fn(&'cx S) -> &'static S;
-fn want_G(f: G) { }
+fn want_G(f: G) {}
// Should meet both.
fn foo(x: &S) -> &'static S {
}
// Should meet both.
-fn bar<'a,'b>(x: &'a S) -> &'b S {
+fn bar<'a, 'b>(x: &'a S) -> &'b S {
panic!()
}
fn supply_F() {
want_F(foo);
- want_F(bar); //~ ERROR mismatched types
+ want_F(bar);
want_F(baz);
}
-pub fn main() {
-}
+pub fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/regions-fn-subtyping-return-static.rs:41:12
- |
-LL | want_F(bar);
- | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
- |
- = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S`
- found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
-error[E0308]: mismatched types
- --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43
+error: lifetime may not live long enough
+ --> $DIR/regions-lifetime-bounds-on-fns.rs:8:5
+ |
+LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | // Illegal now because there is no `'b:'a` declaration.
+LL | *x = *y;
+ | ^^^^^^^ assignment requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+ --> $DIR/regions-lifetime-bounds-on-fns.rs:14:5
+ |
+LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | a(x, y);
+ | ^^^^^^^ argument requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: higher-ranked subtype error
+ --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
|
LL | let _: fn(&mut &isize, &mut &isize) = a;
- | ---------------------------- ^ expected concrete lifetime, found bound lifetime parameter
- | |
- | expected due to this
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+ --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
|
- = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
- found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+LL | let _: fn(&mut &isize, &mut &isize) = a;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error: aborting due to 4 previous errors
-For more information about this error, try `rustc --explain E0308`.
--> $DIR/regions-lifetime-bounds-on-fns.rs:20:43
|
LL | let _: fn(&mut &isize, &mut &isize) = a;
- | ---------------------------- ^ expected concrete lifetime, found bound lifetime parameter
- | |
- | expected due to this
+ | ^ one type is more general than the other
|
= note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
- found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+ found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
error: aborting due to 3 previous errors
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/regions-proc-bound-capture.rs:9:5
+ |
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+ | - let's call the lifetime of this reference `'1`
+LL | // This is illegal, because the region bound on `proc` is 'static.
+LL | Box::new(move || { *x })
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+
+error: aborting due to previous error
+
Box::new(move|| { *x })
}
-fn static_proc(x: &isize) -> Box<dyn FnMut()->(isize) + 'static> {
+fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
// This is illegal, because the region bound on `proc` is 'static.
- Box::new(move|| { *x }) //~ ERROR explicit lifetime required in the type of `x` [E0621]
+ Box::new(move || { *x }) //~ ERROR cannot infer an appropriate lifetime
}
fn main() { }
-error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/regions-proc-bound-capture.rs:9:5
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/regions-proc-bound-capture.rs:9:14
|
-LL | fn static_proc(x: &isize) -> Box<dyn FnMut()->(isize) + 'static> {
- | ------ help: add explicit lifetime `'static` to the type of `x`: `&'static isize`
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+ | ------ this data with an anonymous lifetime `'_`...
LL | // This is illegal, because the region bound on `proc` is 'static.
-LL | Box::new(move|| { *x })
- | ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
+LL | Box::new(move || { *x })
+ | ^^^^^^^^^^^^^^ ...is captured here, requiring it to live as long as `'static`
+ |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
+ |
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + '_> {
+ | ^^
+help: alternatively, add an explicit `'static` bound to this reference
+ |
+LL | fn static_proc(x: &'static isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+ | ^^^^^^^^^^^^^^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0621`.
+For more information about this error, try `rustc --explain E0759`.
|
LL | let f = [0; -4_isize];
| ^^^^^^^^ expected `usize`, found `isize`
+ |
+ = note: `-4_isize` cannot fit into type `usize`
error[E0308]: mismatched types
--> $DIR/repeat_count.rs:22:23
|
LL | let f = [0_usize; -1_isize];
| ^^^^^^^^ expected `usize`, found `isize`
+ |
+ = note: `-1_isize` cannot fit into type `usize`
error[E0308]: mismatched types
--> $DIR/repeat_count.rs:25:17
|
LL | use mul2::Mul;
|
-LL | use mul3::Mul;
- |
-LL | use mul4::Mul;
+LL | use std::ops::Mul;
|
- and 2 other candidates
error[E0405]: cannot find trait `ThisTraitReallyDoesntExistInAnyModuleReally` in this scope
--> $DIR/issue-21221-1.rs:63:6
LL | impl T for Foo { }
| ^ not found in this scope
|
-help: consider importing this trait
+help: consider importing one of these items
+ |
+LL | use baz::T;
|
LL | use foo::bar::T;
|
| ^
help: consider importing this enum
|
-LL | use m::n::Z;
+LL | use m::Z;
|
error[E0423]: expected value, found enum `m::n::Z`
| ^
help: consider importing this enum
|
-LL | use m::n::Z;
+LL | use m::Z;
|
error[E0412]: cannot find type `Z` in this scope
| ^
help: consider importing this enum
|
-LL | use m::n::Z;
+LL | use m::Z;
|
error[E0423]: expected value, found struct variant `m::n::Z::Struct`
| ^
help: consider importing this enum
|
-LL | use m::n::Z;
+LL | use m::Z;
|
error[E0603]: enum `Z` is private
fn main() {
[(); return match 0 { n => n }];
//~^ ERROR: return statement outside of function body
- //~| ERROR: `match` is not allowed in a `const`
[(); return match 0 { 0 => 0 }];
//~^ ERROR: return statement outside of function body
- //~| ERROR: `match` is not allowed in a `const`
[(); return match () { 'a' => 0, _ => 0 }];
//~^ ERROR: return statement outside of function body
- //~| ERROR: `match` is not allowed in a `const`
}
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/return-match-array-const.rs:2:17
- |
-LL | [(); return match 0 { n => n }];
- | ^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/return-match-array-const.rs:6:17
- |
-LL | [(); return match 0 { 0 => 0 }];
- | ^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/return-match-array-const.rs:10:17
- |
-LL | [(); return match () { 'a' => 0, _ => 0 }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
error[E0572]: return statement outside of function body
--> $DIR/return-match-array-const.rs:2:10
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0572]: return statement outside of function body
- --> $DIR/return-match-array-const.rs:6:10
+ --> $DIR/return-match-array-const.rs:5:10
|
LL | [(); return match 0 { 0 => 0 }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0572]: return statement outside of function body
- --> $DIR/return-match-array-const.rs:10:10
+ --> $DIR/return-match-array-const.rs:8:10
|
LL | [(); return match () { 'a' => 0, _ => 0 }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0572, E0658.
-For more information about an error, try `rustc --explain E0572`.
+For more information about this error, try `rustc --explain E0572`.
--- /dev/null
+#![feature(non_ascii_idents)]
+
+extern crate ьаг; //~ ERROR cannot load a crate with a non-ascii name `ьаг`
+//~| ERROR can't find crate for `ьаг`
+
+fn main() {}
--- /dev/null
+error: cannot load a crate with a non-ascii name `ьаг`
+ --> $DIR/crate_name_nonascii_forbidden-1.rs:3:1
+ |
+LL | extern crate ьаг;
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0463]: can't find crate for `ьаг`
+ --> $DIR/crate_name_nonascii_forbidden-1.rs:3:1
+ |
+LL | extern crate ьаг;
+ | ^^^^^^^^^^^^^^^^^ can't find crate
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0463`.
--- /dev/null
+// compile-flags:--extern му_сгате
+// edition:2018
+#![feature(non_ascii_idents)]
+
+use му_сгате::baz; //~ ERROR cannot load a crate with a non-ascii name `му_сгате`
+ //~| can't find crate for `му_сгате`
+
+
+fn main() {}
--- /dev/null
+error: cannot load a crate with a non-ascii name `му_сгате`
+ --> $DIR/crate_name_nonascii_forbidden-2.rs:5:5
+ |
+LL | use му_сгате::baz;
+ | ^^^^^^^^
+
+error[E0463]: can't find crate for `му_сгате`
+ --> $DIR/crate_name_nonascii_forbidden-2.rs:5:5
+ |
+LL | use му_сгате::baz;
+ | ^^^^^^^^ can't find crate
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0463`.
if let A::<{
true && let 1 = 1 //~ ERROR `let` expressions are not supported here
- //~| ERROR `match` is not allowed in a `const`
}>::O = 5 {}
while let A::<{
true && let 1 = 1 //~ ERROR `let` expressions are not supported here
- //~| ERROR `match` is not allowed in a `const`
}>::O = 5 {}
if A::<{
true && let 1 = 1 //~ ERROR `let` expressions are not supported here
- //~| ERROR `match` is not allowed in a `const`
}>::O == 5 {}
// In the cases above we have `ExprKind::Block` to help us out.
error: expected one of `,` or `>`, found `&&`
- --> $DIR/disallowed-positions.rs:239:14
+ --> $DIR/disallowed-positions.rs:236:14
|
LL | true && let 1 = 1
| ^^ expected one of `,` or `>`
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:223:17
+ --> $DIR/disallowed-positions.rs:222:17
|
LL | true && let 1 = 1
| ^^^^^^^^^
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:228:17
+ --> $DIR/disallowed-positions.rs:226:17
|
LL | true && let 1 = 1
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/disallowed-positions.rs:218:17
- |
-LL | true && let 1 = 1
- | ^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/disallowed-positions.rs:223:17
- |
-LL | true && let 1 = 1
- | ^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const`
- --> $DIR/disallowed-positions.rs:228:17
- |
-LL | true && let 1 = 1
- | ^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:32:8
|
= help: the trait `std::ops::Try` is not implemented for `{integer}`
= note: required by `std::ops::Try::into_result`
-error: aborting due to 106 previous errors; 2 warnings emitted
+error: aborting due to 103 previous errors; 2 warnings emitted
-Some errors have detailed explanations: E0277, E0308, E0600, E0614, E0658.
+Some errors have detailed explanations: E0277, E0308, E0600, E0614.
For more information about an error, try `rustc --explain E0277`.
#![allow(incomplete_features)]
pub trait MyTrait {
- fn method(&self);
+ fn method(&self) -> Option<()>;
}
impl const MyTrait for () {
- fn method(&self) {
- match *self {} //~ ERROR `match` is not allowed in a `const fn`
+ fn method(&self) -> Option<()> {
+ Some(())?; //~ ERROR `?` is not allowed in a `const fn`
+ None
}
}
-error[E0658]: `match` is not allowed in a `const fn`
+error[E0744]: `?` is not allowed in a `const fn`
--> $DIR/hir-const-check.rs:12:9
|
-LL | match *self {}
- | ^^^^^^^^^^^^^^
- |
- = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
- = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+LL | Some(())?;
+ | ^^^^^^^^^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0744`.
--- /dev/null
+error[E0277]: `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
+ --> $DIR/rfc1623.rs:21:1
+ |
+LL | / static SOME_STRUCT: &SomeStruct = &SomeStruct {
+LL | | foo: &Foo { bools: &[false, true] },
+LL | | bar: &Bar { bools: &[true, true] },
+LL | | f: &id,
+LL | |
+LL | | };
+ | |__^ `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
+ |
+ = help: within `&SomeStruct`, the trait `std::marker::Sync` is not implemented for `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
+ = note: required because it appears within the type `&dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
+ = note: required because it appears within the type `SomeStruct`
+ = note: required because it appears within the type `&SomeStruct`
+ = note: shared static variables must have a type that implements `Sync`
+
+error: higher-ranked subtype error
+ --> $DIR/rfc1623.rs:21:35
+ |
+LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
+ | ___________________________________^
+LL | | foo: &Foo { bools: &[false, true] },
+LL | | bar: &Bar { bools: &[true, true] },
+LL | | f: &id,
+LL | |
+LL | | };
+ | |_^
+
+error: higher-ranked subtype error
+ --> $DIR/rfc1623.rs:21:35
+ |
+LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
+ | ___________________________________^
+LL | | foo: &Foo { bools: &[false, true] },
+LL | | bar: &Bar { bools: &[true, true] },
+LL | | f: &id,
+LL | |
+LL | | };
+ | |_^
+
+error: higher-ranked subtype error
+ --> $DIR/rfc1623.rs:21:35
+ |
+LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
+ | ___________________________________^
+LL | | foo: &Foo { bools: &[false, true] },
+LL | | bar: &Bar { bools: &[true, true] },
+LL | | f: &id,
+LL | |
+LL | | };
+ | |_^
+
+error: higher-ranked subtype error
+ --> $DIR/rfc1623.rs:21:35
+ |
+LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
+ | ___________________________________^
+LL | | foo: &Foo { bools: &[false, true] },
+LL | | bar: &Bar { bools: &[true, true] },
+LL | | f: &id,
+LL | |
+LL | | };
+ | |_^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 =
&(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8);
-
struct SomeStruct<'x, 'y, 'z: 'x> {
foo: &'x Foo<'z>,
bar: &'x Bar<'z>,
- f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Bar<'b>,
+ f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>,
}
fn id<T>(t: T) -> T {
t
}
-static SOME_STRUCT: &SomeStruct = SomeStruct { //~ ERROR mismatched types
+static SOME_STRUCT: &SomeStruct = &SomeStruct {
foo: &Foo { bools: &[false, true] },
bar: &Bar { bools: &[true, true] },
f: &id,
- //~^ ERROR type mismatch in function arguments
- //~| ERROR type mismatch resolving
+ //~^ ERROR mismatched types
};
// very simple test for a 'static static with default lifetime
error[E0308]: mismatched types
- --> $DIR/rfc1623.rs:22:35
- |
-LL | static SOME_STRUCT: &SomeStruct = SomeStruct {
- | ___________________________________^
-LL | | foo: &Foo { bools: &[false, true] },
-LL | | bar: &Bar { bools: &[true, true] },
-LL | | f: &id,
-LL | |
-LL | |
-LL | | };
- | |_^ expected `&SomeStruct<'static, 'static, 'static>`, found struct `SomeStruct`
- |
-help: consider borrowing here
- |
-LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
-LL | foo: &Foo { bools: &[false, true] },
-LL | bar: &Bar { bools: &[true, true] },
-LL | f: &id,
-LL |
-LL |
- ...
-
-error[E0631]: type mismatch in function arguments
- --> $DIR/rfc1623.rs:25:8
- |
-LL | fn id<T>(t: T) -> T {
- | ------------------- found signature of `fn(_) -> _`
-...
-LL | f: &id,
- | ^^^ expected signature of `for<'a, 'b> fn(&'a Foo<'b>) -> _`
- |
- = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
-
-error[E0271]: type mismatch resolving `for<'a, 'b> <fn(_) -> _ {id::<_>} as std::ops::FnOnce<(&'a Foo<'b>,)>>::Output == &'a Foo<'b>`
- --> $DIR/rfc1623.rs:25:8
+ --> $DIR/rfc1623.rs:24:8
|
LL | f: &id,
- | ^^^ expected bound lifetime parameter 'a, found concrete lifetime
+ | ^^^ one type is more general than the other
|
- = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
+ = note: expected type `std::ops::FnOnce<(&'a Foo<'b>,)>`
+ found type `std::ops::FnOnce<(&Foo<'_>,)>`
-error: aborting due to 3 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0271, E0308, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
// needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
//
// compile-flags: -Z sanitizer=address -O -g
//
// needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
//
// compile-flags: -Z sanitizer=address -O
//
// the `#[cfg(sanitize = "option")]` attribute is configured.
// needs-sanitizer-support
-// only-linux
-// only-x86_64
+// needs-sanitizer-address
+// needs-sanitizer-leak
+// needs-sanitizer-memory
+// needs-sanitizer-thread
// check-pass
// revisions: address leak memory thread
//[address]compile-flags: -Zsanitizer=address --cfg address
--- /dev/null
+// compile-flags: -Z sanitizer=address -Z sanitizer=memory --target x86_64-unknown-linux-gnu
+// error-pattern: error: `-Zsanitizer=address` is incompatible with `-Zsanitizer=memory`
+
+#![feature(no_core)]
+#![no_core]
+#![no_main]
--- /dev/null
+error: `-Zsanitizer=address` is incompatible with `-Zsanitizer=memory`
+
+error: aborting due to previous error
+
// miscompilation which was subsequently detected by AddressSanitizer as UB.
//
// needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
//
// compile-flags: -Copt-level=0 -Zsanitizer=address
// run-pass
// needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-leak
//
// compile-flags: -Z sanitizer=leak -O
//
// needs-sanitizer-support
-// only-linux
-// only-x86_64
+// needs-sanitizer-memory
//
// compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
//
//
// min-llvm-version 9.0
// needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
//
// no-prefer-dynamic
// revisions: opt0 opt1
// would occasionally fail, making test flaky.
//
// needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-thread
//
// compile-flags: -Z sanitizer=thread -O
//
-// ignore-tidy-linelength
// compile-flags: -Z sanitizer=leak --target i686-unknown-linux-gnu
-// error-pattern: error: LeakSanitizer only works with the `x86_64-unknown-linux-gnu` or `x86_64-apple-darwin` target
+// error-pattern: error: `-Zsanitizer=leak` only works with targets:
#![feature(no_core)]
#![no_core]
-error: LeakSanitizer only works with the `x86_64-unknown-linux-gnu` or `x86_64-apple-darwin` target
+error: `-Zsanitizer=leak` only works with targets: aarch64-unknown-linux-gnu, x86_64-apple-darwin, x86_64-unknown-linux-gnu
error: aborting due to previous error
// needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
//
// compile-flags: -Zsanitizer=address
// run-fail
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16
|
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
- | ^^^^ ---------- ---------- ...and required to be `'static` by this
+ | ^^^^ ---------- ---------- ...and is required to live as long as `'static` here
| | |
- | | data with this lifetime...
+ | | this data with an anonymous lifetime `'_`...
| ...is captured here...
+ |
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+ |
+LL | async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
+ | ^^^^
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0759`.
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44
|
LL | fn f(self: Pin<&Self>) -> impl Clone { self }
- | ---------- ---------- ^^^^ ...and is captured here
- | | |
- | | ...is required to be `'static` by this...
- | data with this lifetime...
+ | ---------- ^^^^ ...is captured here...
+ | |
+ | this data with an anonymous lifetime `'_`...
|
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the method body at 6:5
+note: ...and is required to live as long as `'static` here
+ --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:31
+ |
+LL | fn f(self: Pin<&Self>) -> impl Clone { self }
+ | ^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
|
LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
| ^^^^
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0759`.
+++ /dev/null
-#!/usr/bin/env rustx
-
-// run-pass
-
-pub fn main() { println!("Hello World"); }
--> $DIR/E0493.rs:17:17
|
LL | const F : Foo = (Foo { a : 0 }, Foo { a : 1 }).1;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - value is dropped here
+ | |
+ | constants cannot evaluate destructors
error: aborting due to previous error
// Make sure we don't crash with a cycle error during coherence.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Trait<T> {
type Assoc;
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/assoc-ty-graph-cycle.rs:5:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// aux-build:cross_crates_defaults.rs
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
extern crate cross_crates_defaults;
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/cross-crate-defaults.rs:5:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
--- /dev/null
+// Check that we check that default associated types satisfy the required
+// bounds on them.
+
+#![feature(specialization)]
+//~^ WARNING `specialization` is incomplete
+
+trait X {
+ type U: Clone;
+ fn unsafe_clone(&self, x: Option<&Self::U>) {
+ x.cloned();
+ }
+}
+
+// We cannot normalize `<T as X>::U` to `str` here, because the default could
+// be overridden. The error here must therefore be found by a method other than
+// normalization.
+impl<T> X for T {
+ default type U = str;
+ //~^ ERROR the trait bound `str: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+ 1.unsafe_clone(None);
+}
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/deafult-associated-type-bound-1.rs:4:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+error[E0277]: the trait bound `str: std::clone::Clone` is not satisfied
+ --> $DIR/deafult-associated-type-bound-1.rs:18:5
+ |
+LL | type U: Clone;
+ | -------------- required by `X::U`
+...
+LL | default type U = str;
+ | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `str`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// Check that generic predicates are also checked for default associated types.
+#![feature(specialization)]
+//~^ WARNING `specialization` is incomplete
+
+trait X<T> {
+ type U: PartialEq<T>;
+ fn unsafe_compare(x: Option<Self::U>, y: Option<T>) {
+ match (x, y) {
+ (Some(a), Some(b)) => a == b,
+ _ => false,
+ };
+ }
+}
+
+impl<B: 'static, T> X<B> for T {
+ default type U = &'static B;
+ //~^ ERROR can't compare `&'static B` with `B`
+}
+
+pub fn main() {
+ <i32 as X<i32>>::unsafe_compare(None, None);
+}
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/deafult-associated-type-bound-2.rs:2:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+error[E0277]: can't compare `&'static B` with `B`
+ --> $DIR/deafult-associated-type-bound-2.rs:16:5
+ |
+LL | type U: PartialEq<T>;
+ | --------------------- required by `X::U`
+...
+LL | default type U = &'static B;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B`
+ |
+ = help: the trait `std::cmp::PartialEq<B>` is not implemented for `&'static B`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// Check that default generics associated types are validated.
+
+#![feature(specialization)]
+#![feature(generic_associated_types)]
+//~^^ WARNING `specialization` is incomplete
+//~^^ WARNING the feature `generic_associated_types` is incomplete
+
+trait X {
+ type U<'a>: PartialEq<&'a Self>;
+ fn unsafe_compare<'b>(x: Option<Self::U<'b>>, y: Option<&'b Self>) {
+ match (x, y) {
+ (Some(a), Some(b)) => a == b,
+ _ => false,
+ };
+ }
+}
+
+impl<T: 'static> X for T {
+ default type U<'a> = &'a T;
+ //~^ ERROR can't compare `T` with `T`
+}
+
+struct NotComparable;
+
+pub fn main() {
+ <NotComparable as X>::unsafe_compare(None, None);
+}
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/deafult-generic-associated-type-bound.rs:3:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/deafult-generic-associated-type-bound.rs:4:12
+ |
+LL | #![feature(generic_associated_types)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: can't compare `T` with `T`
+ --> $DIR/deafult-generic-associated-type-bound.rs:19:5
+ |
+LL | type U<'a>: PartialEq<&'a Self>;
+ | -------------------------------- required by `X::U`
+...
+LL | default type U<'a> = &'a T;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T`
+ |
+ = help: the trait `std::cmp::PartialEq` is not implemented for `T`
+ = note: required because of the requirements on the impl of `std::cmp::PartialEq` for `&'a T`
+help: consider further restricting this bound
+ |
+LL | impl<T: 'static + std::cmp::PartialEq> X for T {
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0277`.
// aux-build:go_trait.rs
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
extern crate go_trait;
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/allowed-cross-crate.rs:8:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// Test that you can list the more specific impl before the more general one.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Foo {
type Out;
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/out-of-order.rs:5:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// projections involve specialization, so long as the associated type is
// provided by the most specialized impl.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Assoc {
type Output;
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/overlap-projection.rs:7:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// run-pass
#![allow(dead_code)]
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Make sure we *can* project non-defaulted associated types
// cf compile-fail/specialization-default-projection.rs
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/projection.rs:4:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Check a number of scenarios in which one impl tries to override another,
// without correctly using `default`.
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-no-default.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
--> $DIR/specialization-no-default.rs:20:5
|
|
= note: to specialize, `redundant` in the parent `impl` must be marked `default`
-error: aborting due to 5 previous errors
+error: aborting due to 5 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0520`.
// Tests that we can combine a default impl that supplies one method with a
// full impl that supplies the other, and they can invoke one another.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Foo {
fn foo_one(&self) -> &'static str;
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-trait-item-not-implemented-rpass.rs:6:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// Tests that default impls do not have to supply all items but regular impls do.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Foo {
fn foo_one(&self) -> &'static str;
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-trait-item-not-implemented.rs:3:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0046]: not all trait items implemented, missing: `foo_two`
--> $DIR/specialization-trait-item-not-implemented.rs:18:1
|
LL | impl Foo for MyStruct {}
| ^^^^^^^^^^^^^^^^^^^^^ missing `foo_two` in implementation
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0046`.
// - default impls do not have to supply all items and
// - a default impl does not count as an impl (in this case, an incomplete default impl).
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Foo {
fn foo_one(&self) -> &'static str;
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-trait-not-implemented.rs:5:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0599]: no method named `foo_one` found for struct `MyStruct` in the current scope
--> $DIR/specialization-trait-not-implemented.rs:22:29
|
LL | trait Foo {
| ^^^^^^^^^
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0599`.
// Tests that a default impl still has to have a WF trait ref.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Foo<'a, T: Eq + 'a> { }
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-wfcheck.rs:3:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0277]: the trait bound `U: std::cmp::Eq` is not satisfied
--> $DIR/specialization-wfcheck.rs:7:17
|
LL | default impl<U: std::cmp::Eq> Foo<'static, U> for () {}
| ^^^^^^^^^^^^^^
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0277`.
#![feature(negative_impls)]
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
struct S;
struct Z;
|
= note: only trait implementations may be annotated with `default`
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/validation.rs:2:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error: impls of auto traits cannot be default
--> $DIR/validation.rs:9:21
|
LL | default impl !Tr for S {}
| ^^^^^^^ ^
-error: aborting due to 5 previous errors
+error: aborting due to 5 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0750`.
// check-pass
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
pub struct Cloned<I>(I);
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-36804.rs:2:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Regression test for a specialization-related ICE (#39448).
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-39448.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0275]: overflow evaluating the requirement `T: FromA<U>`
--> $DIR/issue-39448.rs:45:13
|
= note: required because of the requirements on the impl of `FromA<U>` for `T`
= note: required because of the requirements on the impl of `ToA<T>` for `U`
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0275`.
// check-pass
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Foo {
fn foo(&self);
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-39618.rs:7:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
--- /dev/null
+#![crate_type = "lib"]
+#![feature(specialization)]
+#![feature(unsize, coerce_unsized)]
+#![allow(incomplete_features)]
+
+use std::ops::CoerceUnsized;
+
+pub struct SmartassPtr<A: Smartass+?Sized>(A::Data);
+
+pub trait Smartass {
+ type Data;
+ type Data2: CoerceUnsized<*const [u8]>;
+}
+
+pub trait MaybeObjectSafe {}
+
+impl MaybeObjectSafe for () {}
+
+impl<T> Smartass for T {
+ type Data = <Self as Smartass>::Data2;
+ default type Data2 = ();
+ //~^ ERROR: the trait bound `(): std::ops::CoerceUnsized<*const [u8]>` is not satisfied
+}
+
+impl Smartass for () {
+ type Data2 = *const [u8; 1];
+}
+
+impl Smartass for dyn MaybeObjectSafe {
+ type Data = *const [u8];
+ type Data2 = *const [u8; 0];
+}
+
+impl<U: Smartass+?Sized, T: Smartass+?Sized> CoerceUnsized<SmartassPtr<T>> for SmartassPtr<U>
+ where <U as Smartass>::Data: std::ops::CoerceUnsized<<T as Smartass>::Data>
+{}
+
+pub fn conv(s: SmartassPtr<()>) -> SmartassPtr<dyn MaybeObjectSafe> {
+ s
+}
--- /dev/null
+error[E0277]: the trait bound `(): std::ops::CoerceUnsized<*const [u8]>` is not satisfied
+ --> $DIR/issue-44861.rs:21:5
+ |
+LL | type Data2: CoerceUnsized<*const [u8]>;
+ | --------------------------------------- required by `Smartass::Data2`
+...
+LL | default type Data2 = ();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::CoerceUnsized<*const [u8]>` is not implemented for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
// run-pass
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
pub trait Foo {
fn foo();
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-50452.rs:3:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Regression test for #52050: when inserting the blanket impl `I`
// into the tree, we had to replace the child node for `Foo`, which
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-52050.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0119]: conflicting implementations of trait `IntoPyDictPointer` for type `()`:
--> $DIR/issue-52050.rs:28:1
|
|
= note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0119`.
--- /dev/null
+#![feature(specialization)]
+#![allow(incomplete_features)]
+
+struct MyStruct {}
+
+trait MyTrait {
+ type MyType: Default;
+}
+
+impl MyTrait for i32 {
+ default type MyType = MyStruct;
+ //~^ ERROR: the trait bound `MyStruct: std::default::Default` is not satisfied
+}
+
+fn main() {
+ let _x: <i32 as MyTrait>::MyType = <i32 as MyTrait>::MyType::default();
+}
--- /dev/null
+error[E0277]: the trait bound `MyStruct: std::default::Default` is not satisfied
+ --> $DIR/issue-59435.rs:11:5
+ |
+LL | type MyType: Default;
+ | --------------------- required by `MyTrait::MyType`
+...
+LL | default type MyType = MyStruct;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::default::Default` is not implemented for `MyStruct`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
// check-pass
// edition:2018
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
fn main() {}
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-63716-parse-async.rs:7:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// check-pass
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-70442.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
#![feature(specialization, associated_type_defaults)]
+//~^ WARN the feature `specialization` is incomplete
// Test that attempting to override a non-default method or one not in the
// parent impl causes an error.
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/non-defaulted-item-fail.rs:1:12
+ |
+LL | #![feature(specialization, associated_type_defaults)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is not marked `default`
- --> $DIR/non-defaulted-item-fail.rs:29:5
+ --> $DIR/non-defaulted-item-fail.rs:30:5
|
LL | / impl<T> Foo for Box<T> {
LL | | type Ty = bool;
= note: to specialize, `Ty` in the parent `impl` must be marked `default`
error[E0520]: `CONST` specializes an item from a parent `impl`, but that item is not marked `default`
- --> $DIR/non-defaulted-item-fail.rs:31:5
+ --> $DIR/non-defaulted-item-fail.rs:32:5
|
LL | / impl<T> Foo for Box<T> {
LL | | type Ty = bool;
= note: to specialize, `CONST` in the parent `impl` must be marked `default`
error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
- --> $DIR/non-defaulted-item-fail.rs:33:5
+ --> $DIR/non-defaulted-item-fail.rs:34:5
|
LL | / impl<T> Foo for Box<T> {
LL | | type Ty = bool;
= note: to specialize, `foo` in the parent `impl` must be marked `default`
error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is not marked `default`
- --> $DIR/non-defaulted-item-fail.rs:45:5
+ --> $DIR/non-defaulted-item-fail.rs:46:5
|
LL | impl<T> Foo for Vec<T> {}
| ------------------------- parent `impl` is here
= note: to specialize, `Ty` in the parent `impl` must be marked `default`
error[E0520]: `CONST` specializes an item from a parent `impl`, but that item is not marked `default`
- --> $DIR/non-defaulted-item-fail.rs:47:5
+ --> $DIR/non-defaulted-item-fail.rs:48:5
|
LL | impl<T> Foo for Vec<T> {}
| ------------------------- parent `impl` is here
= note: to specialize, `CONST` in the parent `impl` must be marked `default`
error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
- --> $DIR/non-defaulted-item-fail.rs:49:5
+ --> $DIR/non-defaulted-item-fail.rs:50:5
|
LL | impl<T> Foo for Vec<T> {}
| ------------------------- parent `impl` is here
|
= note: to specialize, `foo` in the parent `impl` must be marked `default`
-error: aborting due to 6 previous errors
+error: aborting due to 6 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0520`.
// aux-build:go_trait.rs
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
extern crate go_trait;
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-allowed-cross-crate.rs:8:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// Test that non-method associated functions can be specialized
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Foo {
fn mk() -> Self;
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-assoc-fns.rs:5:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// run-pass
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Tests a variety of basic specialization scenarios and method
// dispatch for them.
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-basics.rs:3:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// aux-build:specialization_cross_crate.rs
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
extern crate specialization_cross_crate;
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-cross-crate.rs:5:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// run-pass
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Test that default methods are cascaded correctly
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-default-methods.rs:3:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Make sure we can't project defaulted associated types
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-default-projection.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0308]: mismatched types
--> $DIR/specialization-default-projection.rs:21:5
|
= help: consider constraining the associated type `<() as Foo>::Assoc` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-error: aborting due to 2 previous errors
+error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0308`.
// associated type in the impl defining it -- otherwise, what happens
// if it's overridden?
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Example {
type Output;
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-default-types.rs:5:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0308]: mismatched types
--> $DIR/specialization-default-types.rs:15:9
|
= help: consider constraining the associated type `<T as Example>::Output` to `std::boxed::Box<T>`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-error: aborting due to 2 previous errors
+error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0308`.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Check a number of scenarios in which one impl tries to override another,
// without correctly using `default`.
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-no-default.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
--> $DIR/specialization-no-default.rs:20:5
|
|
= note: to specialize, `redundant` in the parent `impl` must be marked `default`
-error: aborting due to 5 previous errors
+error: aborting due to 5 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0520`.
// run-pass
#![allow(dead_code)]
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Ensure that specialization works for impls defined directly on a projection
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-on-projection.rs:4:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// Test that you can list the more specific impl before the more general one.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Foo {
type Out;
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-out-of-order.rs:5:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
#![feature(negative_impls)]
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait MyTrait {}
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-overlap-negative.rs:2:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0751]: found both positive and negative implementation of trait `std::marker::Send` for type `TestType<_>`:
--> $DIR/specialization-overlap-negative.rs:9:1
|
LL | impl<T: MyTrait> !Send for TestType<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0751`.
// projections involve specialization, so long as the associated type is
// provided by the most specialized impl.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Assoc {
type Output;
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-overlap-projection.rs:7:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Foo { fn foo() {} }
impl<T: Clone> Foo for T {}
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-overlap.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0119]: conflicting implementations of trait `Foo` for type `std::vec::Vec<_>`:
--> $DIR/specialization-overlap.rs:5:1
|
LL | impl<T: Eq> Qux for T {}
| ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
-error: aborting due to 4 previous errors
+error: aborting due to 4 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0119`.
#![feature(optin_builtin_traits)]
#![feature(negative_impls)]
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
auto trait Foo {}
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-polarity.rs:5:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0751]: found both positive and negative implementation of trait `Foo` for type `u8`:
--> $DIR/specialization-polarity.rs:10:1
|
LL | impl Bar for u8 {}
| ^^^^^^^^^^^^^^^ positive implementation here
-error: aborting due to 2 previous errors
+error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0751`.
#![allow(dead_code)]
#![allow(unused_variables)]
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Regression test for ICE when combining specialized associated types and type
// aliases
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-projection-alias.rs:5:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// run-pass
#![allow(dead_code)]
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Make sure we *can* project non-defaulted associated types
// cf compile-fail/specialization-default-projection.rs
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-projection.rs:4:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// run-pass
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Test that you can specialize via an explicit trait hierarchy
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-super-traits.rs:3:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// run-pass
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Iterator {
fn next(&self);
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-translate-projections-with-lifetimes.rs:3:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// type parameters *and* rely on projections, and the type parameters are input
// types on the trait.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Trait<T> {
fn convert(&self) -> T;
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-translate-projections-with-params.rs:7:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
// Ensure that provided items are inherited properly even when impls vary in
// type parameters *and* rely on projections.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
use std::convert::Into;
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/specialization-translate-projections.rs:6:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
--> $DIR/static-drop-scope.rs:9:60
|
LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor);
- | ^^^^^^^^ statics cannot evaluate destructors
+ | ^^^^^^^^- value is dropped here
+ | |
+ | statics cannot evaluate destructors
error[E0716]: temporary value dropped while borrowed
--> $DIR/static-drop-scope.rs:9:60
--> $DIR/static-drop-scope.rs:13:59
|
LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor);
- | ^^^^^^^^ constants cannot evaluate destructors
+ | ^^^^^^^^- value is dropped here
+ | |
+ | constants cannot evaluate destructors
error[E0716]: temporary value dropped while borrowed
--> $DIR/static-drop-scope.rs:13:59
--> $DIR/static-drop-scope.rs:17:28
|
LL | static EARLY_DROP_S: i32 = (WithDtor, 0).1;
- | ^^^^^^^^^^^^^ statics cannot evaluate destructors
+ | ^^^^^^^^^^^^^ - value is dropped here
+ | |
+ | statics cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/static-drop-scope.rs:20:27
|
LL | const EARLY_DROP_C: i32 = (WithDtor, 0).1;
- | ^^^^^^^^^^^^^ constants cannot evaluate destructors
+ | ^^^^^^^^^^^^^ - value is dropped here
+ | |
+ | constants cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/static-drop-scope.rs:23:24
|
LL | const fn const_drop<T>(_: T) {}
- | ^ constant functions cannot evaluate destructors
+ | ^ - value is dropped here
+ | |
+ | constant functions cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/static-drop-scope.rs:27:5
|
LL | (x, ()).1
| ^^^^^^^ constant functions cannot evaluate destructors
+LL |
+LL | }
+ | - value is dropped here
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/static-drop-scope.rs:31:34
|
LL | const EARLY_DROP_C_OPTION: i32 = (Some(WithDtor), 0).1;
- | ^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors
+ | ^^^^^^^^^^^^^^^^^^^ - value is dropped here
+ | |
+ | constants cannot evaluate destructors
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/static-drop-scope.rs:36:43
|
LL | const EARLY_DROP_C_OPTION_CONSTANT: i32 = (HELPER, 0).1;
- | ^^^^^^^^^^^ constants cannot evaluate destructors
+ | ^^^^^^^^^^^ - value is dropped here
+ | |
+ | constants cannot evaluate destructors
error: aborting due to 10 previous errors
--- /dev/null
+trait Trait {
+ fn func1() -> Struct1<Self>; //~ ERROR E0277
+ fn func2<'a>() -> Struct2<'a, Self>; //~ ERROR E0277
+ fn func3() -> Struct3<Self>; //~ ERROR E0277
+ fn func4() -> Struct4<Self>; //~ ERROR E0277
+}
+
+struct Struct1<T>{
+ _t: std::marker::PhantomData<*const T>,
+}
+struct Struct2<'a, T>{
+ _t: &'a T,
+}
+struct Struct3<T>{
+ _t: T,
+}
+
+struct X<T>(T);
+
+struct Struct4<T>{
+ _t: X<T>,
+}
+
+struct Struct5<T: ?Sized>{
+ _t: X<T>, //~ ERROR E0277
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+ --> $DIR/adt-param-with-implicit-sized-bound.rs:25:5
+ |
+LL | struct X<T>(T);
+ | - required by this bound in `X`
+...
+LL | struct Struct5<T: ?Sized>{
+ | - this type parameter needs to be `std::marker::Sized`
+LL | _t: X<T>,
+ | ^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `T`
+ = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+ --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10
+ |
+LL | struct X<T>(T);
+ | ^ - ...if indirection was used here: `Box<T>`
+ | |
+ | this could be changed to `T: ?Sized`...
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+ --> $DIR/adt-param-with-implicit-sized-bound.rs:2:19
+ |
+LL | fn func1() -> Struct1<Self>;
+ | ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+...
+LL | struct Struct1<T>{
+ | - required by this bound in `Struct1`
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `Self`
+ = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider further restricting `Self`
+ |
+LL | fn func1() -> Struct1<Self> where Self: std::marker::Sized;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider relaxing the implicit `Sized` restriction
+ |
+LL | struct Struct1<T: ?Sized>{
+ | ^^^^^^^^
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+ --> $DIR/adt-param-with-implicit-sized-bound.rs:3:23
+ |
+LL | fn func2<'a>() -> Struct2<'a, Self>;
+ | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+...
+LL | struct Struct2<'a, T>{
+ | - required by this bound in `Struct2`
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `Self`
+ = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider further restricting `Self`
+ |
+LL | fn func2<'a>() -> Struct2<'a, Self> where Self: std::marker::Sized;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider relaxing the implicit `Sized` restriction
+ |
+LL | struct Struct2<'a, T: ?Sized>{
+ | ^^^^^^^^
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+ --> $DIR/adt-param-with-implicit-sized-bound.rs:4:19
+ |
+LL | fn func3() -> Struct3<Self>;
+ | ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+...
+LL | struct Struct3<T>{
+ | - required by this bound in `Struct3`
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `Self`
+ = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+ --> $DIR/adt-param-with-implicit-sized-bound.rs:14:16
+ |
+LL | struct Struct3<T>{
+ | ^ this could be changed to `T: ?Sized`...
+LL | _t: T,
+ | - ...if indirection was used here: `Box<T>`
+help: consider further restricting `Self`
+ |
+LL | fn func3() -> Struct3<Self> where Self: std::marker::Sized;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+ --> $DIR/adt-param-with-implicit-sized-bound.rs:5:19
+ |
+LL | fn func4() -> Struct4<Self>;
+ | ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+...
+LL | struct Struct4<T>{
+ | - required by this bound in `Struct4`
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `Self`
+ = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider further restricting `Self`
+ |
+LL | fn func4() -> Struct4<Self> where Self: std::marker::Sized;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider relaxing the implicit `Sized` restriction
+ |
+LL | struct Struct4<T: ?Sized>{
+ | ^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
-error[E0277]: the trait bound `fn() -> impl std::future::Future {foo}: std::future::Future` is not satisfied
+error[E0277]: `fn() -> impl std::future::Future {foo}` is not a future
--> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:10:9
|
LL | async fn foo() {}
| ----------------- required by this bound in `bar`
...
LL | bar(foo);
- | ^^^ the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}`
+ | ^^^ `fn() -> impl std::future::Future {foo}` is not a future
|
+ = help: the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}`
help: use parentheses to call the function
|
LL | bar(foo());
| ^^
-error[E0277]: the trait bound `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]: std::future::Future` is not satisfied
+error[E0277]: `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future
--> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:12:9
|
LL | fn bar(f: impl Future<Output=()>) {}
LL | let async_closure = async || ();
| -------- consider calling this closure
LL | bar(async_closure);
- | ^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]`
+ | ^^^^^^^^^^^^^ `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future
|
+ = help: the trait `std::future::Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]`
help: use parentheses to call the closure
|
LL | bar(async_closure());
fn main() {
let A = 3;
- //~^ ERROR refutable pattern in local binding: `i32::MIN..=1i32` and
+ //~^ ERROR refutable pattern in local binding: `i32::MIN..=1_i32` and
//~| interpreted as a constant pattern, not a new variable
//~| HELP introduce a variable instead
//~| SUGGESTION a_var
-error[E0005]: refutable pattern in local binding: `i32::MIN..=1i32` and `3i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
--> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9
|
LL | let A = 3;
--- /dev/null
+pub fn foo<T>(s: S<T>, t: S<T>) {
+ let _ = s == t; //~ ERROR binary operation `==` cannot be applied to type `S<T>`
+}
+
+struct S<T>(T);
+
+fn main() {}
--- /dev/null
+error[E0369]: binary operation `==` cannot be applied to type `S<T>`
+ --> $DIR/invalid-bin-op.rs:2:15
+ |
+LL | let _ = s == t;
+ | - ^^ - S<T>
+ | |
+ | S<T>
+ |
+ = note: the trait `std::cmp::PartialEq` is not implemented for `S<T>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0369`.
| |
| help: consider introducing lifetime `'a` here: `'a,`
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
--> $DIR/missing-lifetimes-in-signature.rs:19:5
|
LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
- | ------ ------------- ...is required to be `'static` by this...
- | |
- | data with this lifetime...
+ | ------ this data with an anonymous lifetime `'_`...
...
LL | / move || {
LL | | *dest = g.get();
LL | | }
- | |_____^ ...and is captured here
+ | |_____^ ...is captured here...
|
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 15:1
+note: ...and is required to live as long as `'static` here
+ --> $DIR/missing-lifetimes-in-signature.rs:15:37
+ |
+LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
+ | ^^^^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `dest`, you can add an explicit `'_` lifetime bound
|
LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
| ^^^^
error: aborting due to 7 previous errors
-Some errors have detailed explanations: E0261, E0309, E0621.
+Some errors have detailed explanations: E0261, E0309, E0621, E0759.
For more information about an error, try `rustc --explain E0261`.
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/trait-object-nested-in-impl-trait.rs:27:23
+ |
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+ | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+ | |
+ | let's call the lifetime of this reference `'1`
+ |
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
+ |
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+ --> $DIR/trait-object-nested-in-impl-trait.rs:39:9
+ |
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+ | - let's call the lifetime of this reference `'1`
+LL | / Iter {
+LL | | current: None,
+LL | | remaining: self.0.iter(),
+LL | | }
+ | |_________^ returning this value requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/trait-object-nested-in-impl-trait.rs:50:9
+ |
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+ | -- lifetime `'a` defined here
+LL | / Iter {
+LL | | current: None,
+LL | | remaining: self.0.iter(),
+LL | | }
+ | |_________^ returning this value requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/trait-object-nested-in-impl-trait.rs:60:30
+ |
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+ | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
+ | |
+ | lifetime `'a` defined here
+ |
+ = help: consider replacing `'a` with `'static`
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
+ |
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+trait Foo {}
+impl<'a, T: Foo> Foo for &'a T {}
+impl<T: Foo + ?Sized> Foo for Box<T> {}
+
+struct Iter<'a, T> {
+ current: Option<Box<dyn Foo + 'a>>,
+ remaining: T,
+}
+
+impl<'a, T> Iterator for Iter<'a, T>
+where
+ T: Iterator,
+ T::Item: Foo + 'a,
+{
+ type Item = Box<dyn Foo + 'a>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let result = self.current.take();
+ self.current = Box::new(self.remaining.next()).map(|f| Box::new(f) as _);
+ result
+ }
+}
+
+struct Bar(Vec<Box<dyn Foo>>);
+
+impl Bar {
+ fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+ Iter {
+ current: None,
+ remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+ }
+ }
+}
+
+struct Baz(Vec<Box<dyn Foo>>);
+
+impl Baz {
+ fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+ Iter {
+ current: None,
+ remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+ }
+ }
+}
+
+struct Bat(Vec<Box<dyn Foo>>);
+
+impl Bat {
+ fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+ Iter {
+ current: None,
+ remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+ }
+ }
+}
+
+struct Ban(Vec<Box<dyn Foo>>);
+
+impl Ban {
+ fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+ Iter {
+ current: None,
+ remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/trait-object-nested-in-impl-trait.rs:30:31
+ |
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+ | ----- this data with an anonymous lifetime `'_`...
+...
+LL | remaining: self.0.iter(),
+ | ------ ^^^^
+ | |
+ | ...is captured here...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/trait-object-nested-in-impl-trait.rs:27:23
+ |
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+ | ^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> {
+ | ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/trait-object-nested-in-impl-trait.rs:41:31
+ |
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+ | ----- this data with an anonymous lifetime `'_`...
+...
+LL | remaining: self.0.iter(),
+ | ------ ^^^^
+ | |
+ | ...is captured here...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/trait-object-nested-in-impl-trait.rs:38:23
+ |
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
+ |
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> + '_ {
+ | ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/trait-object-nested-in-impl-trait.rs:52:31
+ |
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+ | -------- this data with lifetime `'a`...
+...
+LL | remaining: self.0.iter(),
+ | ------ ^^^^
+ | |
+ | ...is captured here...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/trait-object-nested-in-impl-trait.rs:49:30
+ |
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
+ |
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> + 'a {
+ | ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+ --> $DIR/trait-object-nested-in-impl-trait.rs:63:31
+ |
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+ | -------- this data with lifetime `'a`...
+...
+LL | remaining: self.0.iter(),
+ | ------ ^^^^
+ | |
+ | ...is captured here...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/trait-object-nested-in-impl-trait.rs:60:30
+ |
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound
+ |
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+ | ^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
+ |
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> {
+ | ^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0759`.
--- /dev/null
+// run-rustfix
+
+pub fn foo<T: std::cmp::PartialEq>(s: &[T], t: &[T]) {
+ let _ = s == t; //~ ERROR binary operation `==` cannot be applied to type `&[T]`
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+
+pub fn foo<T>(s: &[T], t: &[T]) {
+ let _ = s == t; //~ ERROR binary operation `==` cannot be applied to type `&[T]`
+}
+
+fn main() {}
--- /dev/null
+error[E0369]: binary operation `==` cannot be applied to type `&[T]`
+ --> $DIR/missing-trait-bound-for-op.rs:4:15
+ |
+LL | let _ = s == t;
+ | - ^^ - &[T]
+ | |
+ | &[T]
+ |
+help: consider restricting type parameter `T`
+ |
+LL | pub fn foo<T: std::cmp::PartialEq>(s: &[T], t: &[T]) {
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0369`.
| ^^
|
= note: lifetime arguments must be provided before type arguments
+ = help: reorder the arguments: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
error[E0747]: lifetime provided when a type was expected
--> $DIR/suggest-move-types.rs:82:56
| ^^
|
= note: lifetime arguments must be provided before type arguments
+ = help: reorder the arguments: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
error: aborting due to 12 previous errors
--- /dev/null
+struct Struct {
+ m: Vec<Someunknownname<String, ()>>, //~ ERROR cannot find type `Someunknownname` in this scope
+ //~^ NOTE not found in this scope
+}
+struct OtherStruct { //~ HELP you might be missing a type parameter
+ m: K, //~ ERROR cannot find type `K` in this scope
+ //~^ NOTE not found in this scope
+}
+fn main() {}
--- /dev/null
+error[E0412]: cannot find type `Someunknownname` in this scope
+ --> $DIR/type-not-found-in-adt-field.rs:2:12
+ |
+LL | m: Vec<Someunknownname<String, ()>>,
+ | ^^^^^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `K` in this scope
+ --> $DIR/type-not-found-in-adt-field.rs:6:8
+ |
+LL | struct OtherStruct {
+ | - help: you might be missing a type parameter: `<K>`
+LL | m: K,
+ | ^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
--- /dev/null
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+enum NonNullary {
+ Nullary,
+ Other(isize),
+}
+
+impl From<NonNullary> for isize {
+ fn from(val: NonNullary) -> isize {
+ match val {
+ NonNullary::Nullary => 0,
+ NonNullary::Other(i) => i,
+ }
+ }
+}
+
+fn main() {
+ let v = NonNullary::Nullary;
+ let val = isize::from(v); //~ ERROR non-primitive cast: `NonNullary` as `isize` [E0605]
+}
+// run-rustfix
+#![allow(dead_code, unused_variables)]
enum NonNullary {
Nullary,
Other(isize),
}
+impl From<NonNullary> for isize {
+ fn from(val: NonNullary) -> isize {
+ match val {
+ NonNullary::Nullary => 0,
+ NonNullary::Other(i) => i,
+ }
+ }
+}
+
fn main() {
let v = NonNullary::Nullary;
let val = v as isize; //~ ERROR non-primitive cast: `NonNullary` as `isize` [E0605]
error[E0605]: non-primitive cast: `NonNullary` as `isize`
- --> $DIR/tag-variant-cast-non-nullary.rs:8:15
+ --> $DIR/tag-variant-cast-non-nullary.rs:19:15
|
LL | let val = v as isize;
- | ^^^^^^^^^^
+ | ^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(v)`
|
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to previous error
--- /dev/null
+// compile-flags: -Z terminal-width=20
+
+// This test checks that `-Z terminal-width` effects the human error output by restricting it to an
+// arbitrarily low value so that the effect is visible.
+
+fn main() {
+ let _: () = 42;
+ //~^ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/flag-human.rs:7:17
+ |
+LL | ..._: () = 42;
+ | -- ^^ expected `()`, found integer
+ | |
+ | expected due to this
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// compile-flags: -Z terminal-width=20 --error-format=json
+
+// This test checks that `-Z terminal-width` effects the JSON error output by restricting it to an
+// arbitrarily low value so that the effect is visible.
+
+fn main() {
+ let _: () = 42;
+ //~^ ERROR mismatched types
+}
--- /dev/null
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code example:
+
+```compile_fail,E0308
+let x: i32 = \"I am not a number!\";
+// ~~~ ~~~~~~~~~~~~~~~~~~~~
+// | |
+// | initializing expression;
+// | compiler infers type `&str`
+// |
+// type `i32` assigned to variable `x`
+```
+
+This error occurs when the compiler is unable to infer the concrete type of a
+variable. It can occur in several cases, the most common being a mismatch
+between two types: the type the author explicitly assigned, and the type the
+compiler inferred.
+"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":244,"byte_end":246,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":" let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":239,"byte_end":241,"line_start":7,"line_end":7,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":" let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types
+ --> $DIR/flag-json.rs:7:17
+ |
+LL | ..._: () = 42;
+ | -- ^^ expected `()`, found integer
+ | |
+ | expected due to this
+
+"}
+{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error
+
+"}
+{"message":"For more information about this error, try `rustc --explain E0308`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0308`.
+"}
--- /dev/null
+// run-pass
+// ignore-emscripten no threads support
+// compile-flags: -O
+
+#![feature(thread_local)]
+
+#[thread_local]
+static S: u32 = 222;
+
+fn main() {
+ let local = &S as *const u32 as usize;
+ let foreign = std::thread::spawn(|| &S as *const u32 as usize).join().unwrap();
+ assert_ne!(local, foreign);
+}
+++ /dev/null
-// run-pass
-#![allow(unused_doc_comments)]
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait Auto {}
-unsafe auto trait AutoUnsafe {}
-
-impl !Auto for bool {}
-impl !AutoUnsafe for bool {}
-
-struct AutoBool(bool);
-
-impl Auto for AutoBool {}
-unsafe impl AutoUnsafe for AutoBool {}
-
-fn take_auto<T: Auto>(_: T) {}
-fn take_auto_unsafe<T: AutoUnsafe>(_: T) {}
-
-fn main() {
- // Parse inside functions.
- auto trait AutoInner {}
- unsafe auto trait AutoUnsafeInner {}
-
- take_auto(0);
- take_auto(AutoBool(true));
- take_auto_unsafe(0);
- take_auto_unsafe(AutoBool(true));
-
- /// Auto traits are allowed in trait object bounds.
- let _: &(dyn Send + Auto) = &0;
-}
#![feature(negative_impls)]
#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
trait MyTrait {
type Foo;
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/negative-default-impls.rs:2:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0750]: negative impls cannot be default impls
- --> $DIR/negative-default-impls.rs:8:1
+ --> $DIR/negative-default-impls.rs:9:1
|
LL | default impl !MyTrait for u32 {}
| ^^^^^^^ ^
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0750`.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
#![feature(negative_impls)]
// Test a negative impl that "specializes" another negative impl.
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/negative-specializes-negative.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
#![feature(negative_impls)]
// Negative impl for u32 cannot "specialize" the base impl.
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/negative-specializes-positive-item.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`:
--> $DIR/negative-specializes-positive-item.rs:11:1
|
LL | impl !MyTrait for u32 {}
| ^^^^^^^^^^^^^^^^^^^^^ negative implementation here
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0751`.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
#![feature(negative_impls)]
// Negative impl for u32 cannot "specialize" the base impl.
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/negative-specializes-positive.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`:
--> $DIR/negative-specializes-positive.rs:7:1
|
LL | impl !MyTrait for u32 {}
| ^^^^^^^^^^^^^^^^^^^^^ negative implementation here
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0751`.
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
#![feature(negative_impls)]
trait MyTrait {}
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/positive-specializes-negative.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`:
--> $DIR/positive-specializes-negative.rs:7:1
|
LL | impl MyTrait for u32 {}
| ^^^^^^^^^^^^^^^^^^^^ positive implementation here
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0751`.
LL | struct S;
| --------- method `b` not found for this
...
-LL | fn b(&self) { }
- | -
- | |
- | the method is available for `std::boxed::Box<S>` here
- | the method is available for `std::sync::Arc<S>` here
- | the method is available for `std::rc::Rc<S>` here
-...
LL | S.b();
| ^ method not found in `S`
|
| - ^ - f64
| |
| &T
+ |
+help: consider further restricting this bound
+ |
+LL | fn foo<T: MyMul<f64, f64> + std::ops::Mul<Output = f64>>(a: &T, b: f64) -> f64 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
--- /dev/null
+// run-rustfix
+use std::net::TcpListener;
+
+struct NoToSocketAddrs(String);
+
+impl std::ops::Deref for NoToSocketAddrs {
+ type Target = String;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+fn main() {
+ let _works = TcpListener::bind("some string");
+ let bad = NoToSocketAddrs("bad".to_owned());
+ let _errors = TcpListener::bind(&*bad);
+ //~^ ERROR the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied
+}
--- /dev/null
+// run-rustfix
+use std::net::TcpListener;
+
+struct NoToSocketAddrs(String);
+
+impl std::ops::Deref for NoToSocketAddrs {
+ type Target = String;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+fn main() {
+ let _works = TcpListener::bind("some string");
+ let bad = NoToSocketAddrs("bad".to_owned());
+ let _errors = TcpListener::bind(&bad);
+ //~^ ERROR the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied
+ --> $DIR/trait-suggest-deferences-issue-39029.rs:16:37
+ |
+LL | let _errors = TcpListener::bind(&bad);
+ | ^^^^
+ | |
+ | the trait `std::net::ToSocketAddrs` is not implemented for `NoToSocketAddrs`
+ | help: consider adding dereference here: `&*bad`
+ |
+ ::: $SRC_DIR/libstd/net/tcp.rs:LL:COL
+ |
+LL | pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
+ | ------------- required by this bound in `std::net::TcpListener::bind`
+ |
+ = note: required because of the requirements on the impl of `std::net::ToSocketAddrs` for `&NoToSocketAddrs`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// run-rustfix
+fn takes_str(_x: &str) {}
+
+fn takes_type_parameter<T>(_x: T) where T: SomeTrait {}
+
+trait SomeTrait {}
+impl SomeTrait for &'_ str {}
+impl SomeTrait for char {}
+
+fn main() {
+ let string = String::new();
+ takes_str(&string); // Ok
+ takes_type_parameter(&*string); // Error
+ //~^ ERROR the trait bound `&std::string::String: SomeTrait` is not satisfied
+}
--- /dev/null
+// run-rustfix
+fn takes_str(_x: &str) {}
+
+fn takes_type_parameter<T>(_x: T) where T: SomeTrait {}
+
+trait SomeTrait {}
+impl SomeTrait for &'_ str {}
+impl SomeTrait for char {}
+
+fn main() {
+ let string = String::new();
+ takes_str(&string); // Ok
+ takes_type_parameter(&string); // Error
+ //~^ ERROR the trait bound `&std::string::String: SomeTrait` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `&std::string::String: SomeTrait` is not satisfied
+ --> $DIR/trait-suggest-deferences-issue-62530.rs:13:26
+ |
+LL | fn takes_type_parameter<T>(_x: T) where T: SomeTrait {}
+ | --------- required by this bound in `takes_type_parameter`
+...
+LL | takes_type_parameter(&string); // Error
+ | ^^^^^^^
+ | |
+ | the trait `SomeTrait` is not implemented for `&std::string::String`
+ | help: consider adding dereference here: `&*string`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// run-rustfix
+use std::ops::Deref;
+
+trait Happy {}
+struct LDM;
+impl Happy for &LDM {}
+
+struct Foo(LDM);
+struct Bar(Foo);
+struct Baz(Bar);
+impl Deref for Foo {
+ type Target = LDM;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+impl Deref for Bar {
+ type Target = Foo;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+impl Deref for Baz {
+ type Target = Bar;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+fn foo<T>(_: T) where T: Happy {}
+
+fn main() {
+ let baz = Baz(Bar(Foo(LDM)));
+ foo(&***baz);
+ //~^ ERROR the trait bound `&Baz: Happy` is not satisfied
+}
--- /dev/null
+// run-rustfix
+use std::ops::Deref;
+
+trait Happy {}
+struct LDM;
+impl Happy for &LDM {}
+
+struct Foo(LDM);
+struct Bar(Foo);
+struct Baz(Bar);
+impl Deref for Foo {
+ type Target = LDM;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+impl Deref for Bar {
+ type Target = Foo;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+impl Deref for Baz {
+ type Target = Bar;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+fn foo<T>(_: T) where T: Happy {}
+
+fn main() {
+ let baz = Baz(Bar(Foo(LDM)));
+ foo(&baz);
+ //~^ ERROR the trait bound `&Baz: Happy` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `&Baz: Happy` is not satisfied
+ --> $DIR/trait-suggest-deferences-multiple-0.rs:34:9
+ |
+LL | fn foo<T>(_: T) where T: Happy {}
+ | ----- required by this bound in `foo`
+...
+LL | foo(&baz);
+ | ^^^^
+ | |
+ | the trait `Happy` is not implemented for `&Baz`
+ | help: consider adding dereference here: `&***baz`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+use std::ops::{Deref, DerefMut};
+
+trait Happy {}
+struct LDM;
+impl Happy for &mut LDM {}
+
+struct Foo(LDM);
+struct Bar(Foo);
+struct Baz(Bar);
+impl Deref for Foo {
+ type Target = LDM;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+impl Deref for Bar {
+ type Target = Foo;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+impl Deref for Baz {
+ type Target = Bar;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+impl DerefMut for Foo {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+impl DerefMut for Bar {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+impl DerefMut for Baz {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+
+fn foo<T>(_: T) where T: Happy {}
+
+fn main() {
+ // Currently the compiler doesn't try to suggest dereferences for situations
+ // where DerefMut involves. So this test is meant to ensure compiler doesn't
+ // generate incorrect help message.
+ let mut baz = Baz(Bar(Foo(LDM)));
+ foo(&mut baz);
+ //~^ ERROR the trait bound `&mut Baz: Happy` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `&mut Baz: Happy` is not satisfied
+ --> $DIR/trait-suggest-deferences-multiple-1.rs:52:9
+ |
+LL | fn foo<T>(_: T) where T: Happy {}
+ | ----- required by this bound in `foo`
+...
+LL | foo(&mut baz);
+ | ^^^^^^^^ the trait `Happy` is not implemented for `&mut Baz`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// Test that we don't hit the recursion limit for short cycles involving lifetimes.
+
+// Shouldn't hit this, we should realize that we're in a cycle sooner.
+#![recursion_limit="20"]
+
+trait NotAuto {}
+trait Y {
+ type P;
+}
+
+impl<'a> Y for C<'a> {
+ type P = Box<X<C<'a>>>;
+}
+
+struct C<'a>(&'a ());
+struct X<T: Y>(T::P);
+
+impl<T: NotAuto> NotAuto for Box<T> {}
+impl<T: Y> NotAuto for X<T> where T::P: NotAuto {}
+impl<'a> NotAuto for C<'a> {}
+
+fn is_send<S: NotAuto>() {}
+//~^ NOTE: required
+
+fn main() {
+ // Should only be a few notes.
+ is_send::<X<C<'static>>>();
+ //~^ ERROR overflow evaluating
+ //~| NOTE: required
+}
--- /dev/null
+error[E0275]: overflow evaluating the requirement `std::boxed::Box<X<C<'_>>>: NotAuto`
+ --> $DIR/traits-inductive-overflow-lifetime.rs:27:5
+ |
+LL | fn is_send<S: NotAuto>() {}
+ | ------- required by this bound in `is_send`
+...
+LL | is_send::<X<C<'static>>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: required because of the requirements on the impl of `NotAuto` for `X<C<'static>>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
// run-pass
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
trait Specializable { type Output; }
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/transmute-specialization.rs:3:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/issue-57611-trait-alias.rs:21:9
+ |
+LL | |x| x
+ | ^^^^^
+
+error: higher-ranked subtype error
+ --> $DIR/issue-57611-trait-alias.rs:21:9
+ |
+LL | |x| x
+ | ^^^^^
+
+error: aborting due to 2 previous errors
+
struct X;
impl Foo for X {
- type Bar = impl Baz<Self, Self>; //~ ERROR type mismatch in closure arguments
- //~^ ERROR type mismatch resolving
+ type Bar = impl Baz<Self, Self>;
+ //~^ ERROR mismatched types
fn bar(&self) -> Self::Bar {
|x| x
-error[E0631]: type mismatch in closure arguments
+error[E0308]: mismatched types
--> $DIR/issue-57611-trait-alias.rs:17:16
|
LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(&'r X) -> _`
-...
-LL | |x| x
- | ----- found signature of `fn(_) -> _`
+ | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
- = note: the return type of a function must have a statically known size
+ = note: expected type `std::ops::FnOnce<(&X,)>`
+ found type `std::ops::FnOnce<(&X,)>`
-error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-57611-trait-alias.rs:21:9: 21:14] as std::ops::FnOnce<(&'r X,)>>::Output == &'r X`
- --> $DIR/issue-57611-trait-alias.rs:17:16
- |
-LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
- |
- = note: the return type of a function must have a statically known size
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
--> $DIR/never_reveal_concrete_type.rs:14:13
|
LL | let _ = x as &'static str;
- | ^^^^^^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to 2 previous errors
--- /dev/null
+// check-pass
+
+// rust-lang/rust#68590: confusing diagnostics when reborrowing through DerefMut.
+
+use std::cell::RefCell;
+
+struct A;
+
+struct S<'a> {
+ a: &'a mut A,
+}
+
+fn take_a(_: &mut A) {}
+
+fn test<'a>(s: &RefCell<S<'a>>) {
+ let mut guard = s.borrow_mut();
+ take_a(guard.a);
+ let _s2 = S { a: guard.a };
+}
+
+fn main() {
+ let a = &mut A;
+ let s = RefCell::new(S { a });
+ test(&s);
+}
--- /dev/null
+// check-pass
+
+// rust-lang/rust#72225: confusing diagnostics when calling FnMut through DerefMut.
+
+use std::cell::RefCell;
+
+struct S {
+ f: Box<dyn FnMut()>
+}
+
+fn test(s: &RefCell<S>) {
+ let mut guard = s.borrow_mut();
+ (guard.f)();
+}
+
+fn main() {
+ let s = RefCell::new(S {
+ f: Box::new(|| ())
+ });
+ test(&s);
+}
--- /dev/null
+// check-pass
+//
+// rust-lang/rust#73592: borrow_mut through Deref should work.
+//
+// Before #72280, when we see something like `&mut *rcvr.method()`, we
+// incorrectly requires `rcvr` to be type-checked as a mut place. While this
+// requirement is usually correct for smart pointers, it is overly restrictive
+// for types like `Mutex` or `RefCell` which can produce a guard that
+// implements `DerefMut` from `&self`.
+//
+// Making it more confusing, because we use Deref as the fallback when DerefMut
+// is implemented, we won't see an issue when the smart pointer does not
+// implement `DerefMut`. It only causes an issue when `rcvr` is obtained via a
+// type that implements both `Deref` or `DerefMut`.
+//
+// This bug is only discovered in #73592 after it is already fixed as a side-effect
+// of a refactoring made in #72280.
+
+#![warn(unused_mut)]
+
+use std::pin::Pin;
+use std::cell::RefCell;
+
+struct S(RefCell<()>);
+
+fn test_pin(s: Pin<&S>) {
+ // This works before #72280.
+ let _ = &mut *s.0.borrow_mut();
+}
+
+fn test_pin_mut(s: Pin<&mut S>) {
+ // This should compile but didn't before #72280.
+ let _ = &mut *s.0.borrow_mut();
+}
+
+fn test_vec(s: &Vec<RefCell<()>>) {
+ // This should compile but didn't before #72280.
+ let _ = &mut *s[0].borrow_mut();
+}
+
+fn test_mut_pin(mut s: Pin<&S>) {
+ //~^ WARN variable does not need to be mutable
+ let _ = &mut *s.0.borrow_mut();
+}
+
+fn test_mut_pin_mut(mut s: Pin<&mut S>) {
+ //~^ WARN variable does not need to be mutable
+ let _ = &mut *s.0.borrow_mut();
+}
+
+fn main() {
+ let mut s = S(RefCell::new(()));
+ test_pin(Pin::new(&s));
+ test_pin_mut(Pin::new(&mut s));
+ test_mut_pin(Pin::new(&s));
+ test_mut_pin_mut(Pin::new(&mut s));
+ test_vec(&vec![s.0]);
+}
--- /dev/null
+warning: variable does not need to be mutable
+ --> $DIR/issue-73592-borrow_mut-through-deref.rs:41:17
+ |
+LL | fn test_mut_pin(mut s: Pin<&S>) {
+ | ----^
+ | |
+ | help: remove this `mut`
+ |
+note: the lint level is defined here
+ --> $DIR/issue-73592-borrow_mut-through-deref.rs:19:9
+ |
+LL | #![warn(unused_mut)]
+ | ^^^^^^^^^^
+
+warning: variable does not need to be mutable
+ --> $DIR/issue-73592-borrow_mut-through-deref.rs:46:21
+ |
+LL | fn test_mut_pin_mut(mut s: Pin<&mut S>) {
+ | ----^
+ | |
+ | help: remove this `mut`
+
+warning: 2 warnings emitted
+
+++ /dev/null
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait Magic : Sized where Option<Self> : Magic {} //~ ERROR E0568
-impl<T:Magic> Magic for T {}
-
-fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
-
-#[derive(Debug)]
-struct NoClone;
-
-fn main() {
- let (a, b) = copy(NoClone);
- println!("{:?} {:?}", a, b);
-}
+++ /dev/null
-error[E0568]: auto traits cannot have super traits
- --> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:20
- |
-LL | auto trait Magic : Sized where Option<Self> : Magic {}
- | ----- ^^^^^ help: remove the super traits
- | |
- | auto trait cannot have super traits
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0568`.
+++ /dev/null
-// This test is for #29859, we need to ensure auto traits,
-// (also known previously as default traits), do not have
-// supertraits. Since the compiler synthesizes these
-// instances on demand, we are essentially enabling
-// users to write axioms if we view trait selection,
-// as a proof system.
-//
-// For example the below test allows us to add the rule:
-// forall (T : Type), T : Copy
-//
-// Providing a copy instance for *any* type, which
-// is most definitely unsound. Imagine copying a
-// type that contains a mutable reference, enabling
-// mutable aliasing.
-//
-// You can imagine an even more dangerous test,
-// which currently compiles on nightly.
-//
-// fn main() {
-// let mut i = 10;
-// let (a, b) = copy(&mut i);
-// println!("{:?} {:?}", a, b);
-// }
-
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait Magic: Copy {} //~ ERROR E0568
-impl<T:Magic> Magic for T {}
-
-fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
-
-#[derive(Debug)]
-struct NoClone;
-
-fn main() {
- let (a, b) = copy(NoClone);
- println!("{:?} {:?}", a, b);
-}
+++ /dev/null
-error[E0568]: auto traits cannot have super traits
- --> $DIR/typeck-auto-trait-no-supertraits.rs:28:19
- |
-LL | auto trait Magic: Copy {}
- | ----- ^^^^ help: remove the super traits
- | |
- | auto trait cannot have super traits
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0568`.
+++ /dev/null
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait MyTrait {}
-
-struct MyS;
-
-struct MyS2;
-
-impl !MyTrait for MyS2 {}
-
-fn is_mytrait<T: MyTrait>() {}
-
-fn main() {
- is_mytrait::<MyS>();
-
- is_mytrait::<(MyS2, MyS)>();
- //~^ ERROR `MyS2: MyTrait` is not satisfied
-}
+++ /dev/null
-error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied in `(MyS2, MyS)`
- --> $DIR/typeck-default-trait-impl-constituent-types-2.rs:17:5
- |
-LL | fn is_mytrait<T: MyTrait>() {}
- | ------- required by this bound in `is_mytrait`
-...
-LL | is_mytrait::<(MyS2, MyS)>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ within `(MyS2, MyS)`, the trait `MyTrait` is not implemented for `MyS2`
- |
- = help: the following implementations were found:
- <MyS2 as MyTrait>
- = note: required because it appears within the type `(MyS2, MyS)`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait MyTrait {}
-
-impl<T> !MyTrait for *mut T {}
-
-struct MyS;
-
-struct MyS2;
-
-impl !MyTrait for MyS2 {}
-
-struct MyS3;
-
-fn is_mytrait<T: MyTrait>() {}
-
-fn main() {
- is_mytrait::<MyS>();
-
- is_mytrait::<MyS2>();
- //~^ ERROR `MyS2: MyTrait` is not satisfied
-}
+++ /dev/null
-error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied
- --> $DIR/typeck-default-trait-impl-constituent-types.rs:21:18
- |
-LL | fn is_mytrait<T: MyTrait>() {}
- | ------- required by this bound in `is_mytrait`
-...
-LL | is_mytrait::<MyS2>();
- | ^^^^ the trait `MyTrait` is not implemented for `MyS2`
- |
- = help: the following implementations were found:
- <MyS2 as MyTrait>
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait MyTrait {}
-
-unsafe auto trait MyUnsafeTrait {}
-
-struct ThisImplsTrait;
-
-impl !MyUnsafeTrait for ThisImplsTrait {}
-
-
-struct ThisImplsUnsafeTrait;
-
-impl !MyTrait for ThisImplsUnsafeTrait {}
-
-fn is_my_trait<T: MyTrait>() {}
-fn is_my_unsafe_trait<T: MyUnsafeTrait>() {}
-
-fn main() {
- is_my_trait::<ThisImplsTrait>();
- is_my_trait::<ThisImplsUnsafeTrait>();
- //~^ ERROR `ThisImplsUnsafeTrait: MyTrait` is not satisfied
-
- is_my_unsafe_trait::<ThisImplsTrait>();
- //~^ ERROR `ThisImplsTrait: MyUnsafeTrait` is not satisfied
-
- is_my_unsafe_trait::<ThisImplsUnsafeTrait>();
-}
+++ /dev/null
-error[E0277]: the trait bound `ThisImplsUnsafeTrait: MyTrait` is not satisfied
- --> $DIR/typeck-default-trait-impl-negation.rs:22:19
- |
-LL | fn is_my_trait<T: MyTrait>() {}
- | ------- required by this bound in `is_my_trait`
-...
-LL | is_my_trait::<ThisImplsUnsafeTrait>();
- | ^^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `ThisImplsUnsafeTrait`
- |
- = help: the following implementations were found:
- <ThisImplsUnsafeTrait as MyTrait>
-
-error[E0277]: the trait bound `ThisImplsTrait: MyUnsafeTrait` is not satisfied
- --> $DIR/typeck-default-trait-impl-negation.rs:25:26
- |
-LL | fn is_my_unsafe_trait<T: MyUnsafeTrait>() {}
- | ------------- required by this bound in `is_my_unsafe_trait`
-...
-LL | is_my_unsafe_trait::<ThisImplsTrait>();
- | ^^^^^^^^^^^^^^ the trait `MyUnsafeTrait` is not implemented for `ThisImplsTrait`
- |
- = help: the following implementations were found:
- <ThisImplsTrait as MyUnsafeTrait>
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-// Test that declaring that `&T` is `Defaulted` if `T:Signed` implies
-// that other `&T` is NOT `Defaulted` if `T:Signed` does not hold. In
-// other words, the auto impl only applies if there are no existing
-// impls whose types unify.
-
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait Defaulted { }
-impl<'a,T:Signed> Defaulted for &'a T { }
-impl<'a,T:Signed> Defaulted for &'a mut T { }
-fn is_defaulted<T:Defaulted>() { }
-
-trait Signed { }
-impl Signed for i32 { }
-
-fn main() {
- is_defaulted::<&'static i32>();
- is_defaulted::<&'static u32>();
- //~^ ERROR `u32: Signed` is not satisfied
-}
+++ /dev/null
-error[E0277]: the trait bound `u32: Signed` is not satisfied
- --> $DIR/typeck-default-trait-impl-precedence.rs:19:5
- |
-LL | fn is_defaulted<T:Defaulted>() { }
- | --------- required by this bound in `is_defaulted`
-...
-LL | is_defaulted::<&'static u32>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`
- |
- = note: required because of the requirements on the impl of `Defaulted` for `&'static u32`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
// Tests that unsafe extern fn pointers do not implement any Fn traits.
-use std::ops::{Fn,FnMut,FnOnce};
+use std::ops::{Fn, FnMut, FnOnce};
-unsafe fn square(x: &isize) -> isize { (*x) * (*x) }
+unsafe fn square(x: &isize) -> isize {
+ (*x) * (*x)
+}
-fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
+fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+ 0
+}
+fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+ 0
+}
+fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+ 0
+}
fn a() {
let x = call_it(&square, 22);
//~^ ERROR E0277
- //~| ERROR expected
}
fn b() {
let y = call_it_mut(&mut square, 22);
//~^ ERROR E0277
- //~| ERROR expected
}
fn c() {
//~^ ERROR E0277
}
-fn main() { }
+fn main() {}
error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
- --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:21
+ --> $DIR/unboxed-closures-unsafe-extern-fn.rs:20:21
|
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
- | ----------------- required by this bound in `call_it`
+LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+ | ------------------- required by this bound in `call_it`
...
LL | let x = call_it(&square, 22);
| ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
|
= help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
- --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:21
- |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
- | ----- required by this bound in `call_it`
-...
-LL | let x = call_it(&square, 22);
- | ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
- |
- = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
-
error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
- --> $DIR/unboxed-closures-unsafe-extern-fn.rs:18:25
+ --> $DIR/unboxed-closures-unsafe-extern-fn.rs:25:25
|
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
- | -------------------- required by this bound in `call_it_mut`
+LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+ | ---------------------- required by this bound in `call_it_mut`
...
LL | let y = call_it_mut(&mut square, 22);
| ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
= help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
- --> $DIR/unboxed-closures-unsafe-extern-fn.rs:18:25
- |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
- | ----- required by this bound in `call_it_mut`
-...
-LL | let y = call_it_mut(&mut square, 22);
- | ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
- |
- = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
-
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
- --> $DIR/unboxed-closures-unsafe-extern-fn.rs:24:26
+ --> $DIR/unboxed-closures-unsafe-extern-fn.rs:30:26
|
-LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
- | ----- required by this bound in `call_it_once`
+LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+ | ----------------------- required by this bound in `call_it_once`
...
LL | let z = call_it_once(square, 22);
| ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
|
- = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
+ = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.
// Tests that unsafe extern fn pointers do not implement any Fn traits.
-use std::ops::{Fn,FnMut,FnOnce};
+use std::ops::{Fn, FnMut, FnOnce};
-extern "C" fn square(x: &isize) -> isize { (*x) * (*x) }
+extern "C" fn square(x: &isize) -> isize {
+ (*x) * (*x)
+}
-fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
+fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+ 0
+}
+fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+ 0
+}
+fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+ 0
+}
fn a() {
let x = call_it(&square, 22);
//~^ ERROR E0277
- //~| ERROR expected
}
fn b() {
let y = call_it_mut(&mut square, 22);
//~^ ERROR E0277
- //~| ERROR expected
}
fn c() {
//~^ ERROR E0277
}
-fn main() { }
+fn main() {}
error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
- --> $DIR/unboxed-closures-wrong-abi.rs:12:21
+ --> $DIR/unboxed-closures-wrong-abi.rs:20:21
|
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
- | ----------------- required by this bound in `call_it`
+LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+ | ------------------- required by this bound in `call_it`
...
LL | let x = call_it(&square, 22);
| ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
|
= help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
- --> $DIR/unboxed-closures-wrong-abi.rs:12:21
- |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
- | ----- required by this bound in `call_it`
-...
-LL | let x = call_it(&square, 22);
- | ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
- |
- = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-
error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
- --> $DIR/unboxed-closures-wrong-abi.rs:18:25
+ --> $DIR/unboxed-closures-wrong-abi.rs:25:25
|
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
- | -------------------- required by this bound in `call_it_mut`
+LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+ | ---------------------- required by this bound in `call_it_mut`
...
LL | let y = call_it_mut(&mut square, 22);
| ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
= help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
- --> $DIR/unboxed-closures-wrong-abi.rs:18:25
- |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
- | ----- required by this bound in `call_it_mut`
-...
-LL | let y = call_it_mut(&mut square, 22);
- | ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
- |
- = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
- --> $DIR/unboxed-closures-wrong-abi.rs:24:26
+ --> $DIR/unboxed-closures-wrong-abi.rs:30:26
|
-LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
- | ----- required by this bound in `call_it_once`
+LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+ | ----------------------- required by this bound in `call_it_once`
...
LL | let z = call_it_once(square, 22);
| ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
|
- = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+ = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.
// Tests that unsafe extern fn pointers do not implement any Fn traits.
-use std::ops::{Fn,FnMut,FnOnce};
+use std::ops::{Fn, FnMut, FnOnce};
-unsafe fn square(x: isize) -> isize { x * x }
+unsafe fn square(x: isize) -> isize {
+ x * x
+}
// note: argument type here is `isize`, not `&isize`
-fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
+fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+ 0
+}
+fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+ 0
+}
+fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+ 0
+}
fn a() {
let x = call_it(&square, 22);
//~^ ERROR E0277
- //~| ERROR expected
}
fn b() {
let y = call_it_mut(&mut square, 22);
//~^ ERROR E0277
- //~| ERROR expected
}
fn c() {
//~^ ERROR E0277
}
-fn main() { }
+fn main() {}
error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
- --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:21
+ --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:21:21
|
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
- | ----------------- required by this bound in `call_it`
+LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+ | ------------------- required by this bound in `call_it`
...
LL | let x = call_it(&square, 22);
| ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
|
= help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
- --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:21
- |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
- | ----- required by this bound in `call_it`
-...
-LL | let x = call_it(&square, 22);
- | ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
- |
- = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
-
error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
- --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:25
+ --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:26:25
|
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
- | -------------------- required by this bound in `call_it_mut`
+LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+ | ---------------------- required by this bound in `call_it_mut`
...
LL | let y = call_it_mut(&mut square, 22);
| ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
= help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
- --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:25
- |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
- | ----- required by this bound in `call_it_mut`
-...
-LL | let y = call_it_mut(&mut square, 22);
- | ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
- |
- = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
-
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
- --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:25:26
+ --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:31:26
|
-LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
- | ----- required by this bound in `call_it_once`
+LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+ | ----------------------- required by this bound in `call_it_once`
...
LL | let z = call_it_once(square, 22);
| ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
|
- = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
+ = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
--> $DIR/dyn-trait-underscore.rs:8:20
|
LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
- | ---- data with this lifetime...
+ | ---- this data with an anonymous lifetime `'_`...
LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
LL | Box::new(items.iter())
- | ---------------^^^^--- ...is captured and required to be `'static` here
+ | ---------------^^^^--- ...is captured and required to live as long as `'static` here
|
-help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 6:1
+help: to declare that the trait object captures data from argument `items`, you can add an explicit `'_` lifetime bound
|
LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T> + '_> {
| ^^^^
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0759`.
--> $DIR/uninhabited-enum-cast.rs:4:20
|
LL | println!("{}", (e as isize).to_string());
- | ^^^^^^^^^^^^
- |
- = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+ | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to previous error
LL | fn move_then_borrow<T: Not<Output=T> + Clone>(x: T) {
| - move occurs because `x` has type `T`, which does not implement the `Copy` trait
LL | !x;
- | -- `x` moved due to this method call
+ | -- `x` moved due to usage in operator
LL |
LL | x.clone();
| ^ value borrowed here after move
|
-note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
+note: calling this operator moves the left-hand side
--> $SRC_DIR/libcore/ops/bit.rs:LL:COL
|
LL | fn not(self) -> Self::Output;
#![stable(feature = "foo", since = "1.33.0")]
#![feature(staged_api)]
-#![feature(const_compare_raw_pointers)]
+#![feature(const_raw_ptr_deref)]
#![feature(const_fn)]
#[stable(feature = "foo", since = "1.33.0")]
#[rustc_const_unstable(feature = "const_foo", issue = "none")]
-const fn unstable(a: *const i32, b: *const i32) -> bool {
- a == b
- //~^ pointer operation is unsafe
+const fn unstable(a: *const i32, b: i32) -> bool {
+ *a == b
+ //~^ dereference of raw pointer is unsafe
}
fn main() {}
-error[E0133]: pointer operation is unsafe and requires unsafe function or block
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
--> $DIR/unsafe-unstable-const-fn.rs:9:5
|
-LL | a == b
- | ^^^^^^ pointer operation
+LL | *a == b
+ | ^^ dereference of raw pointer
|
- = note: operations on pointers in constants
+ = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error: aborting due to previous error
|
= help: the trait `std::marker::Sized` is not implemented for `T`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box<U>`
+ --> $DIR/unsized-enum.rs:4:10
+ |
+LL | enum Foo<U> { FooSome(U), FooNone }
+ | ^ - ...if indirection was used here: `Box<U>`
+ | |
+ | this could be changed to `U: ?Sized`...
error: aborting due to previous error
|
= help: the trait `std::marker::Sized` is not implemented for `X`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
+ --> $DIR/unsized-inherent-impl-self-type.rs:5:11
+ |
+LL | struct S5<Y>(Y);
+ | ^ - ...if indirection was used here: `Box<Y>`
+ | |
+ | this could be changed to `Y: ?Sized`...
error: aborting due to previous error
|
= help: the trait `std::marker::Sized` is not implemented for `T`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+ --> $DIR/unsized-struct.rs:4:12
+ |
+LL | struct Foo<T> { data: T }
+ | ^ - ...if indirection was used here: `Box<T>`
+ | |
+ | this could be changed to `T: ?Sized`...
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/unsized-struct.rs:13:24
|
= help: the trait `std::marker::Sized` is not implemented for `X`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
+ --> $DIR/unsized-trait-impl-self-type.rs:8:11
+ |
+LL | struct S5<Y>(Y);
+ | ^ - ...if indirection was used here: `Box<Y>`
+ | |
+ | this could be changed to `Y: ?Sized`...
error: aborting due to previous error
|
= help: the trait `std::marker::Sized` is not implemented for `X`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider relaxing the implicit `Sized` restriction
+ |
+LL | trait T2<Z: ?Sized> {
+ | ^^^^^^^^
error: aborting due to previous error
= help: within `S<X>`, the trait `std::marker::Sized` is not implemented for `X`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required because it appears within the type `S<X>`
+help: consider relaxing the implicit `Sized` restriction
+ |
+LL | fn f5<Y: ?Sized>(x: &Y) {}
+ | ^^^^^^^^
error[E0277]: the size for values of type `X` cannot be known at compilation time
--> $DIR/unsized3.rs:40:8
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required because it appears within the type `S<X>`
= note: required because it appears within the type `({integer}, S<X>)`
+help: consider relaxing the implicit `Sized` restriction
+ |
+LL | fn f5<Y: ?Sized>(x: &Y) {}
+ | ^^^^^^^^
error: aborting due to 6 previous errors
|
= help: the trait `std::marker::Sized` is not implemented for `X`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider relaxing the implicit `Sized` restriction
+ |
+LL | trait T1<Z: T + ?Sized> {
+ | ^^^^^^^^
error: aborting due to previous error
+#![allow(mixed_script_confusables)]
+
fn foo<
'β, //~ ERROR non-ascii idents are not fully supported
γ //~ ERROR non-ascii idents are not fully supported
error[E0658]: non-ascii idents are not fully supported
- --> $DIR/utf8_idents.rs:2:5
+ --> $DIR/utf8_idents.rs:4:5
|
LL | 'β,
| ^^
= help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
error[E0658]: non-ascii idents are not fully supported
- --> $DIR/utf8_idents.rs:3:5
+ --> $DIR/utf8_idents.rs:5:5
|
LL | γ
| ^
= help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
error[E0658]: non-ascii idents are not fully supported
- --> $DIR/utf8_idents.rs:8:5
+ --> $DIR/utf8_idents.rs:10:5
|
LL | δ: usize
| ^
= help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
error[E0658]: non-ascii idents are not fully supported
- --> $DIR/utf8_idents.rs:12:9
+ --> $DIR/utf8_idents.rs:14:9
|
LL | let α = 0.00001f64;
| ^
= help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
warning: type parameter `γ` should have an upper camel case name
- --> $DIR/utf8_idents.rs:3:5
+ --> $DIR/utf8_idents.rs:5:5
|
LL | γ
| ^ help: convert the identifier to upper camel case: `Γ`
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+ --> $DIR/wf-fn-where-clause.rs:16:12
+ |
+LL | struct Vec<T> {
+ | ^ this could be changed to `T: ?Sized`...
+LL | t: T,
+ | - ...if indirection was used here: `Box<T>`
error[E0038]: the trait `std::marker::Copy` cannot be made into an object
--> $DIR/wf-fn-where-clause.rs:12:16
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/where-for-self-2.rs:23:5
+ |
+LL | foo(&X);
+ | ^^^^^^^
+
+error: aborting due to previous error
+
}
fn foo<T>(x: &T)
- where for<'a> &'a T: Bar
-{}
+where
+ for<'a> &'a T: Bar,
+{
+}
fn main() {
- foo(&X); //~ ERROR trait bound
+ foo(&X); //~ ERROR implementation of `Bar` is not general enough
}
-error[E0277]: the trait bound `for<'a> &'a _: Bar` is not satisfied
- --> $DIR/where-for-self-2.rs:21:5
+error: implementation of `Bar` is not general enough
+ --> $DIR/where-for-self-2.rs:23:5
|
-LL | fn foo<T>(x: &T)
- | --- required by a bound in this
-LL | where for<'a> &'a T: Bar
- | --- required by this bound in `foo`
+LL | / trait Bar {
+LL | | fn bar(&self);
+LL | | }
+ | |_- trait `Bar` defined here
...
-LL | foo(&X);
- | ^^^ the trait `for<'a> Bar` is not implemented for `&'a _`
+LL | foo(&X);
+ | ^^^ implementation of `Bar` is not general enough
|
- = help: the following implementations were found:
- <&'static u32 as Bar>
+ = note: `Bar` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
+ = note: ...but `Bar` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0277`.
//~^ ERROR use of undeclared lifetime name `'a`
for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
//~^ ERROR use of undeclared lifetime name `'b`
- //~| ERROR nested quantification of lifetimes
{}
fn main() {}
LL | (dyn for<'a> Trait1<'a>): Trait1<'a>,
| ^^ undeclared lifetime
-error[E0316]: nested quantification of lifetimes
- --> $DIR/where-lifetime-resolution.rs:8:17
- |
-LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
- | ^^^^^^^^^^^^^^^^^^^^^^
-
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/where-lifetime-resolution.rs:8:52
|
LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
| ^^ undeclared lifetime
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0261`.
//! via `x.py dist hash-and-sign`; the cmdline arguments are set up
//! by rustbuild (in `src/bootstrap/dist.rs`).
-#![deny(warnings)]
-
use serde::Serialize;
-use toml;
use std::collections::BTreeMap;
use std::collections::HashMap;
-Subproject commit 79c769c3d7b4c2cf6a93781575b7f592ef974255
+Subproject commit c26576f9adddd254b3dd63aecba176434290a9f6
-#![deny(warnings)]
-
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
+++ /dev/null
-<!--
-Hi there! Whether you've come to make a suggestion for a new lint, an improvement to an existing lint or to report a bug or a false positive in Clippy, you've come to the right place.
-
-For bug reports and false positives, please include the output of `cargo clippy -V` in the report.
-
-Thank you for using Clippy!
-
-Write your comment below this line: -->
--- /dev/null
+---
+name: Blank Issue
+about: Create a blank issue.
+---
--- /dev/null
+---
+name: Bug Report
+about: Create a bug report for Clippy
+labels: L-bug
+---
+<!--
+Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
+along with any information you feel relevant to replicating the bug.
+-->
+
+I tried this code:
+
+```rust
+<code>
+```
+
+I expected to see this happen: *explanation*
+
+Instead, this happened: *explanation*
+
+### Meta
+
+- `cargo clippy -V`: e.g. clippy 0.0.212 (f455e46 2020-06-20)
+- `rustc -Vv`:
+ ```
+ rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+ binary: rustc
+ commit-hash: f455e46eae1a227d735091091144601b467e1565
+ commit-date: 2020-06-20
+ host: x86_64-unknown-linux-gnu
+ release: 1.46.0-nightly
+ LLVM version: 10.0
+ ```
+
+<!--
+Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
+environment. E.g. `RUST_BACKTRACE=1 cargo clippy`.
+-->
+<details><summary>Backtrace</summary>
+ <p>
+
+ ```
+ <backtrace>
+ ```
+
+ </p>
+</details>
--- /dev/null
+blank_issues_enabled: true
+contact_links:
+ - name: Rust Programming Language Forum
+ url: https://users.rust-lang.org
+ about: Please ask and answer questions about Rust here.
--- /dev/null
+---
+name: Internal Compiler Error
+about: Create a report for an internal compiler error in Clippy.
+labels: L-bug, L-crash
+---
+<!--
+Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
+a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for
+how to create smaller examples.
+
+http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
+
+-->
+
+### Code
+
+```rust
+<code>
+```
+
+### Meta
+
+- `cargo clippy -V`: e.g. clippy 0.0.212 (f455e46 2020-06-20)
+- `rustc -Vv`:
+ ```
+ rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+ binary: rustc
+ commit-hash: f455e46eae1a227d735091091144601b467e1565
+ commit-date: 2020-06-20
+ host: x86_64-unknown-linux-gnu
+ release: 1.46.0-nightly
+ LLVM version: 10.0
+ ```
+
+### Error output
+
+```
+<output>
+```
+
+<!--
+Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
+environment. E.g. `RUST_BACKTRACE=1 cargo clippy`.
+-->
+<details><summary>Backtrace</summary>
+ <p>
+
+ ```
+ <backtrace>
+ ```
+
+ </p>
+</details>
--- /dev/null
+---
+name: New lint suggestion
+about: Suggest a new Clippy lint.
+labels: L-lint
+---
+
+### What it does
+
+*What does this lint do?*
+
+### Categories (optional)
+
+- Kind: *See <https://github.com/rust-lang/rust-clippy/blob/master/README.md#clippy> for list of lint kinds*
+
+*What benefit of this lint over old code?*
+
+For example:
+- Remove bounce checking inserted by ...
+- Remove the need to duplicating/storing/typo ...
+
+### Drawbacks
+
+None.
+
+### Example
+
+```rust
+<code>
+```
+
+Could be written as:
+
+```rust
+<code>
+```
---
+*Please keep the line below*
changelog: none
sed -e "s,tests/ui,\$DIR," -e "/= help/d" cstring.stderr > normalized.stderr
diff normalized.stderr tests/ui/cstring.stderr
+
+# make sure "clippy-driver --rustc --arg" and "rustc --arg" behave the same
+SYSROOT=`rustc --print sysroot`
+diff <(LD_LIBRARY_PATH=${SYSROOT}/lib ./target/debug/clippy-driver --rustc --version --verbose) <(rustc --version --verbose)
+
+
+echo "fn main() {}" > target/driver_test.rs
+# we can't run 2 rustcs on the same file at the same time
+CLIPPY=`LD_LIBRARY_PATH=${SYSROOT}/lib ./target/debug/clippy-driver ./target/driver_test.rs --rustc`
+RUSTC=`rustc ./target/driver_test.rs`
+diff <($CLIPPY) <($RUSTC)
+
# TODO: CLIPPY_CONF_DIR / CARGO_MANIFEST_DIR
_ => (),
}
- let (l_ty, r_ty) = (cx.tables.expr_ty(l), cx.tables.expr_ty(r));
+ let (l_ty, r_ty) = (cx.tables().expr_ty(l), cx.tables().expr_ty(r));
if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() {
span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
self.expr_span = Some(expr.span);
}
},
hir::ExprKind::Unary(hir::UnOp::UnNeg, arg) => {
- let ty = cx.tables.expr_ty(arg);
- if constant_simple(cx, cx.tables, expr).is_none() {
+ let ty = cx.tables().expr_ty(arg);
+ if constant_simple(cx, cx.tables(), expr).is_none() {
if ty.is_integral() {
span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
self.expr_span = Some(expr.span);
}
if_chain! {
if let ExprKind::Unary(_, ref lit) = e.kind;
- if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.tables, lit);
+ if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.tables(), lit);
if is_true;
then {
lint_true(true);
if let ExprKind::DropTemps(ref expr) = expr.kind;
if let ExprKind::Unary(UnOp::UnNot, ref expr) = expr.kind;
// bind the first argument of the `assert!` macro
- if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.tables, expr);
+ if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.tables(), expr);
// arm 1 pattern
if let PatKind::Lit(ref lit_expr) = arms[0].pat.kind;
if let ExprKind::Lit(ref lit) = lit_expr.kind;
hir::ExprKind::Assign(assignee, e, _) => {
if let hir::ExprKind::Binary(op, l, r) = &e.kind {
let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| {
- let ty = cx.tables.expr_ty(assignee);
- let rty = cx.tables.expr_ty(rhs);
+ let ty = cx.tables().expr_ty(assignee);
+ let rty = cx.tables().expr_ty(rhs);
macro_rules! ops {
($op:expr,
$cx:expr,
// a = b commutative_op a
// Limited to primitive type as these ops are know to be commutative
if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r)
- && cx.tables.expr_ty(assignee).is_primitive_ty()
+ && cx.tables().expr_ty(assignee).is_primitive_ty()
{
match op.node {
hir::BinOpKind::Add
];
fn type_is_atomic(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
- if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.tables.expr_ty(expr).kind {
+ if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.tables().expr_ty(expr).kind {
ATOMIC_TYPES
.iter()
.any(|ty| match_def_path(cx, did, &["core", "sync", "atomic", ty]))
if method == "load" || method == "store";
let ordering_arg = if method == "load" { &args[1] } else { &args[2] };
if let ExprKind::Path(ref ordering_qpath) = ordering_arg.kind;
- if let Some(ordering_def_id) = cx.tables.qpath_res(ordering_qpath, ordering_arg.hir_id).opt_def_id();
+ if let Some(ordering_def_id) = cx.tables().qpath_res(ordering_qpath, ordering_arg.hir_id).opt_def_id();
then {
if method == "load" &&
match_ordering_def_path(cx, ordering_def_id, &["Release", "AcqRel"]) {
if_chain! {
if let ExprKind::Call(ref func, ref args) = expr.kind;
if let ExprKind::Path(ref func_qpath) = func.kind;
- if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id();
+ if let Some(def_id) = cx.tables().qpath_res(func_qpath, func.hir_id).opt_def_id();
if ["fence", "compiler_fence"]
.iter()
.any(|func| match_def_path(cx, def_id, &["core", "sync", "atomic", func]));
if let ExprKind::Path(ref ordering_qpath) = &args[0].kind;
- if let Some(ordering_def_id) = cx.tables.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id();
+ if let Some(ordering_def_id) = cx.tables().qpath_res(ordering_qpath, args[0].hir_id).opt_def_id();
if match_ordering_def_path(cx, ordering_def_id, &["Relaxed"]);
then {
span_lint_and_help(
}
fn fetch_int_literal(cx: &LateContext<'_, '_>, lit: &Expr<'_>) -> Option<u128> {
- match constant(cx, cx.tables, lit)?.0 {
+ match constant(cx, cx.tables(), lit)?.0 {
Constant::Int(n) => Some(n),
_ => None,
}
})
},
ExprKind::MethodCall(path, _, args, _) if args.len() == 1 => {
- let type_of_receiver = cx.tables.expr_ty(&args[0]);
+ let type_of_receiver = cx.tables().expr_ty(&args[0]);
if !is_type_diagnostic_item(cx, type_of_receiver, sym!(option_type))
&& !is_type_diagnostic_item(cx, type_of_receiver, sym!(result_type))
{
self.bool_expr(e)
},
ExprKind::Unary(UnOp::UnNot, inner) => {
- if self.cx.tables.node_types()[inner.hir_id].is_bool() {
+ if self.cx.tables().node_types()[inner.hir_id].is_bool() {
self.bool_expr(e);
} else {
walk_expr(self, e);
}
fn implements_ord<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, expr: &Expr<'_>) -> bool {
- let ty = cx.tables.expr_ty(expr);
+ let ty = cx.tables().expr_ty(expr);
get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]))
}
if let ExprKind::Binary(ref op, ref l, ref r) = body.value.kind;
if op.node == BinOpKind::Eq;
if match_type(cx,
- walk_ptrs_ty(cx.tables.expr_ty(&filter_args[0])),
+ walk_ptrs_ty(cx.tables().expr_ty(&filter_args[0])),
&paths::SLICE_ITER);
then {
let needle = match get_path_name(l) {
_ => { return; }
}
};
- if ty::Uint(UintTy::U8) != walk_ptrs_ty(cx.tables.expr_ty(needle)).kind {
+ if ty::Uint(UintTy::U8) != walk_ptrs_ty(cx.tables().expr_ty(needle)).kind {
return;
}
let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) =
let mut helper = CCHelper { cc: 1, returns: 0 };
helper.visit_expr(expr);
let CCHelper { cc, returns } = helper;
- let ret_ty = cx.tables.node_type(expr.hir_id);
+ let ret_ty = cx.tables().node_type(expr.hir_id);
let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym!(result_type)) {
returns
} else {
}
// Check that the type being compared implements `core::cmp::Ord`
- let ty = cx.tables.expr_ty(lhs1);
+ let ty = cx.tables().expr_ty(lhs1);
let is_ord = get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]));
if !is_ord {
let l = self.expr(left)?;
let r = self.expr(right);
match (l, r) {
- (Constant::Int(l), Some(Constant::Int(r))) => match self.tables.expr_ty(left).kind {
+ (Constant::Int(l), Some(Constant::Int(r))) => match self.tables.expr_ty_opt(left)?.kind {
ty::Int(ity) => {
let l = sext(self.lcx.tcx, l, ity);
let r = sext(self.lcx.tcx, r, ity);
/// Implementation of `IFS_SAME_COND`.
fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr<'_>]) {
let hash: &dyn Fn(&&Expr<'_>) -> u64 = &|expr| -> u64 {
- let mut h = SpanlessHash::new(cx, cx.tables);
+ let mut h = SpanlessHash::new(cx, cx.tables());
h.hash_expr(expr);
h.finish()
};
/// Implementation of `SAME_FUNCTIONS_IN_IF_CONDITION`.
fn lint_same_fns_in_if_cond(cx: &LateContext<'_, '_>, conds: &[&Expr<'_>]) {
let hash: &dyn Fn(&&Expr<'_>) -> u64 = &|expr| -> u64 {
- let mut h = SpanlessHash::new(cx, cx.tables);
+ let mut h = SpanlessHash::new(cx, cx.tables());
h.hash_expr(expr);
h.finish()
};
if let ExprKind::Match(_, ref arms, MatchSource::Normal) = expr.kind {
let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 {
- let mut h = SpanlessHash::new(cx, cx.tables);
+ let mut h = SpanlessHash::new(cx, cx.tables());
h.hash_expr(&arm.body);
h.finish()
};
},
PatKind::Binding(.., ident, ref as_pat) => {
if let Entry::Vacant(v) = map.entry(ident.name) {
- v.insert(cx.tables.pat_ty(pat));
+ v.insert(cx.tables().pat_ty(pat));
}
if let Some(ref as_pat) = *as_pat {
bindings_impl(cx, as_pat, map);
if let ExprKind::Call(ref path, ..) = expr.kind;
if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
if let ExprKind::Path(ref qpath) = path.kind;
- if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id();
+ if let Some(def_id) = cx.tables().qpath_res(qpath, path.hir_id).opt_def_id();
if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
then {
match qpath {
// TODO: Work out a way to put "whatever the imported way of referencing
// this type in this file" rather than a fully-qualified type.
- let expr_ty = cx.tables.expr_ty(expr);
+ let expr_ty = cx.tables().expr_ty(expr);
if let ty::Adt(..) = expr_ty.kind {
let replacement = format!("{}::default()", expr_ty);
span_lint_and_sugg(
fn lint_deref(cx: &LateContext<'_, '_>, method_name: &str, call_expr: &Expr<'_>, var_span: Span, expr_span: Span) {
match method_name {
"deref" => {
- if cx
- .tcx
- .lang_items()
- .deref_trait()
- .map_or(false, |id| implements_trait(cx, cx.tables.expr_ty(&call_expr), id, &[]))
- {
+ if cx.tcx.lang_items().deref_trait().map_or(false, |id| {
+ implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[])
+ }) {
span_lint_and_sugg(
cx,
EXPLICIT_DEREF_METHODS,
}
},
"deref_mut" => {
- if cx
- .tcx
- .lang_items()
- .deref_mut_trait()
- .map_or(false, |id| implements_trait(cx, cx.tables.expr_ty(&call_expr), id, &[]))
- {
+ if cx.tcx.lang_items().deref_mut_trait().map_or(false, |id| {
+ implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[])
+ }) {
span_lint_and_sugg(
cx,
EXPLICIT_DEREF_METHODS,
let lint;
let msg;
let arg = &args[0];
- let arg_ty = cx.tables.expr_ty(arg);
+ let arg_ty = cx.tables().expr_ty(arg);
if let ty::Ref(..) = arg_ty.kind {
if match_def_path(cx, def_id, &paths::DROP) {
if_chain! {
if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, ref left, ref right) = expr.kind;
if let ExprKind::MethodCall(ref method_path, _ , ref args, _) = left.kind;
- if match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(&args[0])), &paths::DURATION);
- if let Some((Constant::Int(divisor), _)) = constant(cx, cx.tables, right);
+ if match_type(cx, walk_ptrs_ty(cx.tables().expr_ty(&args[0])), &paths::DURATION);
+ if let Some((Constant::Int(divisor), _)) = constant(cx, cx.tables(), right);
then {
let suggested_fn = match (method_path.ident.as_str().as_ref(), divisor) {
("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis",
if let ExprKind::AddrOf(BorrowKind::Ref, _, ref key) = params[1].kind;
then {
let map = ¶ms[0];
- let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(map));
+ let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(map));
return if match_type(cx, obj_ty, &paths::BTREEMAP) {
Some(("BTreeMap", map, key))
(&ExprKind::Lit(..), _) | (_, &ExprKind::Lit(..)) => {},
// &foo == &bar
(&ExprKind::AddrOf(BorrowKind::Ref, _, ref l), &ExprKind::AddrOf(BorrowKind::Ref, _, ref r)) => {
- let lty = cx.tables.expr_ty(l);
- let rty = cx.tables.expr_ty(r);
+ let lty = cx.tables().expr_ty(l);
+ let rty = cx.tables().expr_ty(r);
let lcpy = is_copy(cx, lty);
let rcpy = is_copy(cx, rty);
// either operator autorefs or both args are copyable
)
} else if lcpy
&& !rcpy
- && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()])
+ && implements_trait(cx, lty, trait_id, &[cx.tables().expr_ty(right).into()])
{
span_lint_and_then(
cx,
)
} else if !lcpy
&& rcpy
- && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()])
+ && implements_trait(cx, cx.tables().expr_ty(left), trait_id, &[rty.into()])
{
span_lint_and_then(
cx,
},
// &foo == bar
(&ExprKind::AddrOf(BorrowKind::Ref, _, ref l), _) => {
- let lty = cx.tables.expr_ty(l);
+ let lty = cx.tables().expr_ty(l);
let lcpy = is_copy(cx, lty);
if (requires_ref || lcpy)
- && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()])
+ && implements_trait(cx, lty, trait_id, &[cx.tables().expr_ty(right).into()])
{
span_lint_and_then(
cx,
},
// foo == &bar
(_, &ExprKind::AddrOf(BorrowKind::Ref, _, ref r)) => {
- let rty = cx.tables.expr_ty(r);
+ let rty = cx.tables().expr_ty(r);
let rcpy = is_copy(cx, rty);
if (requires_ref || rcpy)
- && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()])
+ && implements_trait(cx, cx.tables().expr_ty(left), trait_id, &[rty.into()])
{
span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |diag| {
let rsnip = snippet(cx, r.span, "...").to_string();
}
fn check(cx: &LateContext<'_, '_>, e: &Expr<'_>, span: Span) {
- if let Some(Constant::Int(0)) = constant_simple(cx, cx.tables, e) {
+ if let Some(Constant::Int(0)) = constant_simple(cx, cx.tables(), e) {
span_lint(
cx,
ERASING_OP,
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_target::abi::LayoutOf;
-use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase};
+use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use crate::utils::span_lint;
let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
cx.tcx.infer_ctxt().enter(|infcx| {
- ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.tables).consume_body(body);
+ ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.tables()).consume_body(body);
});
for node in v.set {
}
impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
- fn consume(&mut self, cmt: &Place<'tcx>, mode: ConsumeMode) {
- if cmt.projections.is_empty() {
- if let PlaceBase::Local(lid) = cmt.base {
+ fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, mode: ConsumeMode) {
+ if cmt.place.projections.is_empty() {
+ if let PlaceBase::Local(lid) = cmt.place.base {
if let ConsumeMode::Move = mode {
// moved out or in. clearly can't be localized
self.set.remove(&lid);
}
}
- fn borrow(&mut self, cmt: &Place<'tcx>, _: ty::BorrowKind) {
- if cmt.projections.is_empty() {
- if let PlaceBase::Local(lid) = cmt.base {
+ fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: ty::BorrowKind) {
+ if cmt.place.projections.is_empty() {
+ if let PlaceBase::Local(lid) = cmt.place.base {
self.set.remove(&lid);
}
}
}
- fn mutate(&mut self, cmt: &Place<'tcx>) {
- if cmt.projections.is_empty() {
+ fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) {
+ if cmt.place.projections.is_empty() {
let map = &self.cx.tcx.hir();
if is_argument(*map, cmt.hir_id) {
// Skip closure arguments
return;
}
- if is_non_trait_box(cmt.ty) && !self.is_large_box(cmt.ty) {
+ if is_non_trait_box(cmt.place.ty) && !self.is_large_box(cmt.place.ty) {
self.set.insert(cmt.hir_id);
}
return;
// Are the expression or the arguments type-adjusted? Then we need the closure
if !(is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)));
- let fn_ty = cx.tables.expr_ty(caller);
+ let fn_ty = cx.tables().expr_ty(caller);
if matches!(fn_ty.kind, ty::FnDef(_, _) | ty::FnPtr(_) | ty::Closure(_, _));
// Are the expression or the arguments type-adjusted? Then we need the closure
if !(is_adjusted(cx, ex) || args.iter().skip(1).any(|arg| is_adjusted(cx, arg)));
- let method_def_id = cx.tables.type_dependent_def_id(ex.hir_id).unwrap();
+ let method_def_id = cx.tables().type_dependent_def_id(ex.hir_id).unwrap();
if !type_is_unsafe_function(cx, cx.tcx.type_of(method_def_id));
if compare_inputs(&mut iter_input_pats(decl, body), &mut args.iter());
/// Tries to determine the type for universal function call to be used instead of the closure
fn get_ufcs_type_name(cx: &LateContext<'_, '_>, method_def_id: def_id::DefId, self_arg: &Expr<'_>) -> Option<String> {
let expected_type_of_self = &cx.tcx.fn_sig(method_def_id).inputs_and_output().skip_binder()[0];
- let actual_type_of_self = &cx.tables.node_type(self_arg.hir_id);
+ let actual_type_of_self = &cx.tables().node_type(self_arg.hir_id);
if let Some(trait_id) = cx.tcx.trait_of_item(method_def_id) {
if match_borrow_depth(expected_type_of_self, &actual_type_of_self)
if let ExprKind::Path(ref qpath) = lhs.kind {
if let QPath::Resolved(_, ref path) = *qpath {
if path.segments.len() == 1 {
- if let def::Res::Local(var) = cx.tables.qpath_res(qpath, lhs.hir_id) {
+ if let def::Res::Local(var) = cx.tables().qpath_res(qpath, lhs.hir_id) {
let mut visitor = ReadVisitor {
cx,
var,
match e.kind {
ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e),
ExprKind::Call(ref func, _) => {
- let typ = self.cx.tables.expr_ty(func);
+ let typ = self.cx.tables().expr_ty(func);
match typ.kind {
ty::FnDef(..) | ty::FnPtr(_) => {
let sig = typ.fn_sig(self.cx.tcx);
}
},
ExprKind::MethodCall(..) => {
- let borrowed_table = self.cx.tables;
+ let borrowed_table = self.cx.tables();
if borrowed_table.expr_ty(e).is_never() {
self.report_diverging_sub_expr(e);
}
if_chain! {
if let QPath::Resolved(None, ref path) = *qpath;
if path.segments.len() == 1;
- if let def::Res::Local(local_id) = self.cx.tables.qpath_res(qpath, expr.hir_id);
+ if let def::Res::Local(local_id) = self.cx.tables().qpath_res(qpath, expr.hir_id);
if local_id == self.var;
// Check that this is a read, not a write.
if !is_in_assignment_position(self.cx, expr);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatLiteral {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) {
if_chain! {
- let ty = cx.tables.expr_ty(expr);
+ let ty = cx.tables().expr_ty(expr);
if let ty::Float(fty) = ty.kind;
if let hir::ExprKind::Lit(ref lit) = expr.kind;
if let LitKind::Float(sym, lit_float_ty) = lit.node;
// Returns the specialized log method for a given base if base is constant
// and is one of 2, 10 and e
fn get_specialized_log_method(cx: &LateContext<'_, '_>, base: &Expr<'_>) -> Option<&'static str> {
- if let Some((value, _)) = constant(cx, cx.tables, base) {
+ if let Some((value, _)) = constant(cx, cx.tables(), base) {
if F32(2.0) == value || F64(2.0) == value {
return Some("log2");
} else if F32(10.0) == value || F64(10.0) == value {
if_chain! {
// if the expression is a float literal and it is unsuffixed then
// add a suffix so the suggestion is valid and unambiguous
- if let ty::Float(float_ty) = cx.tables.expr_ty(expr).kind;
+ if let ty::Float(float_ty) = cx.tables().expr_ty(expr).kind;
if let ExprKind::Lit(lit) = &expr.kind;
if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node;
then {
rhs,
) = &args[0].kind
{
- let recv = match (constant(cx, cx.tables, lhs), constant(cx, cx.tables, rhs)) {
+ let recv = match (constant(cx, cx.tables(), lhs), constant(cx, cx.tables(), rhs)) {
(Some((value, _)), _) if F32(1.0) == value || F64(1.0) == value => rhs,
(_, Some((value, _))) if F32(1.0) == value || F64(1.0) == value => lhs,
_ => return,
fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
// Check receiver
- if let Some((value, _)) = constant(cx, cx.tables, &args[0]) {
+ if let Some((value, _)) = constant(cx, cx.tables(), &args[0]) {
let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
"exp"
} else if F32(2.0) == value || F64(2.0) == value {
}
// Check argument
- if let Some((value, _)) = constant(cx, cx.tables, &args[1]) {
+ if let Some((value, _)) = constant(cx, cx.tables(), &args[1]) {
let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
(
SUBOPTIMAL_FLOPS,
fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
if_chain! {
if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, ref lhs, ref rhs) = expr.kind;
- if cx.tables.expr_ty(lhs).is_floating_point();
- if let Some((value, _)) = constant(cx, cx.tables, rhs);
+ if cx.tables().expr_ty(lhs).is_floating_point();
+ if let Some((value, _)) = constant(cx, cx.tables(), rhs);
if F32(1.0) == value || F64(1.0) == value;
if let ExprKind::MethodCall(ref path, _, ref method_args, _) = lhs.kind;
- if cx.tables.expr_ty(&method_args[0]).is_floating_point();
+ if cx.tables().expr_ty(&method_args[0]).is_floating_point();
if path.ident.name.as_str() == "exp";
then {
span_lint_and_sugg(
fn is_float_mul_expr<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
if_chain! {
if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref lhs, ref rhs) = &expr.kind;
- if cx.tables.expr_ty(lhs).is_floating_point();
- if cx.tables.expr_ty(rhs).is_floating_point();
+ if cx.tables().expr_ty(lhs).is_floating_point();
+ if cx.tables().expr_ty(rhs).is_floating_point();
then {
return Some((lhs, rhs));
}
/// Returns true iff expr is some zero literal
fn is_zero(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
- match constant_simple(cx, cx.tables, expr) {
+ match constant_simple(cx, cx.tables(), expr) {
Some(Constant::Int(i)) => i == 0,
Some(Constant::F32(f)) => f == 0.0,
Some(Constant::F64(f)) => f == 0.0,
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::MethodCall(ref path, _, args, _) = &expr.kind {
- let recv_ty = cx.tables.expr_ty(&args[0]);
+ let recv_ty = cx.tables().expr_ty(&args[0]);
if recv_ty.is_floating_point() {
match &*path.ident.name.as_str() {
// matches `core::fmt::Display::fmt`
if args.len() == 2;
if let ExprKind::Path(ref qpath) = args[1].kind;
- if let Some(did) = cx.tables.qpath_res(qpath, args[1].hir_id).opt_def_id();
+ if let Some(did) = cx.tables().qpath_res(qpath, args[1].hir_id).opt_def_id();
if match_def_path(cx, did, &paths::DISPLAY_FMT_METHOD);
// check `(arg0,)` in match block
if let PatKind::Tuple(ref pats, None) = arms[0].pat.kind;
if pats.len() == 1;
then {
- let ty = walk_ptrs_ty(cx.tables.pat_ty(&pats[0]));
+ let ty = walk_ptrs_ty(cx.tables().pat_ty(&pats[0]));
if ty.kind != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) {
return None;
}
// primitive types are never mutable
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
ty::Adt(ref adt, ref substs) => {
- tys.insert(adt.did) && !ty.is_freeze(cx.tcx, cx.param_env, span)
+ tys.insert(adt.did) && !ty.is_freeze(cx.tcx.at(span), cx.param_env)
|| KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did, path))
&& substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys))
},
// Argument 0 (the struct we're calling the method on) is a vector
if let Some(struct_calling_on) = args.get(0);
- let struct_ty = cx.tables.expr_ty(struct_calling_on);
+ let struct_ty = cx.tables().expr_ty(struct_calling_on);
if is_type_diagnostic_item(cx, struct_ty, sym!(vec_type));
// Argument to "get" is a subtraction
// `1 << 0` is a common pattern in bit manipulation code
if_chain! {
if let BinOpKind::Shl = cmp.node;
- if let Some(Constant::Int(0)) = constant_simple(cx, cx.tables, right);
- if let Some(Constant::Int(1)) = constant_simple(cx, cx.tables, left);
+ if let Some(Constant::Int(0)) = constant_simple(cx, cx.tables(), right);
+ if let Some(Constant::Int(1)) = constant_simple(cx, cx.tables(), left);
then {
return true;
}
#[allow(clippy::cast_possible_wrap)]
fn check(cx: &LateContext<'_, '_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) {
- if let Some(Constant::Int(v)) = constant_simple(cx, cx.tables, e) {
- let check = match cx.tables.expr_ty(e).kind {
+ if let Some(Constant::Int(v)) = constant_simple(cx, cx.tables(), e) {
+ let check = match cx.tables().expr_ty(e).kind {
ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
ty::Uint(uty) => clip(cx.tcx, !0, uty),
_ => return,
if_chain! {
if let ExprKind::MethodCall(path, _span, args, _) = &expr.kind;
if path.ident.to_string() == "lock";
- let ty = cx.tables.expr_ty(&args[0]);
+ let ty = cx.tables().expr_ty(&args[0]);
if is_type_diagnostic_item(cx, ty, sym!(mutex_type));
then {
Some(&args[0])
if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = op.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation
if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
- if is_type_diagnostic_item(cx, cx.tables.expr_ty(&result_types[0]), sym!(result_type));
+ if is_type_diagnostic_item(cx, cx.tables().expr_ty(&result_types[0]), sym!(result_type));
if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";
then {
ExprKind::Call(expr, ..) => {
if_chain! {
if let ExprKind::Path(qpath) = &expr.kind;
- if let Some(path_def_id) = cx.tables.qpath_res(qpath, expr.hir_id).opt_def_id();
+ if let Some(path_def_id) = cx.tables().qpath_res(qpath, expr.hir_id).opt_def_id();
if match_def_path(cx, path_def_id, &BEGIN_PANIC) ||
match_def_path(cx, path_def_id, &BEGIN_PANIC_FMT);
then { }
};
// Check if the variable in the condition statement is an integer
- if !cx.tables.expr_ty(cond_var).is_integral() {
+ if !cx.tables().expr_ty(cond_var).is_integral() {
return;
}
ExprKind::Lit(ref cond_lit) => {
// Check if the constant is zero
if let LitKind::Int(0, _) = cond_lit.node {
- if cx.tables.expr_ty(cond_left).is_signed() {
+ if cx.tables().expr_ty(cond_left).is_signed() {
} else {
print_lint_and_sugg(cx, &var_name, expr);
};
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Index(ref array, ref index) = &expr.kind {
- let ty = cx.tables.expr_ty(array);
+ let ty = cx.tables().expr_ty(array);
if let Some(range) = higher::range(cx, index) {
// Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
if let ty::Array(_, s) = ty.kind {
// Catchall non-range index, i.e., [n] or [n << m]
if let ty::Array(..) = ty.kind {
// Index is a constant uint.
- if let Some(..) = constant(cx, cx.tables, index) {
+ if let Some(..) = constant(cx, cx.tables(), index) {
// Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
return;
}
range: higher::Range<'_>,
array_size: u128,
) -> (Option<u128>, Option<u128>) {
- let s = range.start.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
+ let s = range.start.map(|expr| constant(cx, cx.tables(), expr).map(|(c, _)| c));
let start = match s {
Some(Some(Constant::Int(x))) => Some(x),
Some(_) => None,
None => Some(0),
};
- let e = range.end.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
+ let e = range.end.map(|expr| constant(cx, cx.tables(), expr).map(|(c, _)| c));
let end = match e {
Some(Some(Constant::Int(x))) => {
if range.limits == RangeLimits::Closed {
}
}
if method.ident.name == sym!(last) && args.len() == 1 {
- let not_double_ended = get_trait_def_id(cx, &paths::DOUBLE_ENDED_ITERATOR)
- .map_or(false, |id| !implements_trait(cx, cx.tables.expr_ty(&args[0]), id, &[]));
+ let not_double_ended = get_trait_def_id(cx, &paths::DOUBLE_ENDED_ITERATOR).map_or(false, |id| {
+ !implements_trait(cx, cx.tables().expr_ty(&args[0]), id, &[])
+ });
if not_double_ended {
return is_infinite(cx, &args[0]);
}
} else if method.ident.name == sym!(collect) {
- let ty = cx.tables.expr_ty(expr);
+ let ty = cx.tables().expr_ty(expr);
if INFINITE_COLLECTORS.iter().any(|path| match_type(cx, ty, path)) {
return is_infinite(cx, &args[0]);
}
if let hir::ExprKind::Binary(binop, left, right) = &expr.kind;
if let hir::BinOpKind::Div = &binop.node;
then {
- let (left_ty, right_ty) = (cx.tables.expr_ty(left), cx.tables.expr_ty(right));
+ let (left_ty, right_ty) = (cx.tables().expr_ty(left), cx.tables().expr_ty(right));
return left_ty.is_integral() && right_ty.is_integral();
}
}
fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
if_chain! {
if let ExprKind::Repeat(_, _) = expr.kind;
- if let ty::Array(element_type, cst) = cx.tables.expr_ty(expr).kind;
+ if let ty::Array(element_type, cst) = cx.tables().expr_ty(expr).kind;
if let ConstKind::Value(val) = cst.val;
if let ConstValue::Scalar(element_count) = val;
if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx);
}
fn check_cmp(cx: &LateContext<'_, '_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
- if let (&ExprKind::MethodCall(ref method_path, _, ref args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
+ if let (&ExprKind::MethodCall(ref method_path, _, ref args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind)
+ {
// check if we are in an is_empty() method
if let Some(name) = get_item_name(cx, method) {
if name.as_str() == "is_empty" {
return false;
}
- let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr));
+ let ty = &walk_ptrs_ty(cx.tables().expr_ty(expr));
match ty.kind {
ty::Dynamic(ref tt, ..) => {
if let Some(principal) = tt.principal() {
impl BorrowVisitor<'_, '_> {
fn fn_def_id(&self, expr: &Expr<'_>) -> Option<DefId> {
match &expr.kind {
- ExprKind::MethodCall(..) => self.cx.tables.type_dependent_def_id(expr.hir_id),
+ ExprKind::MethodCall(..) => self.cx.tables().type_dependent_def_id(expr.hir_id),
ExprKind::Call(
Expr {
kind: ExprKind::Path(qpath),
..
},
..,
- ) => self.cx.tables.qpath_res(qpath, expr.hir_id).opt_def_id(),
+ ) => self.cx.tables().qpath_res(qpath, expr.hir_id).opt_def_id(),
_ => None,
}
}
then {
let span = stmt.span.to(if_.span);
- let has_interior_mutability = !cx.tables.node_type(canonical_id).is_freeze(
- cx.tcx,
+ let has_interior_mutability = !cx.tables().node_type(canonical_id).is_freeze(
+ cx.tcx.at(span),
cx.param_env,
- span
);
if has_interior_mutability { return; }
/// **What it does:** Checks for `let _ = sync_lock`
///
/// **Why is this bad?** This statement immediately drops the lock instead of
- /// extending it's lifetime to the end of the scope, which is often not intended.
+ /// extending its lifetime to the end of the scope, which is often not intended.
/// To extend lock lifetime to the end of the scope, use an underscore-prefixed
/// name instead (i.e. _lock). If you want to explicitly drop the lock,
/// `std::mem::drop` conveys your intention better and is less error-prone.
if let PatKind::Wild = local.pat.kind;
if let Some(ref init) = local.init;
then {
- let init_ty = cx.tables.expr_ty(init);
+ let init_ty = cx.tables().expr_ty(init);
let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
GenericArgKind::Type(inner_ty) => {
SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path))
"consider using an underscore-prefixed named \
binding or dropping explicitly with `std::mem::drop`"
)
- } else if is_must_use_ty(cx, cx.tables.expr_ty(init)) {
+ } else if is_must_use_ty(cx, cx.tables().expr_ty(init)) {
span_lint_and_help(
cx,
LET_UNDERSCORE_MUST_USE,
// error-pattern:cargo-clippy
#![feature(bindings_after_at)]
-#![feature(box_syntax)]
#![feature(box_patterns)]
+#![feature(box_syntax)]
+#![feature(concat_idents)]
+#![feature(crate_visibility_modifier)]
+#![feature(drain_filter)]
#![feature(or_patterns)]
#![feature(rustc_private)]
#![feature(stmt_expr_attributes)]
-#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]
#![recursion_limit = "512"]
-#![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)]
-#![deny(rustc::internal)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
-#![feature(crate_visibility_modifier)]
-#![feature(concat_idents)]
-#![feature(drain_filter)]
+#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]
+#![warn(trivial_casts, trivial_numeric_casts)]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
+// warn on rustc internal lints
+#![deny(rustc::internal)]
// FIXME: switch to something more ergonomic here, once available.
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
-#[allow(unused_extern_crates)]
extern crate rustc_ast;
-#[allow(unused_extern_crates)]
extern crate rustc_ast_pretty;
-#[allow(unused_extern_crates)]
extern crate rustc_attr;
-#[allow(unused_extern_crates)]
extern crate rustc_data_structures;
-#[allow(unused_extern_crates)]
-extern crate rustc_driver;
-#[allow(unused_extern_crates)]
extern crate rustc_errors;
-#[allow(unused_extern_crates)]
extern crate rustc_hir;
-#[allow(unused_extern_crates)]
extern crate rustc_hir_pretty;
-#[allow(unused_extern_crates)]
extern crate rustc_index;
-#[allow(unused_extern_crates)]
extern crate rustc_infer;
-#[allow(unused_extern_crates)]
extern crate rustc_lexer;
-#[allow(unused_extern_crates)]
extern crate rustc_lint;
-#[allow(unused_extern_crates)]
extern crate rustc_middle;
-#[allow(unused_extern_crates)]
extern crate rustc_mir;
-#[allow(unused_extern_crates)]
extern crate rustc_parse;
-#[allow(unused_extern_crates)]
extern crate rustc_parse_format;
-#[allow(unused_extern_crates)]
extern crate rustc_session;
-#[allow(unused_extern_crates)]
extern crate rustc_span;
-#[allow(unused_extern_crates)]
extern crate rustc_target;
-#[allow(unused_extern_crates)]
extern crate rustc_trait_selection;
-#[allow(unused_extern_crates)]
extern crate rustc_typeck;
use rustc_data_structures::fx::FxHashSet;
/// # Example
///
/// ```
-/// # #![feature(rustc_private)]
-/// # #[allow(unused_extern_crates)]
-/// # extern crate rustc_middle;
-/// # #[allow(unused_extern_crates)]
-/// # extern crate rustc_session;
-/// # #[macro_use]
-/// # use clippy_lints::declare_clippy_lint;
+/// #![feature(rustc_private)]
+/// extern crate rustc_session;
/// use rustc_session::declare_tool_lint;
+/// use clippy_lints::declare_clippy_lint;
///
/// declare_clippy_lint! {
/// /// **What it does:** Checks for ... (describe what the lint matches).
store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
- store.register_early_pass(|| box macro_use::MacroUseImports);
store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
store.register_late_pass(|| box unnamed_address::UnnamedAddress);
single_char_binding_names_threshold,
});
store.register_early_pass(|| box unnested_or_patterns::UnnestedOrPatterns);
+ store.register_late_pass(|| box macro_use::MacroUseImports::default());
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
LintId::of(&types::OPTION_OPTION),
LintId::of(&unicode::NON_ASCII_LITERAL),
LintId::of(&unicode::UNICODE_NOT_NFC),
+ LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
LintId::of(&unused_self::UNUSED_SELF),
LintId::of(&wildcard_imports::ENUM_GLOB_USE),
LintId::of(&wildcard_imports::WILDCARD_IMPORTS),
LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
- LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
LintId::of(&unwrap::PANICKING_UNWRAP),
LintId::of(&types::UNNECESSARY_CAST),
LintId::of(&types::VEC_BOX),
LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
- LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
LintId::of(&unwrap::UNNECESSARY_UNWRAP),
LintId::of(&useless_conversion::USELESS_CONVERSION),
LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
})
{
let hir_id = ty.hir_id;
- match self.cx.tables.qpath_res(qpath, hir_id) {
+ match self.cx.tables().qpath_res(qpath, hir_id) {
Res::Def(DefKind::TyAlias | DefKind::Struct, def_id) => {
let generics = self.cx.tcx.generics_of(def_id);
for _ in generics.params.as_slice() {
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol;
-use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase};
+use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use std::iter::{once, Iterator};
use std::mem;
if_chain! {
if let ExprKind::MethodCall(..) | ExprKind::Call(..) = iter_expr.kind;
if let Some(iter_def_id) = get_trait_def_id(cx, &paths::ITERATOR);
- if implements_trait(cx, cx.tables.expr_ty(iter_expr), iter_def_id, &[]);
+ if implements_trait(cx, cx.tables().expr_ty(iter_expr), iter_def_id, &[]);
then {
return;
}
if_chain! {
if let ExprKind::Index(seqexpr_left, idx_left) = lhs.kind;
if let ExprKind::Index(seqexpr_right, idx_right) = rhs.kind;
- if is_slice_like(cx, cx.tables.expr_ty(seqexpr_left))
- && is_slice_like(cx, cx.tables.expr_ty(seqexpr_right));
+ if is_slice_like(cx, cx.tables().expr_ty(seqexpr_left))
+ && is_slice_like(cx, cx.tables().expr_ty(seqexpr_right));
if let Some(offset_left) = get_offset(cx, &idx_left, canonical_id);
if let Some(offset_right) = get_offset(cx, &idx_right, canonical_id);
lint_iter_method(cx, args, arg, method_name);
}
} else if method_name == "into_iter" && match_trait_method(cx, arg, &paths::INTO_ITERATOR) {
- let receiver_ty = cx.tables.expr_ty(&args[0]);
- let receiver_ty_adjusted = cx.tables.expr_ty_adjusted(&args[0]);
+ let receiver_ty = cx.tables().expr_ty(&args[0]);
+ let receiver_ty_adjusted = cx.tables().expr_ty_adjusted(&args[0]);
if TyS::same_type(receiver_ty, receiver_ty_adjusted) {
let mut applicability = Applicability::MachineApplicable;
let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
/// Checks for `for` loops over `Option`s and `Result`s.
fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>) {
- let ty = cx.tables.expr_ty(arg);
+ let ty = cx.tables().expr_ty(arg);
if is_type_diagnostic_item(cx, ty, sym!(option_type)) {
span_lint_and_help(
cx,
/// actual `Iterator` that the loop uses.
fn make_iterator_snippet(cx: &LateContext<'_, '_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String {
let impls_iterator = get_trait_def_id(cx, &paths::ITERATOR)
- .map_or(false, |id| implements_trait(cx, cx.tables.expr_ty(arg), id, &[]));
+ .map_or(false, |id| implements_trait(cx, cx.tables().expr_ty(arg), id, &[]));
if impls_iterator {
format!(
"{}",
// (&mut x).into_iter() ==> x.iter_mut()
match &arg.kind {
ExprKind::AddrOf(BorrowKind::Ref, mutability, arg_inner)
- if has_iter_method(cx, cx.tables.expr_ty(&arg_inner)).is_some() =>
+ if has_iter_method(cx, cx.tables().expr_ty(&arg_inner)).is_some() =>
{
let meth_name = match mutability {
Mutability::Mut => "iter_mut",
if let PatKind::Tuple(ref pat, _) = pat.kind {
if pat.len() == 2 {
let arg_span = arg.span;
- let (new_pat_span, kind, ty, mutbl) = match cx.tables.expr_ty(arg).kind {
+ let (new_pat_span, kind, ty, mutbl) = match cx.tables().expr_ty(arg).kind {
ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) {
(key, _) if pat_is_wild(key, body) => (pat[1].span, "value", ty, mutbl),
(_, value) if pat_is_wild(value, body) => (pat[0].span, "key", ty, Mutability::Not),
}
}
-struct MutatePairDelegate {
+struct MutatePairDelegate<'a, 'tcx> {
+ cx: &'a LateContext<'a, 'tcx>,
hir_id_low: Option<HirId>,
hir_id_high: Option<HirId>,
span_low: Option<Span>,
span_high: Option<Span>,
}
-impl<'tcx> Delegate<'tcx> for MutatePairDelegate {
- fn consume(&mut self, _: &Place<'tcx>, _: ConsumeMode) {}
+impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
+ fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: ConsumeMode) {}
- fn borrow(&mut self, cmt: &Place<'tcx>, bk: ty::BorrowKind) {
+ fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) {
if let ty::BorrowKind::MutBorrow = bk {
- if let PlaceBase::Local(id) = cmt.base {
+ if let PlaceBase::Local(id) = cmt.place.base {
if Some(id) == self.hir_id_low {
- self.span_low = Some(cmt.span)
+ self.span_low = Some(self.cx.tcx.hir().span(cmt.hir_id))
}
if Some(id) == self.hir_id_high {
- self.span_high = Some(cmt.span)
+ self.span_high = Some(self.cx.tcx.hir().span(cmt.hir_id))
}
}
}
}
- fn mutate(&mut self, cmt: &Place<'tcx>) {
- if let PlaceBase::Local(id) = cmt.base {
+ fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) {
+ if let PlaceBase::Local(id) = cmt.place.base {
if Some(id) == self.hir_id_low {
- self.span_low = Some(cmt.span)
+ self.span_low = Some(self.cx.tcx.hir().span(cmt.hir_id))
}
if Some(id) == self.hir_id_high {
- self.span_high = Some(cmt.span)
+ self.span_high = Some(self.cx.tcx.hir().span(cmt.hir_id))
}
}
}
}
-impl<'tcx> MutatePairDelegate {
+impl MutatePairDelegate<'_, '_> {
fn mutation_span(&self) -> (Option<Span>, Option<Span>) {
(self.span_low, self.span_high)
}
None
}
-fn check_for_mutation(
- cx: &LateContext<'_, '_>,
+fn check_for_mutation<'a, 'tcx>(
+ cx: &LateContext<'a, 'tcx>,
body: &Expr<'_>,
bound_ids: &[Option<HirId>],
) -> (Option<Span>, Option<Span>) {
let mut delegate = MutatePairDelegate {
+ cx,
hir_id_low: bound_ids[0],
hir_id_high: bound_ids[1],
span_low: None,
};
let def_id = body.hir_id.owner.to_def_id();
cx.tcx.infer_ctxt().enter(|infcx| {
- ExprUseVisitor::new(&mut delegate, &infcx, def_id.expect_local(), cx.param_env, cx.tables).walk_expr(body);
+ ExprUseVisitor::new(&mut delegate, &infcx, def_id.expect_local(), cx.param_env, cx.tables()).walk_expr(body);
});
delegate.mutation_span()
}
if index_used_directly {
self.indexed_directly.insert(
seqvar.segments[0].ident.name,
- (Some(extent), self.cx.tables.node_type(seqexpr.hir_id)),
+ (Some(extent), self.cx.tables().node_type(seqexpr.hir_id)),
);
}
return false; // no need to walk further *on the variable*
if index_used_directly {
self.indexed_directly.insert(
seqvar.segments[0].ident.name,
- (None, self.cx.tables.node_type(seqexpr.hir_id)),
+ (None, self.cx.tables().node_type(seqexpr.hir_id)),
);
}
return false; // no need to walk further *on the variable*
ExprKind::Call(ref f, args) => {
self.visit_expr(f);
for expr in args {
- let ty = self.cx.tables.expr_ty_adjusted(expr);
+ let ty = self.cx.tables().expr_ty_adjusted(expr);
self.prefer_mutable = false;
if let ty::Ref(_, _, mutbl) = ty.kind {
if mutbl == Mutability::Mut {
}
},
ExprKind::MethodCall(_, _, args, _) => {
- let def_id = self.cx.tables.type_dependent_def_id(expr.hir_id).unwrap();
+ let def_id = self.cx.tables().type_dependent_def_id(expr.hir_id).unwrap();
for (ty, expr) in self.cx.tcx.fn_sig(def_id).inputs().skip_binder().iter().zip(args) {
self.prefer_mutable = false;
if let ty::Ref(_, _, mutbl) = ty.kind {
fn is_ref_iterable_type(cx: &LateContext<'_, '_>, e: &Expr<'_>) -> bool {
// no walk_ptrs_ty: calling iter() on a reference can make sense because it
// will allow further borrows afterwards
- let ty = cx.tables.expr_ty(e);
+ let ty = cx.tables().expr_ty(e);
is_iterable_array(ty, cx) ||
is_type_diagnostic_item(cx, ty, sym!(vec_type)) ||
match_type(cx, ty, &paths::LINKED_LIST) ||
if self.state == VarState::DontWarn {
return;
}
- if SpanlessEq::new(self.cx).eq_expr(&expr, self.end_expr) {
+ if expr.hir_id == self.end_expr.hir_id {
self.past_loop = true;
return;
}
}
fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) {
- if constant(cx, cx.tables, cond).is_some() {
+ if constant(cx, cx.tables(), cond).is_some() {
// A pure constant condition (e.g., `while false`) is not linted.
return;
}
has_break_or_return: bool,
}
-impl<'a, 'tcx> Visitor<'tcx> for HasBreakOrReturnVisitor {
+impl<'tcx> Visitor<'tcx> for HasBreakOrReturnVisitor {
type Map = Map<'tcx>;
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
if let Some(ref generic_args) = chain_method.args;
if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
then {
- let ty = cx.tables.node_type(ty.hir_id);
+ let ty = cx.tables().node_type(ty.hir_id);
if is_type_diagnostic_item(cx, ty, sym!(vec_type)) ||
is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) ||
match_type(cx, ty, &paths::BTREEMAP) ||
-use crate::utils::{snippet, span_lint_and_sugg};
+use crate::utils::{in_macro, snippet, span_lint_and_sugg};
+use hir::def::{DefKind, Res};
use if_chain::if_chain;
use rustc_ast::ast;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::edition::Edition;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{edition::Edition, Span};
declare_clippy_lint! {
/// **What it does:** Checks for `#[macro_use] use...`.
/// **Why is this bad?** Since the Rust 2018 edition you can import
/// macro's directly, this is considered idiomatic.
///
- /// **Known problems:** This lint does not generate an auto-applicable suggestion.
+ /// **Known problems:** None.
///
/// **Example:**
/// ```rust
"#[macro_use] is no longer needed"
}
-declare_lint_pass!(MacroUseImports => [MACRO_USE_IMPORTS]);
+const BRACKETS: &[char] = &['<', '>'];
-impl EarlyLintPass for MacroUseImports {
- fn check_item(&mut self, ecx: &EarlyContext<'_>, item: &ast::Item) {
+#[derive(Clone, Debug, PartialEq, Eq)]
+struct PathAndSpan {
+ path: String,
+ span: Span,
+}
+
+/// `MacroRefData` includes the name of the macro
+/// and the path from `SourceMap::span_to_filename`.
+#[derive(Debug, Clone)]
+pub struct MacroRefData {
+ name: String,
+ path: String,
+}
+
+impl MacroRefData {
+ pub fn new(name: String, callee: Span, cx: &LateContext<'_, '_>) -> Self {
+ let mut path = cx.sess().source_map().span_to_filename(callee).to_string();
+
+ // std lib paths are <::std::module::file type>
+ // so remove brackets, space and type.
+ if path.contains('<') {
+ path = path.replace(BRACKETS, "");
+ }
+ if path.contains(' ') {
+ path = path.split(' ').next().unwrap().to_string();
+ }
+ Self { name, path }
+ }
+}
+
+#[derive(Default)]
+#[allow(clippy::module_name_repetitions)]
+pub struct MacroUseImports {
+ /// the actual import path used and the span of the attribute above it.
+ imports: Vec<(String, Span)>,
+ /// the span of the macro reference, kept to ensure only one reference is used per macro call.
+ collected: FxHashSet<Span>,
+ mac_refs: Vec<MacroRefData>,
+}
+
+impl_lint_pass!(MacroUseImports => [MACRO_USE_IMPORTS]);
+
+impl MacroUseImports {
+ fn push_unique_macro(&mut self, cx: &LateContext<'_, '_>, span: Span) {
+ let call_site = span.source_callsite();
+ let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
+ if let Some(callee) = span.source_callee() {
+ if !self.collected.contains(&call_site) {
+ let name = if name.contains("::") {
+ name.split("::").last().unwrap().to_string()
+ } else {
+ name.to_string()
+ };
+
+ self.mac_refs.push(MacroRefData::new(name, callee.def_site, cx));
+ self.collected.insert(call_site);
+ }
+ }
+ }
+
+ fn push_unique_macro_pat_ty(&mut self, cx: &LateContext<'_, '_>, span: Span) {
+ let call_site = span.source_callsite();
+ let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
+ if let Some(callee) = span.source_callee() {
+ if !self.collected.contains(&call_site) {
+ self.mac_refs
+ .push(MacroRefData::new(name.to_string(), callee.def_site, cx));
+ self.collected.insert(call_site);
+ }
+ }
+ }
+}
+
+impl<'l, 'txc> LateLintPass<'l, 'txc> for MacroUseImports {
+ fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item<'_>) {
if_chain! {
- if ecx.sess.opts.edition == Edition::Edition2018;
- if let ast::ItemKind::Use(use_tree) = &item.kind;
+ if cx.sess().opts.edition == Edition::Edition2018;
+ if let hir::ItemKind::Use(path, _kind) = &item.kind;
if let Some(mac_attr) = item
.attrs
.iter()
.find(|attr| attr.ident().map(|s| s.to_string()) == Some("macro_use".to_string()));
+ if let Res::Def(DefKind::Mod, id) = path.res;
then {
- let msg = "`macro_use` attributes are no longer needed in the Rust 2018 edition";
- let help = format!("use {}::<macro name>", snippet(ecx, use_tree.span, "_"));
+ for kid in cx.tcx.item_children(id).iter() {
+ if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res {
+ let span = mac_attr.span;
+ let def_path = cx.tcx.def_path_str(mac_id);
+ self.imports.push((def_path, span));
+ }
+ }
+ } else {
+ if in_macro(item.span) {
+ self.push_unique_macro_pat_ty(cx, item.span);
+ }
+ }
+ }
+ }
+ fn check_attribute(&mut self, cx: &LateContext<'_, '_>, attr: &ast::Attribute) {
+ if in_macro(attr.span) {
+ self.push_unique_macro(cx, attr.span);
+ }
+ }
+ fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) {
+ if in_macro(expr.span) {
+ self.push_unique_macro(cx, expr.span);
+ }
+ }
+ fn check_stmt(&mut self, cx: &LateContext<'_, '_>, stmt: &hir::Stmt<'_>) {
+ if in_macro(stmt.span) {
+ self.push_unique_macro(cx, stmt.span);
+ }
+ }
+ fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat<'_>) {
+ if in_macro(pat.span) {
+ self.push_unique_macro_pat_ty(cx, pat.span);
+ }
+ }
+ fn check_ty(&mut self, cx: &LateContext<'_, '_>, ty: &hir::Ty<'_>) {
+ if in_macro(ty.span) {
+ self.push_unique_macro_pat_ty(cx, ty.span);
+ }
+ }
+ #[allow(clippy::too_many_lines)]
+ fn check_crate_post(&mut self, cx: &LateContext<'_, '_>, _krate: &hir::Crate<'_>) {
+ let mut used = FxHashMap::default();
+ let mut check_dup = vec![];
+ for (import, span) in &self.imports {
+ let found_idx = self.mac_refs.iter().position(|mac| import.ends_with(&mac.name));
+
+ if let Some(idx) = found_idx {
+ let _ = self.mac_refs.remove(idx);
+ let seg = import.split("::").collect::<Vec<_>>();
+
+ match seg.as_slice() {
+ // an empty path is impossible
+ // a path should always consist of 2 or more segments
+ [] | [_] => return,
+ [root, item] => {
+ if !check_dup.contains(&(*item).to_string()) {
+ used.entry(((*root).to_string(), span))
+ .or_insert_with(Vec::new)
+ .push((*item).to_string());
+ check_dup.push((*item).to_string());
+ }
+ },
+ [root, rest @ ..] => {
+ if rest.iter().all(|item| !check_dup.contains(&(*item).to_string())) {
+ let filtered = rest
+ .iter()
+ .filter_map(|item| {
+ if check_dup.contains(&(*item).to_string()) {
+ None
+ } else {
+ Some((*item).to_string())
+ }
+ })
+ .collect::<Vec<_>>();
+ used.entry(((*root).to_string(), span))
+ .or_insert_with(Vec::new)
+ .push(filtered.join("::"));
+ check_dup.extend(filtered);
+ } else {
+ let rest = rest.to_vec();
+ used.entry(((*root).to_string(), span))
+ .or_insert_with(Vec::new)
+ .push(rest.join("::"));
+ check_dup.extend(rest.iter().map(ToString::to_string));
+ }
+ },
+ }
+ }
+ }
+
+ let mut suggestions = vec![];
+ for ((root, span), path) in used {
+ if path.len() == 1 {
+ suggestions.push((span, format!("{}::{}", root, path[0])))
+ } else {
+ suggestions.push((span, format!("{}::{{{}}}", root, path.join(", "))))
+ }
+ }
+
+ // If mac_refs is not empty we have encountered an import we could not handle
+ // such as `std::prelude::v1::foo` or some other macro that expands to an import.
+ if self.mac_refs.is_empty() {
+ for (span, import) in suggestions {
+ let help = format!("use {};", import);
span_lint_and_sugg(
- ecx,
+ cx,
MACRO_USE_IMPORTS,
- mac_attr.span,
- msg,
+ *span,
+ "`macro_use` attributes are no longer needed in the Rust 2018 edition",
"remove the attribute and import the macro directly, try",
help,
- Applicability::HasPlaceholders,
- );
+ Applicability::MaybeIncorrect,
+ )
}
}
}
if let hir::ExprKind::MethodCall(ref method, _, ref args, _) = e.kind;
if args.len() == 2;
if method.ident.as_str() == "map";
- let ty = cx.tables.expr_ty(&args[0]);
+ let ty = cx.tables().expr_ty(&args[0]);
if is_type_diagnostic_item(cx, ty, sym!(option_type)) || match_trait_method(cx, e, &paths::ITERATOR);
if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind;
let closure_body = cx.tcx.hir().body(body_id);
match closure_expr.kind {
hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) => {
if ident_eq(name, inner) {
- if let ty::Ref(.., Mutability::Not) = cx.tables.expr_ty(inner).kind {
+ if let ty::Ref(.., Mutability::Not) = cx.tables().expr_ty(inner).kind {
lint(cx, e.span, args[0].span, true);
}
}
if ident_eq(name, &obj[0]) && method.ident.as_str() == "clone"
&& match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) {
- let obj_ty = cx.tables.expr_ty(&obj[0]);
+ let obj_ty = cx.tables().expr_ty(&obj[0]);
if let ty::Ref(_, ty, _) = obj_ty.kind {
let copy = is_copy(cx, ty);
lint(cx, e.span, args[0].span, copy);
}
fn is_unit_function(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) -> bool {
- let ty = cx.tables.expr_ty(expr);
+ let ty = cx.tables().expr_ty(expr);
if let ty::FnDef(id, _) = ty.kind {
if let Some(fn_type) = cx.tcx.fn_sig(id).no_bound_vars() {
}
fn is_unit_expression(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) -> bool {
- is_unit_type(cx.tables.expr_ty(expr))
+ is_unit_type(cx.tables().expr_ty(expr))
}
/// The expression inside a closure may or may not have surrounding braces and
fn lint_map_unit_fn(cx: &LateContext<'_, '_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) {
let var_arg = &map_args[0];
- let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.tables.expr_ty(var_arg), sym!(option_type)) {
+ let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.tables().expr_ty(var_arg), sym!(option_type)) {
("Option", "Some", OPTION_MAP_UNIT_FN)
- } else if is_type_diagnostic_item(cx, cx.tables.expr_ty(var_arg), sym!(result_type)) {
+ } else if is_type_diagnostic_item(cx, cx.tables().expr_ty(var_arg), sym!(result_type)) {
("Result", "Ok", RESULT_MAP_UNIT_FN)
} else {
return;
}
fn is_vector(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
- let ty = cx.tables.expr_ty(expr);
+ let ty = cx.tables().expr_ty(expr);
let ty = walk_ptrs_ty(ty);
is_type_diagnostic_item(cx, ty, sym!(vec_type))
}
fn is_full_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
- let ty = cx.tables.expr_ty(expr);
+ let ty = cx.tables().expr_ty(expr);
let ty = walk_ptrs_ty(ty);
match_type(cx, ty, &utils::paths::RANGE_FULL)
}
// allow match arms with just expressions
return;
};
- let ty = cx.tables.expr_ty(ex);
+ let ty = cx.tables().expr_ty(ex);
if ty.kind != ty::Bool || is_allowed(cx, MATCH_BOOL, ex.hir_id) {
check_single_match_single_pattern(cx, ex, arms, expr, els);
check_single_match_opt_like(cx, ex, arms, expr, ty, els);
fn check_match_bool(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
// Type of expression is `bool`.
- if cx.tables.expr_ty(ex).kind == ty::Bool {
+ if cx.tables().expr_ty(ex).kind == ty::Bool {
span_lint_and_then(
cx,
MATCH_BOOL,
}
fn check_overlapping_arms<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
- if arms.len() >= 2 && cx.tables.expr_ty(ex).is_integral() {
- let ranges = all_ranges(cx, arms, cx.tables.expr_ty(ex));
+ if arms.len() >= 2 && cx.tables().expr_ty(ex).is_integral() {
+ let ranges = all_ranges(cx, arms, cx.tables().expr_ty(ex));
let type_ranges = type_ranges(&ranges);
if !type_ranges.is_empty() {
if let Some((start, end)) = overlapping(&type_ranges) {
}
fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
- let ex_ty = walk_ptrs_ty(cx.tables.expr_ty(ex));
+ let ex_ty = walk_ptrs_ty(cx.tables().expr_ty(ex));
if is_type_diagnostic_item(cx, ex_ty, sym!(result_type)) {
for arm in arms {
if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind {
}
fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
- let ty = cx.tables.expr_ty(ex);
+ let ty = cx.tables().expr_ty(ex);
if !ty.is_enum() {
// If there isn't a nice closed set of possible values that can be conveniently enumerated,
// don't complain about not enumerating the mall.
"as_mut"
};
- let output_ty = cx.tables.expr_ty(expr);
- let input_ty = cx.tables.expr_ty(ex);
+ let output_ty = cx.tables().expr_ty(expr);
+ let input_ty = cx.tables().expr_ty(ex);
let cast = if_chain! {
if let ty::Adt(_, substs) = input_ty.kind;
match match_body.kind {
ExprKind::Block(block, _) => {
// macro + expr_ty(body) == ()
- if block.span.from_expansion() && cx.tables.expr_ty(&match_body).is_unit() {
+ if block.span.from_expansion() && cx.tables().expr_ty(&match_body).is_unit() {
snippet_body.push(';');
}
},
_ => {
// expr_ty(body) == ()
- if cx.tables.expr_ty(&match_body).is_unit() {
+ if cx.tables().expr_ty(&match_body).is_unit() {
snippet_body.push(';');
}
},
{
if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
let lhs = match lhs {
- Some(lhs) => constant(cx, cx.tables, lhs)?.0,
+ Some(lhs) => constant(cx, cx.tables(), lhs)?.0,
None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?,
};
let rhs = match rhs {
- Some(rhs) => constant(cx, cx.tables, rhs)?.0,
+ Some(rhs) => constant(cx, cx.tables(), rhs)?.0,
None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
};
let rhs = match range_end {
}
if let PatKind::Lit(ref value) = pat.kind {
- let value = constant(cx, cx.tables, value)?.0;
+ let value = constant(cx, cx.tables(), value)?.0;
return Some(SpannedRange {
span: pat.span,
node: (value.clone(), Bound::Included(value)),
if let ExprKind::Call(ref func, ref func_args) = expr.kind;
// is `mem::discriminant`
if let ExprKind::Path(ref func_qpath) = func.kind;
- if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id();
+ if let Some(def_id) = cx.tables().qpath_res(func_qpath, func.hir_id).opt_def_id();
if match_def_path(cx, def_id, &paths::MEM_DISCRIMINANT);
// type is non-enum
- let ty_param = cx.tables.node_substs(func.hir_id).type_at(0);
+ let ty_param = cx.tables().node_substs(func.hir_id).type_at(0);
if !ty_param.is_enum();
then {
if let ExprKind::Path(ref qpath) = path_expr.kind {
if let Some(def_id) = qpath_res(cx, qpath, path_expr.hir_id).opt_def_id() {
if match_def_path(cx, def_id, &paths::MEM_FORGET) {
- let forgot_ty = cx.tables.expr_ty(&args[0]);
+ let forgot_ty = cx.tables().expr_ty(&args[0]);
if forgot_ty.ty_adt_def().map_or(false, |def| def.has_dtor(cx.tcx)) {
span_lint(cx, MEM_FORGET, e.span, "usage of `mem::forget` on `Drop` type");
}
}
-fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr<'_>, expr_span: Span) {
- if let ExprKind::Call(ref repl_func, ref repl_args) = src.kind {
- if_chain! {
- if repl_args.is_empty();
- if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
- if let Some(repl_def_id) = cx.tables.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
- then {
- if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) {
- span_lint_and_help(
- cx,
- MEM_REPLACE_WITH_UNINIT,
- expr_span,
- "replacing with `mem::uninitialized()`",
- None,
- "consider using the `take_mut` crate instead",
- );
- } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) &&
- !cx.tables.expr_ty(src).is_primitive() {
- span_lint_and_help(
- cx,
- MEM_REPLACE_WITH_UNINIT,
- expr_span,
- "replacing with `mem::zeroed()`",
- None,
- "consider using a default value or the `take_mut` crate instead",
- );
- }
+fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) {
+ if_chain! {
+ // check if replacement is mem::MaybeUninit::uninit().assume_init()
+ if let Some(method_def_id) = cx.tables().type_dependent_def_id(src.hir_id);
+ if cx.tcx.is_diagnostic_item(sym::assume_init, method_def_id);
+ then {
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ MEM_REPLACE_WITH_UNINIT,
+ expr_span,
+ "replacing with `mem::MaybeUninit::uninit().assume_init()`",
+ "consider using",
+ format!(
+ "std::ptr::read({})",
+ snippet_with_applicability(cx, dest.span, "", &mut applicability)
+ ),
+ applicability,
+ );
+ return;
+ }
+ }
+
+ if_chain! {
+ if let ExprKind::Call(ref repl_func, ref repl_args) = src.kind;
+ if repl_args.is_empty();
+ if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
+ if let Some(repl_def_id) = cx.tables().qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
+ then {
+ if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) {
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ MEM_REPLACE_WITH_UNINIT,
+ expr_span,
+ "replacing with `mem::uninitialized()`",
+ "consider using",
+ format!(
+ "std::ptr::read({})",
+ snippet_with_applicability(cx, dest.span, "", &mut applicability)
+ ),
+ applicability,
+ );
+ } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) &&
+ !cx.tables().expr_ty(src).is_primitive() {
+ span_lint_and_help(
+ cx,
+ MEM_REPLACE_WITH_UNINIT,
+ expr_span,
+ "replacing with `mem::zeroed()`",
+ None,
+ "consider using a default value or the `take_mut` crate instead",
+ );
}
}
}
if_chain! {
if !in_external_macro(cx.tcx.sess, expr_span);
if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
- if let Some(repl_def_id) = cx.tables.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
+ if let Some(repl_def_id) = cx.tables().qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
if match_def_path(cx, repl_def_id, &paths::DEFAULT_TRAIT_METHOD);
then {
span_lint_and_then(
// Check that `expr` is a call to `mem::replace()`
if let ExprKind::Call(ref func, ref func_args) = expr.kind;
if let ExprKind::Path(ref func_qpath) = func.kind;
- if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id();
+ if let Some(def_id) = cx.tables().qpath_res(func_qpath, func.hir_id).opt_def_id();
if match_def_path(cx, def_id, &paths::MEM_REPLACE);
if let [dest, src] = &**func_args;
then {
check_replace_option_with_none(cx, src, dest, expr.span);
- check_replace_with_uninit(cx, src, expr.span);
+ check_replace_with_uninit(cx, src, dest, expr.span);
check_replace_with_default(cx, src, dest, expr.span);
}
}
/// Lint use of `_.and_then(|x| Some(y))` for `Option`s
fn lint(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
- if !match_type(cx, cx.tables.expr_ty(&args[0]), Self::TYPE_QPATH) {
+ if !match_type(cx, cx.tables().expr_ty(&args[0]), Self::TYPE_QPATH) {
return;
}
/// Checks for the `INEFFICIENT_TO_STRING` lint
pub fn lint<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'tcx>) {
if_chain! {
- if let Some(to_string_meth_did) = cx.tables.type_dependent_def_id(expr.hir_id);
+ if let Some(to_string_meth_did) = cx.tables().type_dependent_def_id(expr.hir_id);
if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
- if let Some(substs) = cx.tables.node_substs_opt(expr.hir_id);
+ if let Some(substs) = cx.tables().node_substs_opt(expr.hir_id);
let self_ty = substs.type_at(0);
let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty);
if deref_count >= 1;
let arith_lhs = &args[1][0];
let arith_rhs = &args[1][1];
- let ty = cx.tables.expr_ty(arith_lhs);
+ let ty = cx.tables().expr_ty(arith_lhs);
if !ty.is_integral() {
return;
}
}
}
- let ty = cx.tables.expr_ty(expr);
+ let ty = cx.tables().expr_ty(expr);
let ty_str = ty.to_string();
// `std::T::MAX` `std::T::MIN` constants
lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
- let self_ty = cx.tables.expr_ty_adjusted(&args[0]);
+ let self_ty = cx.tables().expr_ty_adjusted(&args[0]);
if args.len() == 1 && method_call.ident.name == sym!(clone) {
lint_clone_on_copy(cx, expr, &args[0], self_ty);
lint_clone_on_ref_ptr(cx, expr, &args[0]);
if let hir::ExprKind::Path(ref qpath) = fun.kind;
let path = &*last_path_segment(qpath).ident.as_str();
if ["default", "new"].contains(&path);
- let arg_ty = cx.tables.expr_ty(arg);
+ let arg_ty = cx.tables().expr_ty(arg);
if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
if implements_trait(cx, arg_ty, default_trait_id, &[]);
) {
if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind {
if path.ident.as_str() == "len" {
- let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
+ let ty = walk_ptrs_ty(cx.tables().expr_ty(&args[0]));
match ty.kind {
ty::Slice(_) | ty::Array(_, _) => return,
if { finder.visit_expr(&arg); finder.found };
if !contains_return(&arg);
- let self_ty = cx.tables.expr_ty(self_expr);
+ let self_ty = cx.tables().expr_ty(self_expr);
if let Some(&(_, fn_has_arguments, poss, suffix)) =
know_types.iter().find(|&&i| match_type(cx, self_ty, i.0));
if call_args.len() == 1
&& (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref))
&& {
- let arg_type = cx.tables.expr_ty(&call_args[0]);
+ let arg_type = cx.tables().expr_ty(&call_args[0]);
let base_type = walk_ptrs_ty(arg_type);
base_type.kind == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type))
}
// Only `&'static str` or `String` can be used directly in the `panic!`. Other types should be
// converted to string.
fn requires_to_string(cx: &LateContext<'_, '_>, arg: &hir::Expr<'_>) -> bool {
- let arg_ty = cx.tables.expr_ty(arg);
+ let arg_ty = cx.tables().expr_ty(arg);
if is_type_diagnostic_item(cx, arg_ty, sym!(string_type)) {
return false;
}
hir::ExprKind::Lit(_) => true,
hir::ExprKind::Call(fun, _) => {
if let hir::ExprKind::Path(ref p) = fun.kind {
- match cx.tables.qpath_res(p, fun.hir_id) {
+ match cx.tables().qpath_res(p, fun.hir_id) {
hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!(
cx.tcx.fn_sig(def_id).output().skip_binder().kind,
ty::Ref(ty::ReStatic, ..)
false
}
},
- hir::ExprKind::MethodCall(..) => cx.tables.type_dependent_def_id(arg.hir_id).map_or(false, |method_id| {
- matches!(
- cx.tcx.fn_sig(method_id).output().skip_binder().kind,
- ty::Ref(ty::ReStatic, ..)
- )
- }),
- hir::ExprKind::Path(ref p) => match cx.tables.qpath_res(p, arg.hir_id) {
+ hir::ExprKind::MethodCall(..) => cx
+ .tables()
+ .type_dependent_def_id(arg.hir_id)
+ .map_or(false, |method_id| {
+ matches!(
+ cx.tcx.fn_sig(method_id).output().skip_binder().kind,
+ ty::Ref(ty::ReStatic, ..)
+ )
+ }),
+ hir::ExprKind::Path(ref p) => match cx.tables().qpath_res(p, arg.hir_id) {
hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _) => true,
_ => false,
},
return;
}
- let receiver_type = cx.tables.expr_ty_adjusted(&args[0]);
+ let receiver_type = cx.tables().expr_ty_adjusted(&args[0]);
let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym!(option_type)) {
"||"
} else if is_type_diagnostic_item(cx, receiver_type, sym!(result_type)) {
/// Checks for the `CLONE_ON_COPY` lint.
fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) {
- let ty = cx.tables.expr_ty(expr);
+ let ty = cx.tables().expr_ty(expr);
if let ty::Ref(_, inner, _) = arg_ty.kind {
if let ty::Ref(_, innermost, _) = inner.kind {
span_lint_and_then(
}
// x.clone() might have dereferenced x, possibly through Deref impls
- if cx.tables.expr_ty(arg) == ty {
+ if cx.tables().expr_ty(arg) == ty {
snip = Some(("try removing the `clone` call", format!("{}", snippet)));
} else {
let deref_count = cx
- .tables
+ .tables()
.expr_adjustments(arg)
.iter()
.filter(|adj| {
}
fn lint_clone_on_ref_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
- let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(arg));
+ let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(arg));
if let ty::Adt(_, subst) = obj_ty.kind {
let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
let arg = &args[1];
if let Some(arglists) = method_chain_args(arg, &["chars"]) {
let target = &arglists[0][0];
- let self_ty = walk_ptrs_ty(cx.tables.expr_ty(target));
+ let self_ty = walk_ptrs_ty(cx.tables().expr_ty(target));
let ref_str = if self_ty.kind == ty::Str {
""
} else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) {
}
fn lint_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
- let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
+ let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&args[0]));
if is_type_diagnostic_item(cx, obj_ty, sym!(string_type)) {
lint_string_extend(cx, expr, args);
}
fn lint_cstring_as_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, source: &hir::Expr<'_>, unwrap: &hir::Expr<'_>) {
if_chain! {
- let source_type = cx.tables.expr_ty(source);
+ let source_type = cx.tables().expr_ty(source);
if let ty::Adt(def, substs) = source_type.kind;
if cx.tcx.is_diagnostic_item(sym!(result_type), def.did);
if match_type(cx, substs.type_at(0), &paths::CSTRING);
iter_args: &'tcx [hir::Expr<'_>],
) {
if_chain! {
- if is_type_diagnostic_item(cx, cx.tables.expr_ty(expr), sym!(vec_type));
- if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0]));
+ if is_type_diagnostic_item(cx, cx.tables().expr_ty(expr), sym!(vec_type));
+ if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.tables().expr_ty(&iter_args[0]));
if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite());
then {
fn lint_step_by<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) {
if match_trait_method(cx, expr, &paths::ITERATOR) {
- if let Some((Constant::Int(0), _)) = constant(cx, cx.tables, &args[1]) {
+ if let Some((Constant::Int(0), _)) = constant(cx, cx.tables(), &args[1]) {
span_lint(
cx,
ITERATOR_STEP_BY_ZERO,
parent_expr_opt = get_parent_expr(cx, parent_expr);
}
- if derefs_to_slice(cx, caller_expr, cx.tables.expr_ty(caller_expr)).is_some() {
+ if derefs_to_slice(cx, caller_expr, cx.tables().expr_ty(caller_expr)).is_some() {
// caller is a Slice
if_chain! {
if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
);
}
}
- } else if is_type_diagnostic_item(cx, cx.tables.expr_ty(caller_expr), sym!(vec_type))
- || matches!(&walk_ptrs_ty(cx.tables.expr_ty(caller_expr)).kind, ty::Array(_, _))
+ } else if is_type_diagnostic_item(cx, cx.tables().expr_ty(caller_expr), sym!(vec_type))
+ || matches!(&walk_ptrs_ty(cx.tables().expr_ty(caller_expr)).kind, ty::Array(_, _))
{
// caller is a Vec or an Array
let mut applicability = Applicability::MachineApplicable;
) {
let iter_args = nth_and_iter_args[1];
let mut_str = if is_mut { "_mut" } else { "" };
- let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() {
+ let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables().expr_ty(&iter_args[0])).is_some() {
"slice"
- } else if is_type_diagnostic_item(cx, cx.tables.expr_ty(&iter_args[0]), sym!(vec_type)) {
+ } else if is_type_diagnostic_item(cx, cx.tables().expr_ty(&iter_args[0]), sym!(vec_type)) {
"Vec"
- } else if is_type_diagnostic_item(cx, cx.tables.expr_ty(&iter_args[0]), sym!(vecdeque_type)) {
+ } else if is_type_diagnostic_item(cx, cx.tables().expr_ty(&iter_args[0]), sym!(vecdeque_type)) {
"VecDeque"
} else {
let nth_args = nth_and_iter_args[0];
fn lint_iter_nth_zero<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, nth_args: &'tcx [hir::Expr<'_>]) {
if_chain! {
if match_trait_method(cx, expr, &paths::ITERATOR);
- if let Some((Constant::Int(0), _)) = constant(cx, cx.tables, &nth_args[1]);
+ if let Some((Constant::Int(0), _)) = constant(cx, cx.tables(), &nth_args[1]);
then {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
// Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`,
// because they do not implement `IndexMut`
let mut applicability = Applicability::MachineApplicable;
- let expr_ty = cx.tables.expr_ty(&get_args[0]);
+ let expr_ty = cx.tables().expr_ty(&get_args[0]);
let get_args_str = if get_args.len() > 1 {
snippet_with_applicability(cx, get_args[1].span, "_", &mut applicability)
} else {
}
if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind {
- if path.ident.name == sym!(iter) && may_slice(cx, cx.tables.expr_ty(&args[0])) {
+ if path.ident.name == sym!(iter) && may_slice(cx, cx.tables().expr_ty(&args[0])) {
Some(&args[0])
} else {
None
/// lint use of `unwrap()` for `Option`s and `Result`s
fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) {
- let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&unwrap_args[0]));
+ let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&unwrap_args[0]));
let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
Some((UNWRAP_USED, "an Option", "None"))
/// lint use of `expect()` for `Option`s and `Result`s
fn lint_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) {
- let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&expect_args[0]));
+ let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&expect_args[0]));
let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
Some((EXPECT_USED, "an Option", "None"))
fn lint_ok_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) {
if_chain! {
// lint if the caller of `ok()` is a `Result`
- if is_type_diagnostic_item(cx, cx.tables.expr_ty(&ok_args[0]), sym!(result_type));
- let result_type = cx.tables.expr_ty(&ok_args[0]);
+ if is_type_diagnostic_item(cx, cx.tables().expr_ty(&ok_args[0]), sym!(result_type));
+ let result_type = cx.tables().expr_ty(&ok_args[0]);
if let Some(error_type) = get_error_type(cx, result_type);
if has_debug_impl(error_type, cx);
}
// lint if caller of `.map().flatten()` is an Option
- if is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_args[0]), sym!(option_type)) {
+ if is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_args[0]), sym!(option_type)) {
let msg = "called `map(..).flatten()` on an `Option`. \
This is more succinctly expressed by calling `.and_then(..)`";
let self_snippet = snippet(cx, map_args[0].span, "..");
unwrap_args: &'tcx [hir::Expr<'_>],
) {
// lint if the caller of `map()` is an `Option`
- let is_option = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_args[0]), sym!(option_type));
- let is_result = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_args[0]), sym!(result_type));
+ let is_option = is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_args[0]), sym!(option_type));
+ let is_result = is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_args[0]), sym!(result_type));
if is_option || is_result {
// Don't make a suggestion that may fail to compile due to mutably borrowing
expr: &'tcx hir::Expr<'_>,
map_or_args: &'tcx [hir::Expr<'_>],
) {
- let is_option = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_or_args[0]), sym!(option_type));
- let is_result = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_or_args[0]), sym!(result_type));
+ let is_option = is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_or_args[0]), sym!(option_type));
+ let is_result = is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_or_args[0]), sym!(result_type));
// There are two variants of this `map_or` lint:
// (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
if segment.ident.name == sym!(Some);
then {
let mut applicability = Applicability::MachineApplicable;
- let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0]));
+ let self_ty = walk_ptrs_ty(cx.tables().expr_ty_adjusted(&args[0][0]));
if self_ty.kind != ty::Str {
return false;
if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) {
// check if the type after `as_ref` or `as_mut` is the same as before
let recvr = &as_ref_args[0];
- let rcv_ty = cx.tables.expr_ty(recvr);
- let res_ty = cx.tables.expr_ty(expr);
+ let rcv_ty = cx.tables().expr_ty(recvr);
+ let res_ty = cx.tables().expr_ty(expr);
let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
if args.is_empty();
if let hir::ExprKind::Path(ref path) = callee.kind;
if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT);
- if !is_maybe_uninit_ty_valid(cx, cx.tables.expr_ty_adjusted(outer));
+ if !is_maybe_uninit_ty_valid(cx, cx.tables().expr_ty_adjusted(outer));
then {
span_lint(
cx,
) {
let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
- let option_ty = cx.tables.expr_ty(&as_ref_args[0]);
+ let option_ty = cx.tables().expr_ty(&as_ref_args[0]);
if !is_type_diagnostic_item(cx, option_ty, sym!(option_type)) {
return;
}
if_chain! {
if args.len() == 1;
if let hir::ExprKind::Path(qpath) = &args[0].kind;
- if let hir::def::Res::Local(local_id) = cx.tables.qpath_res(qpath, args[0].hir_id);
+ if let hir::def::Res::Local(local_id) = cx.tables().qpath_res(qpath, args[0].hir_id);
if closure_body.params[0].pat.hir_id == local_id;
- let adj = cx.tables.expr_adjustments(&args[0]).iter().map(|x| &x.kind).collect::<Box<[_]>>();
+ let adj = cx.tables().expr_adjustments(&args[0]).iter().map(|x| &x.kind).collect::<Box<[_]>>();
if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
then {
- let method_did = cx.tables.type_dependent_def_id(closure_expr.hir_id).unwrap();
+ let method_did = cx.tables().type_dependent_def_id(closure_expr.hir_id).unwrap();
deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
} else {
false
if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner1) = inner.kind;
if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner2) = inner1.kind;
if let hir::ExprKind::Path(ref qpath) = inner2.kind;
- if let hir::def::Res::Local(local_id) = cx.tables.qpath_res(qpath, inner2.hir_id);
+ if let hir::def::Res::Local(local_id) = cx.tables().qpath_res(qpath, inner2.hir_id);
then {
closure_body.params[0].pat.hir_id == local_id
} else {
fn check_pointer_offset(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
if_chain! {
if args.len() == 2;
- if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.tables.expr_ty(&args[0]).kind;
+ if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.tables().expr_ty(&args[0]).kind;
if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
if layout.is_zst();
then {
}
fn lint_filetype_is_file(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
- let ty = cx.tables.expr_ty(&args[0]);
+ let ty = cx.tables().expr_ty(&args[0]);
if !match_type(cx, ty, &paths::FILE_TYPE) {
return;
map_span: Span,
) {
// lint if the caller of `map()` is an `Option`
- if is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_args[0]), sym!(option_type)) {
- if !is_copy(cx, cx.tables.expr_ty(&unwrap_args[1])) {
+ if is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_args[0]), sym!(option_type)) {
+ if !is_copy(cx, cx.tables().expr_ty(&unwrap_args[1])) {
// Do not lint if the `map` argument uses identifiers in the `map`
// argument that are also used in the `unwrap_or` argument
if match_qpath(path, &paths::OPTION_SOME) {
if_chain! {
if let hir::ExprKind::Path(path) = &args[0].kind;
- if let Res::Local(ref local) = cx.tables.qpath_res(path, args[0].hir_id);
+ if let Res::Local(ref local) = cx.tables().qpath_res(path, args[0].hir_id);
then {
if arg_id == *local {
return (false, false)
}
match (
outer_max,
- Constant::partial_cmp(cx.tcx, cx.tables.expr_ty(ie), &outer_c, &inner_c),
+ Constant::partial_cmp(cx.tcx, cx.tables().expr_ty(ie), &outer_c, &inner_c),
) {
(_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (),
_ => {
fn min_max<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
if let ExprKind::Call(ref path, ref args) = expr.kind {
if let ExprKind::Path(ref qpath) = path.kind {
- cx.tables.qpath_res(qpath, path.hir_id).opt_def_id().and_then(|def_id| {
- if match_def_path(cx, def_id, &paths::CMP_MIN) {
- fetch_const(cx, args, MinMax::Min)
- } else if match_def_path(cx, def_id, &paths::CMP_MAX) {
- fetch_const(cx, args, MinMax::Max)
- } else {
- None
- }
- })
+ cx.tables()
+ .qpath_res(qpath, path.hir_id)
+ .opt_def_id()
+ .and_then(|def_id| {
+ if match_def_path(cx, def_id, &paths::CMP_MIN) {
+ fetch_const(cx, args, MinMax::Min)
+ } else if match_def_path(cx, def_id, &paths::CMP_MAX) {
+ fetch_const(cx, args, MinMax::Max)
+ } else {
+ None
+ }
+ })
} else {
None
}
if args.len() != 2 {
return None;
}
- if let Some(c) = constant_simple(cx, cx.tables, &args[0]) {
- if constant_simple(cx, cx.tables, &args[1]).is_none() {
+ if let Some(c) = constant_simple(cx, cx.tables(), &args[0]) {
+ if constant_simple(cx, cx.tables(), &args[1]).is_none() {
// otherwise ignore
Some((m, c, &args[1]))
} else {
None
}
- } else if let Some(c) = constant_simple(cx, cx.tables, &args[1]) {
+ } else if let Some(c) = constant_simple(cx, cx.tables(), &args[1]) {
Some((m, c, &args[0]))
} else {
None
binding != "_result" && // FIXME: #944
is_used(cx, expr) &&
// don't lint if the declaration is in a macro
- non_macro_local(cx, cx.tables.qpath_res(qpath, expr.hir_id))
+ non_macro_local(cx, cx.tables().qpath_res(qpath, expr.hir_id))
{
Some(binding)
} else {
fn check_nan(cx: &LateContext<'_, '_>, expr: &Expr<'_>, cmp_expr: &Expr<'_>) {
if_chain! {
if !in_constant(cx, cmp_expr.hir_id);
- if let Some((value, _)) = constant(cx, cx.tables, expr);
+ if let Some((value, _)) = constant(cx, cx.tables(), expr);
then {
let needs_lint = match value {
Constant::F32(num) => num.is_nan(),
}
fn is_named_constant<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) -> bool {
- if let Some((_, res)) = constant(cx, cx.tables, expr) {
+ if let Some((_, res)) = constant(cx, cx.tables(), expr) {
res
} else {
false
}
fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) -> bool {
- match constant(cx, cx.tables, expr) {
+ match constant(cx, cx.tables(), expr) {
Some((Constant::F32(f), _)) => f == 0.0 || f.is_infinite(),
Some((Constant::F64(f), _)) => f == 0.0 || f.is_infinite(),
Some((Constant::Vec(vec), _)) => vec.iter().all(|f| match f {
}
fn is_float(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
- let value = &walk_ptrs_ty(cx.tables.expr_ty(expr)).kind;
+ let value = &walk_ptrs_ty(cx.tables().expr_ty(expr)).kind;
if let ty::Array(arr_ty, _) = value {
return matches!(arr_ty.kind, ty::Float(_));
}
fn is_array(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
- matches!(&walk_ptrs_ty(cx.tables.expr_ty(expr)).kind, ty::Array(_, _))
+ matches!(&walk_ptrs_ty(cx.tables().expr_ty(expr)).kind, ty::Array(_, _))
}
fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
let (arg_ty, snip) = match expr.kind {
ExprKind::MethodCall(.., ref args, _) if args.len() == 1 => {
if match_trait_method(cx, expr, &paths::TO_STRING) || match_trait_method(cx, expr, &paths::TO_OWNED) {
- (cx.tables.expr_ty_adjusted(&args[0]), snippet(cx, args[0].span, ".."))
+ (cx.tables().expr_ty_adjusted(&args[0]), snippet(cx, args[0].span, ".."))
} else {
return;
}
ExprKind::Call(ref path, ref v) if v.len() == 1 => {
if let ExprKind::Path(ref path) = path.kind {
if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) {
- (cx.tables.expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
+ (cx.tables().expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
} else {
return;
}
_ => return,
};
- let other_ty = cx.tables.expr_ty_adjusted(other);
+ let other_ty = cx.tables().expr_ty_adjusted(other);
let partial_eq_trait_id = match cx.tcx.lang_items().eq_trait() {
Some(id) => id,
None => return,
}
fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option<OperandInfo> {
- match constant(cx, cx.tables, operand) {
- Some((Constant::Int(v), _)) => match cx.tables.expr_ty(expr).kind {
+ match constant(cx, cx.tables(), operand) {
+ Some((Constant::Int(v), _)) => match cx.tables().expr_ty(expr).kind {
ty::Int(ity) => {
let value = sext(cx.tcx, v, ity);
return Some(OperandInfo {
}
fn check_non_const_operands<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>, operand: &Expr<'_>) {
- let operand_type = cx.tables.expr_ty(operand);
+ let operand_type = cx.tables().expr_ty(operand);
if might_have_negative_value(operand_type) {
span_lint_and_then(
cx,
if let hir::PatKind::Wild = local.pat.kind {
return;
}
- check_ty(cx, local.span, cx.tables.pat_ty(&*local.pat));
+ check_ty(cx, local.span, cx.tables().pat_ty(&*local.pat));
}
}
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0) && is_mutable_type(cx, inner_ty, span)
},
Tuple(..) => ty.tuple_fields().any(|ty| is_mutable_type(cx, ty, span)),
- Adt(..) => cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env, span),
+ Adt(..) => cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx.at(span), cx.param_env),
_ => false,
}
}
expr.span,
"generally you want to avoid `&mut &mut _` if possible",
);
- } else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.tables.expr_ty(e).kind {
+ } else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.tables().expr_ty(e).kind {
span_lint(
self.cx,
MUT_MUT,
check_arguments(
cx,
arguments,
- cx.tables.expr_ty(fn_expr),
+ cx.tables().expr_ty(fn_expr),
&rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
);
}
},
ExprKind::MethodCall(ref path, _, ref arguments, _) => {
- let def_id = cx.tables.type_dependent_def_id(e.hir_id).unwrap();
- let substs = cx.tables.node_substs(e.hir_id);
+ let def_id = cx.tables().type_dependent_def_id(e.hir_id).unwrap();
+ let substs = cx.tables().node_substs(e.hir_id);
let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
check_arguments(cx, arguments, method_type, &path.ident.as_str())
},
return;
},
ExprKind::Path(_) => {
- if let Some(adj) = self.cx.tables.adjustments().get(expr.hir_id) {
+ if let Some(adj) = self.cx.tables().adjustments().get(expr.hir_id) {
if adj
.iter()
.any(|a| matches!(a.target.kind, ty::Ref(_, _, Mutability::Mut)))
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Mutex {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
- let ty = cx.tables.expr_ty(expr);
+ let ty = cx.tables().expr_ty(expr);
if let ty::Adt(_, subst) = ty.kind {
if is_type_diagnostic_item(cx, ty, sym!(mutex_type)) {
let mutex_param = subst.type_at(0);
use self::Expression::{Bool, Other};
if let ExprKind::Binary(op, ref left_side, ref right_side) = e.kind {
- let (l_ty, r_ty) = (cx.tables.expr_ty(left_side), cx.tables.expr_ty(right_side));
+ let (l_ty, r_ty) = (cx.tables().expr_ty(left_side), cx.tables().expr_ty(right_side));
if l_ty.is_bool() && r_ty.is_bool() {
let mut applicability = Applicability::MachineApplicable;
return;
}
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = e.kind {
- if let ty::Ref(..) = cx.tables.expr_ty(inner).kind {
- for adj3 in cx.tables.expr_adjustments(e).windows(3) {
+ if let ty::Ref(..) = cx.tables().expr_ty(inner).kind {
+ for adj3 in cx.tables().expr_adjustments(e).windows(3) {
if let [Adjustment {
kind: Adjust::Deref(_), ..
}, Adjustment {
}
if_chain! {
if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind;
- if let ty::Ref(_, tam, mutbl) = cx.tables.pat_ty(pat).kind;
+ if let ty::Ref(_, tam, mutbl) = cx.tables().pat_ty(pat).kind;
if mutbl == Mutability::Not;
if let ty::Ref(_, _, mutbl) = tam.kind;
// only lint immutable refs, because borrowed `&mut T` cannot be moved out
} = {
let mut ctx = MovedVariablesCtxt::default();
cx.tcx.infer_ctxt().enter(|infcx| {
- euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.tables).consume_body(body);
+ euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.tables()).consume_body(body);
});
ctx
};
!preds.is_empty() && {
let ty_empty_region = cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_root_empty, ty);
preds.iter().all(|t| {
- let ty_params = &t
- .skip_binder()
- .trait_ref
- .substs
- .iter()
- .skip(1)
- .collect::<Vec<_>>();
+ let ty_params = &t.skip_binder().trait_ref.substs.iter().skip(1).collect::<Vec<_>>();
implements_trait(cx, ty_empty_region, t.def_id(), ty_params)
})
},
}
impl MovedVariablesCtxt {
- fn move_common(&mut self, cmt: &euv::Place<'_>) {
- if let euv::PlaceBase::Local(vid) = cmt.base {
+ fn move_common(&mut self, cmt: &euv::PlaceWithHirId<'_>) {
+ if let euv::PlaceBase::Local(vid) = cmt.place.base {
self.moved_vars.insert(vid);
}
}
}
impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
- fn consume(&mut self, cmt: &euv::Place<'tcx>, mode: euv::ConsumeMode) {
+ fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, mode: euv::ConsumeMode) {
if let euv::ConsumeMode::Move = mode {
self.move_common(cmt);
}
}
- fn borrow(&mut self, _: &euv::Place<'tcx>, _: ty::BorrowKind) {}
+ fn borrow(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: ty::BorrowKind) {}
- fn mutate(&mut self, _: &euv::Place<'tcx>) {}
+ fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>) {}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessUpdate {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Struct(_, ref fields, Some(ref base)) = expr.kind {
- let ty = cx.tables.expr_ty(expr);
+ let ty = cx.tables().expr_ty(expr);
if let ty::Adt(def, _) = ty.kind {
if fields.len() == def.non_enum_variant().fields.len() {
span_lint(
then {
- let ty = cx.tables.expr_ty(left);
+ let ty = cx.tables().expr_ty(left);
let implements_ord = {
if let Some(id) = utils::get_trait_def_id(cx, &paths::ORD) {
fn check_mul(cx: &LateContext<'_, '_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
if_chain! {
if let ExprKind::Lit(ref l) = lit.kind;
- if let Constant::Int(1) = consts::lit_to_constant(&l.node, cx.tables.expr_ty_opt(lit));
- if cx.tables.expr_ty(exp).is_integral();
+ if let Constant::Int(1) = consts::lit_to_constant(&l.node, cx.tables().expr_ty_opt(lit));
+ if cx.tables().expr_ty(exp).is_integral();
then {
span_lint(cx, NEG_MULTIPLY, span, "Negation by multiplying with `-1`");
}
/// }
/// ```
///
- /// To fix the lint, and a `Default` implementation that delegates to `new`:
+ /// To fix the lint, add a `Default` implementation that delegates to `new`:
///
/// ```ignore
/// struct Foo(Bar);
}
match expr.kind {
ExprKind::Lit(..) | ExprKind::Closure(..) => true,
- ExprKind::Path(..) => !has_drop(cx, cx.tables.expr_ty(expr)),
+ ExprKind::Path(..) => !has_drop(cx, cx.tables().expr_ty(expr)),
ExprKind::Index(ref a, ref b) | ExprKind::Binary(_, ref a, ref b) => {
has_no_effect(cx, a) && has_no_effect(cx, b)
},
| ExprKind::AddrOf(_, _, ref inner)
| ExprKind::Box(ref inner) => has_no_effect(cx, inner),
ExprKind::Struct(_, ref fields, ref base) => {
- !has_drop(cx, cx.tables.expr_ty(expr))
+ !has_drop(cx, cx.tables().expr_ty(expr))
&& fields.iter().all(|field| has_no_effect(cx, &field.expr))
&& base.as_ref().map_or(true, |base| has_no_effect(cx, base))
},
let res = qpath_res(cx, qpath, callee.hir_id);
match res {
Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..) => {
- !has_drop(cx, cx.tables.expr_ty(expr)) && args.iter().all(|arg| has_no_effect(cx, arg))
+ !has_drop(cx, cx.tables().expr_ty(expr)) && args.iter().all(|arg| has_no_effect(cx, arg))
},
_ => false,
}
| ExprKind::AddrOf(_, _, ref inner)
| ExprKind::Box(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
ExprKind::Struct(_, ref fields, ref base) => {
- if has_drop(cx, cx.tables.expr_ty(expr)) {
+ if has_drop(cx, cx.tables().expr_ty(expr)) {
None
} else {
Some(fields.iter().map(|f| &f.expr).chain(base).map(Deref::deref).collect())
let res = qpath_res(cx, qpath, callee.hir_id);
match res {
Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..)
- if !has_drop(cx, cx.tables.expr_ty(expr)) =>
+ if !has_drop(cx, cx.tables().expr_ty(expr)) =>
{
Some(args.iter().collect())
},
}
fn verify_ty_bound<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>, source: Source) {
- if ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP) || is_copy(cx, ty) {
+ if ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) || is_copy(cx, ty) {
// An `UnsafeCell` is `!Copy`, and an `UnsafeCell` is also the only type which
// is `!Freeze`, thus if our type is `Copy` we can be sure it must be `Freeze`
// as well.
}
let ty = if needs_check_adjustment {
- let adjustments = cx.tables.expr_adjustments(dereferenced_expr);
+ let adjustments = cx.tables().expr_adjustments(dereferenced_expr);
if let Some(i) = adjustments.iter().position(|adj| match adj.kind {
Adjust::Borrow(_) | Adjust::Deref(_) => true,
_ => false,
}) {
if i == 0 {
- cx.tables.expr_ty(dereferenced_expr)
+ cx.tables().expr_ty(dereferenced_expr)
} else {
adjustments[i - 1].target
}
return;
}
} else {
- cx.tables.expr_ty(dereferenced_expr)
+ cx.tables().expr_ty(dereferenced_expr)
};
verify_ty_bound(cx, ty, Source::Expr { expr: expr.span });
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OpenOptions {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
if let ExprKind::MethodCall(ref path, _, ref arguments, _) = e.kind {
- let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&arguments[0]));
+ let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&arguments[0]));
if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) {
let mut options = Vec::new();
get_open_options(cx, &arguments[0], &mut options);
fn get_open_options(cx: &LateContext<'_, '_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
if let ExprKind::MethodCall(ref path, _, ref arguments, _) = argument.kind {
- let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&arguments[0]));
+ let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&arguments[0]));
// Only proceed if this is a call on some object of type std::fs::OpenOptions
if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 {
if let ExprKind::Path(QPath::Resolved(_, ref path2)) = ident2.kind;
if let ExprKind::Path(QPath::Resolved(_, ref path3)) = second.kind;
if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]);
- if cx.tables.expr_ty(ident1).is_integral();
- if cx.tables.expr_ty(ident2).is_integral();
+ if cx.tables().expr_ty(ident1).is_integral();
+ if cx.tables().expr_ty(ident2).is_integral();
then {
if let BinOpKind::Lt = op.node {
if let BinOpKind::Add = op2.node {
if let ExprKind::Path(QPath::Resolved(_, ref path2)) = ident2.kind;
if let ExprKind::Path(QPath::Resolved(_, ref path3)) = first.kind;
if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]);
- if cx.tables.expr_ty(ident1).is_integral();
- if cx.tables.expr_ty(ident2).is_integral();
+ if cx.tables().expr_ty(ident1).is_integral();
+ if cx.tables().expr_ty(ident2).is_integral();
then {
if let BinOpKind::Gt = op.node {
if let BinOpKind::Add = op2.node {
if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
if path.ident.name == sym!(push);
if args.len() == 2;
- if match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(&args[0])), &paths::PATH_BUF);
+ if match_type(cx, walk_ptrs_ty(cx.tables().expr_ty(&args[0])), &paths::PATH_BUF);
if let Some(get_index_arg) = args.get(1);
if let ExprKind::Lit(ref lit) = get_index_arg.kind;
if let LitKind::Str(ref path_lit, _) = lit.node;
// Is the type of the expression a usize?
fn is_expr_ty_usize<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>) -> bool {
- cx.tables.expr_ty(expr) == cx.tcx.types.usize
+ cx.tables().expr_ty(expr) == cx.tcx.types.usize
}
// Is the type of the expression a raw pointer?
fn is_expr_ty_raw_ptr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>) -> bool {
- cx.tables.expr_ty(expr).is_unsafe_ptr()
+ cx.tables().expr_ty(expr).is_unsafe_ptr()
}
fn build_suggestion<'a, 'tcx>(
}
fn moves_by_default(cx: &LateContext<'_, '_>, expression: &Expr<'_>) -> bool {
- let expr_ty = cx.tables.expr_ty(expression);
+ let expr_ty = cx.tables().expr_ty(expression);
- !expr_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, expression.span)
+ !expr_ty.is_copy_modulo_regions(cx.tcx.at(expression.span), cx.param_env)
}
fn is_option(cx: &LateContext<'_, '_>, expression: &Expr<'_>) -> bool {
- let expr_ty = cx.tables.expr_ty(expression);
+ let expr_ty = cx.tables().expr_ty(expression);
is_type_diagnostic_item(cx, expr_ty, sym!(option_type))
}
ExprKind::Ret(Some(ref expr)) => Self::expression_returns_none(cx, expr),
ExprKind::Path(ref qp) => {
if let Res::Def(DefKind::Ctor(def::CtorOf::Variant, def::CtorKind::Const), def_id) =
- cx.tables.qpath_res(qp, expression.hir_id)
+ cx.tables().qpath_res(qp, expression.hir_id)
{
return match_def_path(cx, def_id, &paths::OPTION_NONE);
}
if_chain! {
if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(cx, expr);
- let ty = cx.tables.expr_ty(start);
+ let ty = cx.tables().expr_ty(start);
if let ty::Int(_) | ty::Uint(_) = ty.kind;
- if let Some((start_idx, _)) = constant(cx, cx.tables, start);
- if let Some((end_idx, _)) = constant(cx, cx.tables, end);
+ if let Some((start_idx, _)) = constant(cx, cx.tables(), start);
+ if let Some((end_idx, _)) = constant(cx, cx.tables(), end);
if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx);
if is_empty_range(limits, ordering);
then {
-use crate::utils::{match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
+use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
-use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_mir::const_eval::is_const_fn;
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Symbol;
declare_clippy_lint! {
/// **What it does:** Lint for redundant pattern matching over `Result` or
arms: &[Arm<'_>],
keyword: &'static str,
) {
+ fn find_suggestion(cx: &LateContext<'_, '_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> {
+ if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") {
+ return Some("is_ok()");
+ }
+ if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") {
+ return Some("is_err()");
+ }
+ if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") {
+ return Some("is_some()");
+ }
+ if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") {
+ return Some("is_none()");
+ }
+ None
+ }
+
+ let hir_id = expr.hir_id;
let good_method = match arms[0].pat.kind {
PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
if let PatKind::Wild = patterns[0].kind {
- if match_qpath(path, &paths::RESULT_OK) {
- "is_ok()"
- } else if match_qpath(path, &paths::RESULT_ERR) {
- "is_err()"
- } else if match_qpath(path, &paths::OPTION_SOME) {
- "is_some()"
- } else {
- return;
- }
+ find_suggestion(cx, hir_id, path)
} else {
- return;
+ None
}
},
-
- PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => "is_none()",
-
- _ => return,
+ PatKind::Path(ref path) => find_suggestion(cx, hir_id, path),
+ _ => None,
+ };
+ let good_method = match good_method {
+ Some(method) => method,
+ None => return,
};
// check that `while_let_on_iterator` lint does not trigger
if arms.len() == 2 {
let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
+ let hir_id = expr.hir_id;
let found_good_method = match node_pair {
(
PatKind::TupleStruct(ref path_left, ref patterns_left, _),
&paths::RESULT_ERR,
"is_ok()",
"is_err()",
+ || can_suggest(cx, hir_id, sym!(result_type), "is_ok"),
+ || can_suggest(cx, hir_id, sym!(result_type), "is_err"),
)
} else {
None
&paths::OPTION_NONE,
"is_some()",
"is_none()",
+ || can_suggest(cx, hir_id, sym!(option_type), "is_some"),
+ || can_suggest(cx, hir_id, sym!(option_type), "is_none"),
)
} else {
None
}
}
+#[allow(clippy::too_many_arguments)]
fn find_good_method_for_match<'a>(
arms: &[Arm<'_>],
path_left: &QPath<'_>,
expected_right: &[&str],
should_be_left: &'a str,
should_be_right: &'a str,
+ can_suggest_left: impl Fn() -> bool,
+ can_suggest_right: impl Fn() -> bool,
) -> Option<&'a str> {
let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
(&(*arms[0].body).kind, &(*arms[1].body).kind)
match body_node_pair {
(ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
- (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
- (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
+ (LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left),
+ (LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right),
_ => None,
},
_ => None,
}
}
+
+fn can_suggest(cx: &LateContext<'_, '_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool {
+ if !in_constant(cx, hir_id) {
+ return true;
+ }
+
+ // Avoid suggesting calls to non-`const fn`s in const contexts, see #5697.
+ cx.tcx
+ .get_diagnostic_item(diag_item)
+ .and_then(|def_id| {
+ cx.tcx.inherent_impls(def_id).iter().find_map(|imp| {
+ cx.tcx
+ .associated_items(*imp)
+ .in_definition_order()
+ .find_map(|item| match item.kind {
+ ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id),
+ _ => None,
+ })
+ })
+ })
+ .map_or(false, |def_id| is_const_fn(cx.tcx, def_id))
+}
if_chain! {
if self.last.is_none();
if let Some(ref expr) = block.expr;
- if match_type(cx, cx.tables.expr_ty(expr), &paths::REGEX);
+ if match_type(cx, cx.tables().expr_ty(expr), &paths::REGEX);
if let Some(span) = is_expn_of(expr.span, "regex");
then {
if !self.spans.contains(&span) {
if let ExprKind::Call(ref fun, ref args) = expr.kind;
if let ExprKind::Path(ref qpath) = fun.kind;
if args.len() == 1;
- if let Some(def_id) = cx.tables.qpath_res(qpath, fun.hir_id).opt_def_id();
+ if let Some(def_id) = cx.tables().qpath_res(qpath, fun.hir_id).opt_def_id();
then {
if match_def_path(cx, def_id, &paths::REGEX_NEW) ||
match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) {
}
fn const_str<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) -> Option<String> {
- constant(cx, cx.tables, e).and_then(|(c, _)| match c {
+ constant(cx, cx.tables(), e).and_then(|(c, _)| match c {
Constant::Str(s) => Some(s),
_ => None,
})
}
fn is_binding(cx: &LateContext<'_, '_>, pat_id: HirId) -> bool {
- let var_ty = cx.tables.node_type_opt(pat_id);
+ let var_ty = cx.tables().node_type_opt(pat_id);
if let Some(var_ty) = var_ty {
match var_ty.kind {
ty::Adt(..) => false,
}
fn is_string(cx: &LateContext<'_, '_>, e: &Expr<'_>) -> bool {
- is_type_diagnostic_item(cx, walk_ptrs_ty(cx.tables.expr_ty(e)), sym!(string_type))
+ is_type_diagnostic_item(cx, walk_ptrs_ty(cx.tables().expr_ty(e)), sym!(string_type))
}
fn is_add(cx: &LateContext<'_, '_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
in_binary_expr: bool,
}
-impl<'a, 'tcx> Visitor<'tcx> for BinaryExprVisitor {
+impl<'tcx> Visitor<'tcx> for BinaryExprVisitor {
type Map = Map<'tcx>;
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind {
if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind {
if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) {
- let ty = walk_ptrs_ty(cx.tables.expr_ty(lhs1));
+ let ty = walk_ptrs_ty(cx.tables().expr_ty(lhs1));
if matches!(ty.kind, ty::Slice(_))
|| matches!(ty.kind, ty::Array(_, _))
match &expr.kind {
ExprKind::Struct(..) | ExprKind::Tup(..) => true,
ExprKind::Path(qpath) => {
- if let Res::Def(DefKind::Const, ..) = cx.tables.qpath_res(qpath, expr.hir_id) {
+ if let Res::Def(DefKind::Const, ..) = cx.tables().qpath_res(qpath, expr.hir_id) {
true
} else {
false
if_chain! {
if let [char_arg, radix_arg] = &**to_digit_args;
if to_digits_path.ident.name.as_str() == "to_digit";
- let char_arg_ty = cx.tables.expr_ty_adjusted(char_arg);
+ let char_arg_ty = cx.tables().expr_ty_adjusted(char_arg);
if char_arg_ty.kind == ty::Char;
then {
Some((true, char_arg, radix_arg))
if_chain! {
if let [char_arg, radix_arg] = &**to_digit_args;
if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind;
- if let to_digits_call_res = cx.tables.qpath_res(to_digits_path, to_digits_call.hir_id);
+ if let to_digits_call_res = cx.tables().qpath_res(to_digits_path, to_digits_call.hir_id);
if let Some(to_digits_def_id) = to_digits_call_res.opt_def_id();
if match_def_path(cx, to_digits_def_id, &["core", "char", "methods", "<impl char>", "to_digit"]);
then {
return;
}
let hash = |ty| -> u64 {
- let mut hasher = SpanlessHash::new(cx, cx.tables);
+ let mut hasher = SpanlessHash::new(cx, cx.tables());
hasher.hash_ty(ty);
hasher.finish()
};
if_chain! {
if let ExprKind::Call(ref path_expr, ref args) = e.kind;
if let ExprKind::Path(ref qpath) = path_expr.kind;
- if let Some(def_id) = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id();
+ if let Some(def_id) = cx.tables().qpath_res(qpath, path_expr.hir_id).opt_def_id();
if match_def_path(cx, def_id, &paths::TRANSMUTE);
then {
- let from_ty = cx.tables.expr_ty(&args[0]);
- let to_ty = cx.tables.expr_ty(e);
+ let from_ty = cx.tables().expr_ty(&args[0]);
+ let to_ty = cx.tables().expr_ty(e);
match (&from_ty.kind, &to_ty.kind) {
_ if from_ty == to_ty => span_lint(
then {
// Catching transmute over constants that resolve to `null`.
- let mut const_eval_context = constant_context(cx, cx.tables);
+ let mut const_eval_context = constant_context(cx, cx.tables());
if_chain! {
if let ExprKind::Path(ref _qpath) = args[0].kind;
let x = const_eval_context.expr(&args[0]);
limit: u64,
}
-impl<'a, 'tcx> TriviallyCopyPassByRef {
+impl<'tcx> TriviallyCopyPassByRef {
pub fn new(limit: Option<u64>, target: &SessionConfig) -> Self {
let limit = limit.unwrap_or_else(|| {
let bit_width = u64::from(target.ptr_width);
if let Some(return_type) = find_err_return_type(cx, &expr.kind);
then {
- let err_type = cx.tables.expr_ty(err_arg);
+ let err_type = cx.tables().expr_ty(err_arg);
let origin_snippet = if err_arg.span.from_expansion() {
snippet_with_macro_callsite(cx, err_arg.span, "_")
} else {
if match_qpath(from_error_fn, &paths::TRY_FROM_ERROR);
if let Some(from_error_arg) = from_error_args.get(0);
then {
- Some(cx.tables.expr_ty(from_error_arg))
+ Some(cx.tables().expr_ty(from_error_arg))
} else {
None
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnitValue {
fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt<'_>) {
if let StmtKind::Local(ref local) = stmt.kind {
- if is_unit(cx.tables.pat_ty(&local.pat)) {
+ if is_unit(cx.tables().pat_ty(&local.pat)) {
if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() {
return;
}
if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind {
if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind {
let op = cmp.node;
- if op.is_comparison() && is_unit(cx.tables.expr_ty(left)) {
+ if op.is_comparison() && is_unit(cx.tables().expr_ty(left)) {
let result = match &*symbol.as_str() {
"assert_eq" | "debug_assert_eq" => "succeed",
"assert_ne" | "debug_assert_ne" => "fail",
}
if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind {
let op = cmp.node;
- if op.is_comparison() && is_unit(cx.tables.expr_ty(left)) {
+ if op.is_comparison() && is_unit(cx.tables().expr_ty(left)) {
let result = match op {
BinOpKind::Eq | BinOpKind::Le | BinOpKind::Ge => "true",
_ => "false",
let args_to_recover = args
.iter()
.filter(|arg| {
- if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) {
+ if is_unit(cx.tables().expr_ty(arg)) && !is_unit_literal(arg) {
if let ExprKind::Match(.., MatchSource::TryDesugar) = &arg.kind {
false
} else {
}
// don't lint for positive constants
- let const_val = constant(cx, &cx.tables, op);
+ let const_val = constant(cx, &cx.tables(), op);
if_chain! {
if let Some((const_val, _)) = const_val;
if let Constant::Int(n) = const_val;
return;
}
if let ExprKind::Cast(ref ex, _) = expr.kind {
- let (cast_from, cast_to) = (cx.tables.expr_ty(ex), cx.tables.expr_ty(expr));
+ let (cast_from, cast_to) = (cx.tables().expr_ty(ex), cx.tables().expr_ty(expr));
lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to);
if let ExprKind::Lit(ref lit) = ex.kind {
if_chain! {
if let ExprKind::Cast(e, _) = &expr.kind;
if let ExprKind::Lit(l) = &e.kind;
if let LitKind::Char(c) = l.node;
- if ty::Uint(UintTy::U8) == cx.tables.expr_ty(expr).kind;
+ if ty::Uint(UintTy::U8) == cx.tables().expr_ty(expr).kind;
then {
let mut applicability = Applicability::MachineApplicable;
let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability);
fn is_cast_between_fixed_and_target<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
- let precast_ty = cx.tables.expr_ty(cast_exp);
- let cast_ty = cx.tables.expr_ty(expr);
+ let precast_ty = cx.tables().expr_ty(cast_exp);
+ let cast_ty = cx.tables().expr_ty(expr);
return is_isize_or_usize(precast_ty) != is_isize_or_usize(cast_ty);
}
// absurd comparison only makes sense on primitive types
// primitive types don't implement comparison operators with each other
- if cx.tables.expr_ty(lhs) != cx.tables.expr_ty(rhs) {
+ if cx.tables().expr_ty(lhs) != cx.tables().expr_ty(rhs) {
return None;
}
fn detect_extreme_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> {
use crate::types::ExtremeType::{Maximum, Minimum};
- let ty = cx.tables.expr_ty(expr);
+ let ty = cx.tables().expr_ty(expr);
- let cv = constant(cx, cx.tables, expr)?.0;
+ let cv = constant(cx, cx.tables(), expr)?.0;
let which = match (&ty.kind, cv) {
(&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => Minimum,
- (&ty::Int(ity), Constant::Int(i))
- if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) =>
- {
+ (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) => {
Minimum
},
(&ty::Bool, Constant::Bool(true)) => Maximum,
- (&ty::Int(ity), Constant::Int(i))
- if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) =>
- {
+ (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) => {
Maximum
},
(&ty::Uint(uty), Constant::Int(i)) if clip(cx.tcx, u128::MAX, uty) == i => Maximum,
fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
- let pre_cast_ty = cx.tables.expr_ty(cast_exp);
- let cast_ty = cx.tables.expr_ty(expr);
+ let pre_cast_ty = cx.tables().expr_ty(cast_exp);
+ let cast_ty = cx.tables().expr_ty(expr);
// if it's a cast from i32 to u32 wrapping will invalidate all these checks
if cx.layout_of(pre_cast_ty).ok().map(|l| l.size) == cx.layout_of(cast_ty).ok().map(|l| l.size) {
return None;
}
match pre_cast_ty.kind {
ty::Int(int_ty) => Some(match int_ty {
- IntTy::I8 => (
- FullInt::S(i128::from(i8::MIN)),
- FullInt::S(i128::from(i8::MAX)),
- ),
- IntTy::I16 => (
- FullInt::S(i128::from(i16::MIN)),
- FullInt::S(i128::from(i16::MAX)),
- ),
- IntTy::I32 => (
- FullInt::S(i128::from(i32::MIN)),
- FullInt::S(i128::from(i32::MAX)),
- ),
- IntTy::I64 => (
- FullInt::S(i128::from(i64::MIN)),
- FullInt::S(i128::from(i64::MAX)),
- ),
+ IntTy::I8 => (FullInt::S(i128::from(i8::MIN)), FullInt::S(i128::from(i8::MAX))),
+ IntTy::I16 => (FullInt::S(i128::from(i16::MIN)), FullInt::S(i128::from(i16::MAX))),
+ IntTy::I32 => (FullInt::S(i128::from(i32::MIN)), FullInt::S(i128::from(i32::MAX))),
+ IntTy::I64 => (FullInt::S(i128::from(i64::MIN)), FullInt::S(i128::from(i64::MAX))),
IntTy::I128 => (FullInt::S(i128::MIN), FullInt::S(i128::MAX)),
- IntTy::Isize => (
- FullInt::S(isize::MIN as i128),
- FullInt::S(isize::MAX as i128),
- ),
+ IntTy::Isize => (FullInt::S(isize::MIN as i128), FullInt::S(isize::MAX as i128)),
}),
ty::Uint(uint_ty) => Some(match uint_ty {
- UintTy::U8 => (
- FullInt::U(u128::from(u8::MIN)),
- FullInt::U(u128::from(u8::MAX)),
- ),
- UintTy::U16 => (
- FullInt::U(u128::from(u16::MIN)),
- FullInt::U(u128::from(u16::MAX)),
- ),
- UintTy::U32 => (
- FullInt::U(u128::from(u32::MIN)),
- FullInt::U(u128::from(u32::MAX)),
- ),
- UintTy::U64 => (
- FullInt::U(u128::from(u64::MIN)),
- FullInt::U(u128::from(u64::MAX)),
- ),
+ UintTy::U8 => (FullInt::U(u128::from(u8::MIN)), FullInt::U(u128::from(u8::MAX))),
+ UintTy::U16 => (FullInt::U(u128::from(u16::MIN)), FullInt::U(u128::from(u16::MAX))),
+ UintTy::U32 => (FullInt::U(u128::from(u32::MIN)), FullInt::U(u128::from(u32::MAX))),
+ UintTy::U64 => (FullInt::U(u128::from(u64::MIN)), FullInt::U(u128::from(u64::MAX))),
UintTy::U128 => (FullInt::U(u128::MIN), FullInt::U(u128::MAX)),
- UintTy::Usize => (
- FullInt::U(usize::MIN as u128),
- FullInt::U(usize::MAX as u128),
- ),
+ UintTy::Usize => (FullInt::U(usize::MIN as u128), FullInt::U(usize::MAX as u128)),
}),
_ => None,
}
}
fn node_as_const_fullint<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
- let val = constant(cx, cx.tables, expr)?.0;
+ let val = constant(cx, cx.tables(), expr)?.0;
if let Constant::Int(const_int) = val {
- match cx.tables.expr_ty(expr).kind {
+ match cx.tables().expr_ty(expr).kind {
ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
ty::Uint(_) => Some(FullInt::U(const_int)),
_ => None,
fn new(cx: &'a LateContext<'a, 'tcx>, target: &'b ImplicitHasherType<'tcx>) -> Self {
Self {
cx,
- body: cx.tables,
+ body: cx.tables(),
target,
suggestions: BTreeMap::new(),
}
if let TyKind::Ptr(MutTy { mutbl: Mutability::Mut, .. }) = t.kind;
if let ExprKind::Cast(e, t) = &e.kind;
if let TyKind::Ptr(MutTy { mutbl: Mutability::Not, .. }) = t.kind;
- if let ty::Ref(..) = cx.tables.node_type(e.hir_id).kind;
+ if let ty::Ref(..) = cx.tables().node_type(e.hir_id).kind;
then {
span_lint(
cx,
}
fn is_trait_ptr(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
- match cx.tables.expr_ty_adjusted(expr).kind {
+ match cx.tables().expr_ty_adjusted(expr).kind {
ty::RawPtr(ty::TypeAndMut { ty, .. }) => ty.is_trait(),
_ => false,
}
}
fn is_fn_def(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
- if let ty::FnDef(..) = cx.tables.expr_ty(expr).kind {
+ if let ty::FnDef(..) = cx.tables().expr_ty(expr).kind {
true
} else {
false
if_chain! {
if let ExprKind::Call(ref func, [ref _left, ref _right]) = expr.kind;
if let ExprKind::Path(ref func_qpath) = func.kind;
- if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id();
+ if let Some(def_id) = cx.tables().qpath_res(func_qpath, func.hir_id).opt_def_id();
if match_def_path(cx, def_id, &paths::PTR_EQ) ||
match_def_path(cx, def_id, &paths::RC_PTR_EQ) ||
match_def_path(cx, def_id, &paths::ARC_PTR_EQ);
- let ty_param = cx.tables.node_substs(func.hir_id).type_at(0);
+ let ty_param = cx.tables().node_substs(func.hir_id).type_at(0);
if ty_param.is_trait();
then {
span_lint_and_help(
if_chain! {
if let ExprKind::Binary(binop, ref left, ref right) = expr.kind;
if is_comparison(binop.node);
- if cx.tables.expr_ty_adjusted(left).is_fn_ptr() &&
- cx.tables.expr_ty_adjusted(right).is_fn_ptr();
+ if cx.tables().expr_ty_adjusted(left).is_fn_ptr() &&
+ cx.tables().expr_ty_adjusted(right).is_fn_ptr();
if is_fn_def(cx, left) || is_fn_def(cx, right);
then {
span_lint(
// The two exprs are method calls.
// Check to see that the function is the same and the arguments are mirrored
// This is enough because the receiver of the method is listed in the arguments
- (ExprKind::MethodCall(left_segment, _, left_args, _), ExprKind::MethodCall(right_segment, _, right_args, _)) => {
+ (
+ ExprKind::MethodCall(left_segment, _, left_args, _),
+ ExprKind::MethodCall(right_segment, _, right_args, _),
+ ) => {
left_segment.ident == right_segment.ident
&& left_args
.iter()
if let name = name_ident.ident.name.to_ident_string();
if name == "sort_by" || name == "sort_unstable_by";
if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args;
- if utils::match_type(cx, &cx.tables.expr_ty(vec), &paths::VEC);
+ if utils::match_type(cx, &cx.tables().expr_ty(vec), &paths::VEC);
if let closure_body = cx.tcx.hir().body(*closure_body_id);
if let &[
Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
/// }
/// ```
pub UNNESTED_OR_PATTERNS,
- complexity,
+ pedantic,
"unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`"
}
if_chain! {
if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind;
if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].kind;
- let ty = cx.tables.expr_ty(&args[0]);
+ let ty = cx.tables().expr_ty(&args[0]);
let name = method_name.ident.as_str();
if is_relevant_option_call(cx, ty, &name) || is_relevant_result_call(cx, ty, &name);
then {
ExprKind::MethodCall(ref name, .., ref args, _) => {
if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" {
- let a = cx.tables.expr_ty(e);
- let b = cx.tables.expr_ty(&args[0]);
+ let a = cx.tables().expr_ty(e);
+ let b = cx.tables().expr_ty(&args[0]);
if TyS::same_type(a, b) {
let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
span_lint_and_sugg(
}
}
if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" {
- let a = cx.tables.expr_ty(e);
- let b = cx.tables.expr_ty(&args[0]);
+ let a = cx.tables().expr_ty(e);
+ let b = cx.tables().expr_ty(&args[0]);
if TyS::same_type(a, b) {
let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
span_lint_and_sugg(
}
if match_trait_method(cx, e, &paths::TRY_INTO_TRAIT) && &*name.ident.as_str() == "try_into" {
if_chain! {
- let a = cx.tables.expr_ty(e);
- let b = cx.tables.expr_ty(&args[0]);
+ let a = cx.tables().expr_ty(e);
+ let b = cx.tables().expr_ty(&args[0]);
if is_type_diagnostic_item(cx, a, sym!(result_type));
if let ty::Adt(_, substs) = a.kind;
if let Some(a_type) = substs.types().next();
if_chain! {
if args.len() == 1;
if let ExprKind::Path(ref qpath) = path.kind;
- if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id();
- let a = cx.tables.expr_ty(e);
- let b = cx.tables.expr_ty(&args[0]);
+ if let Some(def_id) = cx.tables().qpath_res(qpath, path.hir_id).opt_def_id();
+ let a = cx.tables().expr_ty(e);
+ let b = cx.tables().expr_ty(&args[0]);
then {
if_chain! {
&& match (&l.kind, &r.kind) {
(Lifetime, Lifetime) => true,
(Type { default: l }, Type { default: r }) => both(l, r, |l, r| eq_ty(l, r)),
- (Const { ty: l }, Const { ty: r }) => eq_ty(l, r),
+ (Const { ty: l, kw_span: _ }, Const { ty: r, kw_span: _ }) => eq_ty(l, r),
_ => false,
}
&& over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
}
},
ExprKind::MethodCall(ref _method_name, ref _generics, ref _args, ref _fn_span) => {
- println!("MethodCall(ref method_name, ref generics, ref args, ref fn_span) = {};", current);
+ println!(
+ "MethodCall(ref method_name, ref generics, ref args, ref fn_span) = {};",
+ current
+ );
println!(" // unimplemented: `ExprKind::MethodCall` is not further destructured at the moment");
},
ExprKind::Tup(ref elements) => {
pub use self::helpers::Conf;
define_Conf! {
- /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
- (blacklisted_names, "blacklisted_names": Vec<String>, ["foo", "bar", "baz", "quux"].iter().map(ToString::to_string).collect()),
+ /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
+ (blacklisted_names, "blacklisted_names": Vec<String>, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
/// Lint: COGNITIVE_COMPLEXITY. The maximum cognitive complexity a function can have
(cognitive_complexity_threshold, "cognitive_complexity_threshold": u64, 25),
/// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. Use the Cognitive Complexity lint instead.
Some(expr)
}
- let def_path = match cx.tables.expr_ty(expr).kind {
+ let def_path = match cx.tables().expr_ty(expr).kind {
ty::Adt(def, _) => cx.tcx.def_path(def.did),
_ => return None,
};
if let hir::ExprKind::Call(ref fun, ref args) = expr.kind;
if let hir::ExprKind::Path(ref qpath) = fun.kind;
if is_expn_of(fun.span, "vec").is_some();
- if let Some(fun_def_id) = cx.tables.qpath_res(qpath, fun.hir_id).opt_def_id();
+ if let Some(fun_def_id) = cx.tables().qpath_res(qpath, fun.hir_id).opt_def_id();
then {
return if match_def_path(cx, fun_def_id, &paths::VEC_FROM_ELEM) && args.len() == 2 {
// `vec![elem; size]` case
pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
Self {
cx,
- tables: cx.tables,
+ tables: cx.tables(),
ignore_fn: false,
}
}
pub fn ignore_fn(self) -> Self {
Self {
cx: self.cx,
- tables: self.cx.tables,
+ tables: self.cx.tables(),
ignore_fn: true,
}
}
rhs: &'a Expr<'a>,
) -> Option<(BinOpKind, &'a Expr<'a>, &'a Expr<'a>)> {
match binop {
- BinOpKind::Add
- | BinOpKind::Mul
- | BinOpKind::Eq
- | BinOpKind::Ne
- | BinOpKind::BitAnd
- | BinOpKind::BitXor
- | BinOpKind::BitOr => Some((binop, rhs, lhs)),
+ BinOpKind::Add | BinOpKind::Eq | BinOpKind::Ne | BinOpKind::BitAnd | BinOpKind::BitXor | BinOpKind::BitOr => {
+ Some((binop, rhs, lhs))
+ },
BinOpKind::Lt => Some((BinOpKind::Gt, rhs, lhs)),
BinOpKind::Le => Some((BinOpKind::Ge, rhs, lhs)),
BinOpKind::Ge => Some((BinOpKind::Le, rhs, lhs)),
BinOpKind::Gt => Some((BinOpKind::Lt, rhs, lhs)),
- BinOpKind::Shl
+ BinOpKind::Mul // Not always commutative, e.g. with matrices. See issue #5698
+ | BinOpKind::Shl
| BinOpKind::Shr
| BinOpKind::Rem
| BinOpKind::Sub
}
match stmt.kind {
hir::StmtKind::Local(ref local) => {
- println!("local variable of type {}", cx.tables.node_type(local.hir_id));
+ println!("local variable of type {}", cx.tables().node_type(local.hir_id));
println!("pattern:");
print_pat(cx, &local.pat, 0);
if let Some(ref e) = local.init {
fn print_expr(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, indent: usize) {
let ind = " ".repeat(indent);
println!("{}+", ind);
- println!("{}ty: {}", ind, cx.tables.expr_ty(expr));
- println!("{}adjustments: {:?}", ind, cx.tables.adjustments().get(expr.hir_id));
+ println!("{}ty: {}", ind, cx.tables().expr_ty(expr));
+ println!("{}adjustments: {:?}", ind, cx.tables().adjustments().get(expr.hir_id));
match expr.kind {
hir::ExprKind::Box(ref e) => {
println!("{}Box", ind);
) = ty.kind
{
if let TyKind::Path(ref path) = inner.kind {
- if let Res::Def(DefKind::Struct, def_id) = cx.tables.qpath_res(path, inner.hir_id) {
+ if let Res::Def(DefKind::Struct, def_id) = cx.tables().qpath_res(path, inner.hir_id) {
return match_def_path(cx, def_id, &paths::LINT);
}
}
if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
let fn_name = path.ident;
if let Some(sugg) = self.map.get(&*fn_name.as_str());
- let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
+ let ty = walk_ptrs_ty(cx.tables().expr_ty(&args[0]));
if match_type(cx, ty, &paths::EARLY_CONTEXT)
|| match_type(cx, ty, &paths::LATE_CONTEXT);
then {
let args = arg_lists[1];
if args.len() == 1;
let self_arg = &args[0];
- let self_ty = walk_ptrs_ty(cx.tables.expr_ty(self_arg));
+ let self_ty = walk_ptrs_ty(cx.tables().expr_ty(self_arg));
if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
then {
span_lint_and_sugg(
/// Checks if the method call given in `expr` belongs to the given trait.
pub fn match_trait_method(cx: &LateContext<'_, '_>, expr: &Expr<'_>, path: &[&str]) -> bool {
- let def_id = cx.tables.type_dependent_def_id(expr.hir_id).unwrap();
+ let def_id = cx.tables().type_dependent_def_id(expr.hir_id).unwrap();
let trt_id = cx.tcx.trait_of_item(def_id);
if let Some(trt_id) = trt_id {
match_def_path(cx, trt_id, path)
/// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_typeck::check::coercion` for more
/// information on adjustments and coercions.
pub fn is_adjusted(cx: &LateContext<'_, '_>, e: &Expr<'_>) -> bool {
- cx.tables.adjustments().get(e.hir_id).is_some()
+ cx.tables().adjustments().get(e.hir_id).is_some()
}
/// Returns the pre-expansion span if is this comes from an expansion of the
}
pub fn is_copy<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
- ty.is_copy_modulo_regions(cx.tcx, cx.param_env, DUMMY_SP)
+ ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env)
}
/// Checks if an expression is constructing a tuple-like enum variant or struct
pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
if let ExprKind::Call(ref fun, _) = expr.kind {
if let ExprKind::Path(ref qp) = fun.kind {
- let res = cx.tables.qpath_res(qp, fun.hir_id);
+ let res = cx.tables().qpath_res(qp, fun.hir_id);
return match res {
def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
pub fn is_refutable(cx: &LateContext<'_, '_>, pat: &Pat<'_>) -> bool {
fn is_enum_variant(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, id: HirId) -> bool {
matches!(
- cx.tables.qpath_res(qpath, id),
+ cx.tables().qpath_res(qpath, id),
def::Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _)
)
}
is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat))
},
PatKind::Slice(ref head, ref middle, ref tail) => {
- match &cx.tables.node_type(pat.hir_id).kind {
+ match &cx.tables().node_type(pat.hir_id).kind {
ty::Slice(..) => {
// [..] is the only irrefutable slice pattern.
!head.is_empty() || middle.is_none() || !tail.is_empty()
if_chain! {
if let ExprKind::Call(ref fun, ref args) = expr.kind;
if let ExprKind::Path(ref qpath) = fun.kind;
- if let Some(fun_def_id) = cx.tables.qpath_res(qpath, fun.hir_id).opt_def_id();
+ if let Some(fun_def_id) = cx.tables().qpath_res(qpath, fun.hir_id).opt_def_id();
if match_def_path(cx, fun_def_id, path);
then {
return Some(&args)
let did = match expr.kind {
ExprKind::Call(ref path, _) => if_chain! {
if let ExprKind::Path(ref qpath) = path.kind;
- if let def::Res::Def(_, did) = cx.tables.qpath_res(qpath, path.hir_id);
+ if let def::Res::Def(_, did) = cx.tables().qpath_res(qpath, path.hir_id);
then {
Some(did)
} else {
None
}
},
- ExprKind::MethodCall(_, _, _, _) => cx.tables.type_dependent_def_id(expr.hir_id),
+ ExprKind::MethodCall(_, _, _, _) => cx.tables().type_dependent_def_id(expr.hir_id),
_ => None,
};
}
/// Convenience extension trait for `DiagnosticBuilder`.
-pub trait DiagnosticBuilderExt<'a, T: LintContext> {
+pub trait DiagnosticBuilderExt<T: LintContext> {
/// Suggests to add an attribute to an item.
///
/// Correctly handles indentation of the attribute and item.
fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability: Applicability);
}
-impl<'a, 'b, 'c, T: LintContext> DiagnosticBuilderExt<'c, T> for rustc_errors::DiagnosticBuilder<'b> {
+impl<T: LintContext> DiagnosticBuilderExt<T> for rustc_errors::DiagnosticBuilder<'_> {
fn suggest_item_with_attr<D: Display + ?Sized>(
&mut self,
cx: &T,
use rustc_middle::hir::map::Map;
use rustc_middle::ty;
use rustc_span::symbol::{Ident, Symbol};
-use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase};
+use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
/// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
pub fn mutated_variables<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &'a LateContext<'a, 'tcx>) -> Option<FxHashSet<HirId>> {
};
let def_id = expr.hir_id.owner.to_def_id();
cx.tcx.infer_ctxt().enter(|infcx| {
- ExprUseVisitor::new(&mut delegate, &infcx, def_id.expect_local(), cx.param_env, cx.tables).walk_expr(expr);
+ ExprUseVisitor::new(&mut delegate, &infcx, def_id.expect_local(), cx.param_env, cx.tables()).walk_expr(expr);
});
if delegate.skip {
impl<'tcx> MutVarsDelegate {
#[allow(clippy::similar_names)]
- fn update(&mut self, cat: &Place<'tcx>) {
- match cat.base {
+ fn update(&mut self, cat: &PlaceWithHirId<'tcx>) {
+ match cat.place.base {
PlaceBase::Local(id) => {
self.used_mutably.insert(id);
},
}
impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
- fn consume(&mut self, _: &Place<'tcx>, _: ConsumeMode) {}
+ fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: ConsumeMode) {}
- fn borrow(&mut self, cmt: &Place<'tcx>, bk: ty::BorrowKind) {
+ fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) {
if let ty::BorrowKind::MutBorrow = bk {
self.update(&cmt)
}
}
- fn mutate(&mut self, cmt: &Place<'tcx>) {
+ fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) {
self.update(&cmt)
}
}
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
// search for `&vec![_]` expressions where the adjusted type is `&[_]`
if_chain! {
- if let ty::Ref(_, ty, _) = cx.tables.expr_ty_adjusted(expr).kind;
+ if let ty::Ref(_, ty, _) = cx.tables().expr_ty_adjusted(expr).kind;
if let ty::Slice(..) = ty.kind;
if let ExprKind::AddrOf(BorrowKind::Ref, _, ref addressee) = expr.kind;
if let Some(vec_args) = higher::vec_macro(cx, addressee);
if_chain! {
if let Some((_, arg, _)) = higher::for_loop(expr);
if let Some(vec_args) = higher::vec_macro(cx, arg);
- if is_copy(cx, vec_type(cx.tables.expr_ty_adjusted(arg)));
+ if is_copy(cx, vec_type(cx.tables().expr_ty_adjusted(arg)));
then {
// report the error around the `vec!` not inside `<std macros>:`
let span = arg.span
let mut applicability = Applicability::MachineApplicable;
let snippet = match *vec_args {
higher::VecArgs::Repeat(elem, len) => {
- if constant(cx, cx.tables, len).is_some() {
+ if constant(cx, cx.tables(), len).is_some() {
format!(
"&[{}; {}]",
snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
if let hir::ExprKind::MethodCall(path_segment, _, ref args, _) = expr.kind;
- if let Some(method_def_id) = cx.tables.type_dependent_def_id(expr.hir_id);
+ if let Some(method_def_id) = cx.tables().type_dependent_def_id(expr.hir_id);
if match_def_path(cx, method_def_id, &paths::VEC_RESIZE) && args.len() == 3;
if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = args[1].kind;
if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = args[2].kind;
if let ExprKind::MethodCall(method_name, _, exprs, _) = expr.kind;
if method_name.ident.as_str() == "read_to_end";
if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind;
- let ty = cx.tables.expr_ty(&exprs[0]);
+ let ty = cx.tables().expr_ty(&exprs[0]);
if match_type(cx, ty, &paths::FILE);
then {
return true
if let ExprKind::MethodCall(method_name, _, exprs, _) = expr.kind;
if method_name.ident.as_str() == "read_to_string";
if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind;
- let ty = cx.tables.expr_ty(&exprs[0]);
+ let ty = cx.tables().expr_ty(&exprs[0]);
if match_type(cx, ty, &paths::FILE);
then {
return true
declare_clippy_lint! {
/// **What it does:** Checks for wildcard imports `use _::*`.
///
- /// **Why is this bad?** wildcard imports can polute the namespace. This is especially bad if
+ /// **Why is this bad?** wildcard imports can pollute the namespace. This is especially bad if
/// you try to import something through a wildcard, that already has been imported by name from
/// a different source:
///
// TODO - constant_simple does not fold many operations involving floats.
// That's probably fine for this lint - it's pretty unlikely that someone would
// do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too.
- if let Some(lhs_value) = constant_simple(cx, cx.tables, left);
- if let Some(rhs_value) = constant_simple(cx, cx.tables, right);
+ if let Some(lhs_value) = constant_simple(cx, cx.tables(), left);
+ if let Some(rhs_value) = constant_simple(cx, cx.tables(), right);
if Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value;
if Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value;
then {
Sometimes you may want to retrieve the type `Ty` of an expression `Expr`, for example to answer following questions:
- which type does this expression correspond to (using its [`TyKind`][TyKind])?
-- is it a sized type?
+- is it a sized type?
- is it a primitive type?
- does it implement a trait?
-This operation is performed using the [`expr_ty()`][expr_ty] method from the [`TypeckTables`][TypeckTables] struct,
+This operation is performed using the [`expr_ty()`][expr_ty] method from the [`TypeckTables`][TypeckTables] struct,
that gives you access to the underlying structure [`TyS`][TyS].
Example of use:
impl LateLintPass<'_, '_> for MyStructLint {
fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
// Get type of `expr`
- let ty = cx.tables.expr_ty(expr);
+ let ty = cx.tables().expr_ty(expr);
// Match its kind to enter its type
match ty.kind {
ty::Adt(adt_def, _) if adt_def.is_struct() => println!("Our `expr` is a struct!"),
}
```
-Similarly in [`TypeckTables`][TypeckTables] methods, you have the [`pat_ty()`][pat_ty] method
+Similarly in [`TypeckTables`][TypeckTables] methods, you have the [`pat_ty()`][pat_ty] method
to retrieve a type from a pattern.
Two noticeable items here:
-- `cx` is the lint context [`LateContext`][LateContext].
- The two most useful data structures in this context are `tcx` and `tables`,
+- `cx` is the lint context [`LateContext`][LateContext].
+ The two most useful data structures in this context are `tcx` and `tables`,
allowing us to jump to type definitions and other compilation stages such as HIR.
-- `tables` is [`TypeckTables`][TypeckTables] and is created by type checking step,
+- `tables` is [`TypeckTables`][TypeckTables] and is created by type checking step,
it includes useful information such as types of expressions, ways to resolve methods and so on.
# Checking if an expr is calling a specific method
}
// 2. Using type context `TyCtxt`
- let ty = cx.tables.expr_ty(expr);
+ let ty = cx.tables().expr_ty(expr);
if cx.tcx.lang_items()
// we are looking for the `DefId` of `Drop` trait in lang items
.drop_trait()
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![feature(rustc_private)]
+#![cfg_attr(feature = "deny-warnings", deny(warnings))]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
+// warn on rustc internal lints
+#![deny(rustc::internal)]
// FIXME: switch to something more ergonomic here, once available.
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
-#[allow(unused_extern_crates)]
+extern crate rustc_data_structures;
extern crate rustc_driver;
-#[allow(unused_extern_crates)]
extern crate rustc_errors;
-#[allow(unused_extern_crates)]
extern crate rustc_interface;
-#[allow(unused_extern_crates)]
extern crate rustc_middle;
use rustc_interface::interface;
#[allow(clippy::find_map, clippy::filter_map)]
fn describe_lints() {
use lintlist::{Level, Lint, ALL_LINTS, LINT_LEVELS};
- use std::collections::HashSet;
+ use rustc_data_structures::fx::FxHashSet;
println!(
"
let scoped = |x: &str| format!("clippy::{}", x);
- let lint_groups: HashSet<_> = lints.iter().map(|lint| lint.group).collect();
+ let lint_groups: FxHashSet<_> = lints.iter().map(|lint| lint.group).collect();
println!("Lint checks provided by clippy:\n");
println!(" {} {:7.7} meaning", padded("name"), "default");
Common options:
-h, --help Print this message
+ --rustc Pass all args to rustc
-V, --version Print version info and exit
Other options are the same as `cargo check`.
exit(rustc_driver::catch_with_exit_code(move || {
let mut orig_args: Vec<String> = env::args().collect();
- if orig_args.iter().any(|a| a == "--version" || a == "-V") {
- let version_info = rustc_tools_util::get_version_info!();
- println!("{}", version_info);
- exit(0);
- }
-
// Get the sysroot, looking from most specific to this invocation to the least:
// - command line
// - runtime environment
.map(|pb| pb.to_string_lossy().to_string())
.expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");
+ // make "clippy-driver --rustc" work like a subcommand that passes further args to "rustc"
+ // for example `clippy-driver --rustc --version` will print the rustc version that clippy-driver
+ // uses
+ if let Some(pos) = orig_args.iter().position(|arg| arg == "--rustc") {
+ orig_args.remove(pos);
+ orig_args[0] = "rustc".to_string();
+
+ // if we call "rustc", we need to pass --sysroot here as well
+ let mut args: Vec<String> = orig_args.clone();
+ if !have_sys_root_arg {
+ args.extend(vec!["--sysroot".into(), sys_root]);
+ };
+
+ return rustc_driver::run_compiler(&args, &mut DefaultCallbacks, None, None);
+ }
+
+ if orig_args.iter().any(|a| a == "--version" || a == "-V") {
+ let version_info = rustc_tools_util::get_version_info!();
+ println!("{}", version_info);
+ exit(0);
+ }
+
// Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
// We're invoking the compiler programmatically, so we ignore this/
let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref());
},
Lint {
name: "unnested_or_patterns",
- group: "complexity",
+ group: "pedantic",
desc: "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`",
deprecation: None,
module: "unnested_or_patterns",
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
use rustc_tools_util::VersionInfo;
use std::env;
if let Some(name) = path.file_name().and_then(OsStr::to_str) {
for dep in CRATES {
if name.starts_with(&format!("lib{}-", dep)) && name.ends_with(".rlib") {
- crates.entry(dep).or_insert(path);
+ if let Some(old) = crates.insert(dep, path.clone()) {
+ panic!("Found multiple rlibs for crate `{}`: `{:?}` and `{:?}", dep, old, path);
+ }
break;
}
}
--- /dev/null
+extern crate macro_rules;
+
+// STMT
+#[macro_export]
+macro_rules! pub_macro {
+ () => {
+ let _ = "hello Mr. Vonnegut";
+ };
+}
+
+pub mod inner {
+ pub use super::*;
+
+ // RE-EXPORT
+ // this will stick in `inner` module
+ pub use macro_rules::foofoo;
+ pub use macro_rules::try_err;
+
+ pub mod nested {
+ pub use macro_rules::string_add;
+ }
+
+ // ITEM
+ #[macro_export]
+ macro_rules! inner_mod_macro {
+ () => {
+ #[allow(dead_code)]
+ pub struct Tardis;
+ };
+ }
+}
+
+// EXPR
+#[macro_export]
+macro_rules! function_macro {
+ () => {
+ if true {
+ } else {
+ }
+ };
+}
+
+// TYPE
+#[macro_export]
+macro_rules! ty_macro {
+ () => {
+ Vec<u8>
+ };
+}
+
+mod extern_exports {
+ pub(super) mod private_inner {
+ #[macro_export]
+ macro_rules! pub_in_private_macro {
+ ($name:ident) => {
+ let $name = String::from("secrets and lies");
+ };
+ }
+ }
+}
fn main() {
let foo = 42;
- let bar = 42;
let baz = 42;
+ let quux = 42;
+ // Unlike these others, `bar` is actually considered an acceptable name.
+ // Among many other legitimate uses, bar commonly refers to a period of time in music.
+ // See https://github.com/rust-lang/rust-clippy/issues/5225.
+ let bar = 42;
- let barb = 42;
- let barbaric = 42;
+ let food = 42;
+ let foodstuffs = 42;
+ let bazaar = 42;
match (42, Some(1337), Some(0)) {
- (foo, Some(bar), baz @ Some(_)) => (),
+ (foo, Some(baz), quux @ Some(_)) => (),
_ => (),
}
}
fn issue_1647(mut foo: u8) {
- let mut bar = 0;
- if let Some(mut baz) = Some(42) {}
+ let mut baz = 0;
+ if let Some(mut quux) = Some(42) {}
}
fn issue_1647_ref() {
- let ref bar = 0;
- if let Some(ref baz) = Some(42) {}
+ let ref baz = 0;
+ if let Some(ref quux) = Some(42) {}
}
fn issue_1647_ref_mut() {
- let ref mut bar = 0;
- if let Some(ref mut baz) = Some(42) {}
+ let ref mut baz = 0;
+ if let Some(ref mut quux) = Some(42) {}
}
LL | let foo = 42;
| ^^^
-error: use of a blacklisted/placeholder name `bar`
+error: use of a blacklisted/placeholder name `baz`
--> $DIR/blacklisted_name.rs:15:9
|
-LL | let bar = 42;
+LL | let baz = 42;
| ^^^
-error: use of a blacklisted/placeholder name `baz`
+error: use of a blacklisted/placeholder name `quux`
--> $DIR/blacklisted_name.rs:16:9
|
-LL | let baz = 42;
- | ^^^
+LL | let quux = 42;
+ | ^^^^
error: use of a blacklisted/placeholder name `foo`
- --> $DIR/blacklisted_name.rs:22:10
+ --> $DIR/blacklisted_name.rs:27:10
|
-LL | (foo, Some(bar), baz @ Some(_)) => (),
+LL | (foo, Some(baz), quux @ Some(_)) => (),
| ^^^
-error: use of a blacklisted/placeholder name `bar`
- --> $DIR/blacklisted_name.rs:22:20
+error: use of a blacklisted/placeholder name `baz`
+ --> $DIR/blacklisted_name.rs:27:20
|
-LL | (foo, Some(bar), baz @ Some(_)) => (),
+LL | (foo, Some(baz), quux @ Some(_)) => (),
| ^^^
-error: use of a blacklisted/placeholder name `baz`
- --> $DIR/blacklisted_name.rs:22:26
+error: use of a blacklisted/placeholder name `quux`
+ --> $DIR/blacklisted_name.rs:27:26
|
-LL | (foo, Some(bar), baz @ Some(_)) => (),
- | ^^^
+LL | (foo, Some(baz), quux @ Some(_)) => (),
+ | ^^^^
error: use of a blacklisted/placeholder name `foo`
- --> $DIR/blacklisted_name.rs:27:19
+ --> $DIR/blacklisted_name.rs:32:19
|
LL | fn issue_1647(mut foo: u8) {
| ^^^
-error: use of a blacklisted/placeholder name `bar`
- --> $DIR/blacklisted_name.rs:28:13
+error: use of a blacklisted/placeholder name `baz`
+ --> $DIR/blacklisted_name.rs:33:13
|
-LL | let mut bar = 0;
+LL | let mut baz = 0;
| ^^^
-error: use of a blacklisted/placeholder name `baz`
- --> $DIR/blacklisted_name.rs:29:21
+error: use of a blacklisted/placeholder name `quux`
+ --> $DIR/blacklisted_name.rs:34:21
|
-LL | if let Some(mut baz) = Some(42) {}
- | ^^^
+LL | if let Some(mut quux) = Some(42) {}
+ | ^^^^
-error: use of a blacklisted/placeholder name `bar`
- --> $DIR/blacklisted_name.rs:33:13
+error: use of a blacklisted/placeholder name `baz`
+ --> $DIR/blacklisted_name.rs:38:13
|
-LL | let ref bar = 0;
+LL | let ref baz = 0;
| ^^^
-error: use of a blacklisted/placeholder name `baz`
- --> $DIR/blacklisted_name.rs:34:21
+error: use of a blacklisted/placeholder name `quux`
+ --> $DIR/blacklisted_name.rs:39:21
|
-LL | if let Some(ref baz) = Some(42) {}
- | ^^^
+LL | if let Some(ref quux) = Some(42) {}
+ | ^^^^
-error: use of a blacklisted/placeholder name `bar`
- --> $DIR/blacklisted_name.rs:38:17
+error: use of a blacklisted/placeholder name `baz`
+ --> $DIR/blacklisted_name.rs:43:17
|
-LL | let ref mut bar = 0;
+LL | let ref mut baz = 0;
| ^^^
-error: use of a blacklisted/placeholder name `baz`
- --> $DIR/blacklisted_name.rs:39:25
+error: use of a blacklisted/placeholder name `quux`
+ --> $DIR/blacklisted_name.rs:44:25
|
-LL | if let Some(ref mut baz) = Some(42) {}
- | ^^^
+LL | if let Some(ref mut quux) = Some(42) {}
+ | ^^^^
error: aborting due to 14 previous errors
--- /dev/null
+#![allow(clippy::explicit_counter_loop)]
+
+fn main() {
+ let v = vec![1, 2, 3];
+ let mut i = 0;
+ let max_storage_size = [0; 128 * 1024];
+ for item in &v {
+ bar(i, *item);
+ i += 1;
+ }
+}
+
+fn bar(_: usize, _: u32) {}
fn f(val: &[u8]) {}
+mod issue_5698 {
+ fn mul_not_always_commutative(x: i32, y: i32) -> i32 {
+ if x == 42 {
+ x * y
+ } else if x == 21 {
+ y * x
+ } else {
+ 0
+ }
+ }
+}
+
fn main() {}
--- /dev/null
+// compile-flags: --edition 2018
+// aux-build:macro_rules.rs
+// aux-build:macro_use_helper.rs
+// run-rustfix
+// ignore-32bit
+
+#![allow(unused_imports, unreachable_code, unused_variables, dead_code)]
+#![allow(clippy::single_component_path_imports)]
+#![warn(clippy::macro_use_imports)]
+
+#[macro_use]
+extern crate macro_use_helper as mac;
+
+#[macro_use]
+extern crate clippy_mini_macro_test as mini_mac;
+
+mod a {
+ use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};
+ use mac;
+ use mini_mac::ClippyMiniMacroTest;
+ use mini_mac;
+ use mac::{inner::foofoo, inner::try_err};
+ use mac::inner;
+ use mac::inner::nested::string_add;
+ use mac::inner::nested;
+
+ #[derive(ClippyMiniMacroTest)]
+ struct Test;
+
+ fn test() {
+ pub_macro!();
+ inner_mod_macro!();
+ pub_in_private_macro!(_var);
+ function_macro!();
+ let v: ty_macro!() = Vec::default();
+
+ inner::try_err!();
+ inner::foofoo!();
+ nested::string_add!();
+ }
+}
+
+fn main() {}
-// edition:2018
+// compile-flags: --edition 2018
+// aux-build:macro_rules.rs
+// aux-build:macro_use_helper.rs
+// run-rustfix
+// ignore-32bit
+
+#![allow(unused_imports, unreachable_code, unused_variables, dead_code)]
+#![allow(clippy::single_component_path_imports)]
#![warn(clippy::macro_use_imports)]
-use std::collections::HashMap;
#[macro_use]
-use std::prelude;
+extern crate macro_use_helper as mac;
+
+#[macro_use]
+extern crate clippy_mini_macro_test as mini_mac;
+
+mod a {
+ #[macro_use]
+ use mac;
+ #[macro_use]
+ use mini_mac;
+ #[macro_use]
+ use mac::inner;
+ #[macro_use]
+ use mac::inner::nested;
-fn main() {
- let _ = HashMap::<u8, u8>::new();
- println!();
+ #[derive(ClippyMiniMacroTest)]
+ struct Test;
+
+ fn test() {
+ pub_macro!();
+ inner_mod_macro!();
+ pub_in_private_macro!(_var);
+ function_macro!();
+ let v: ty_macro!() = Vec::default();
+
+ inner::try_err!();
+ inner::foofoo!();
+ nested::string_add!();
+ }
}
+
+fn main() {}
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:5:1
+ --> $DIR/macro_use_imports.rs:18:5
|
-LL | #[macro_use]
- | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use std::prelude::<macro name>`
+LL | #[macro_use]
+ | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};`
|
= note: `-D clippy::macro-use-imports` implied by `-D warnings`
-error: aborting due to previous error
+error: `macro_use` attributes are no longer needed in the Rust 2018 edition
+ --> $DIR/macro_use_imports.rs:20:5
+ |
+LL | #[macro_use]
+ | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
+
+error: `macro_use` attributes are no longer needed in the Rust 2018 edition
+ --> $DIR/macro_use_imports.rs:22:5
+ |
+LL | #[macro_use]
+ | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
+
+error: `macro_use` attributes are no longer needed in the Rust 2018 edition
+ --> $DIR/macro_use_imports.rs:24:5
+ |
+LL | #[macro_use]
+ | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
+
+error: aborting due to 4 previous errors
takes_bool(x);
issue5504();
+ issue5697();
let _ = if gen_opt().is_some() {
1
if m!().is_some() {}
while m!().is_some() {}
}
+
+// None of these should be linted because none of the suggested methods
+// are `const fn` without toggling a feature.
+const fn issue5697() {
+ if let Ok(_) = Ok::<i32, i32>(42) {}
+
+ if let Err(_) = Err::<i32, i32>(42) {}
+
+ if let Some(_) = Some(42) {}
+
+ if let None = None::<()> {}
+
+ while let Ok(_) = Ok::<i32, i32>(10) {}
+
+ while let Err(_) = Ok::<i32, i32>(10) {}
+
+ while let Some(_) = Some(42) {}
+
+ while let None = None::<()> {}
+
+ match Ok::<i32, i32>(42) {
+ Ok(_) => true,
+ Err(_) => false,
+ };
+
+ match Err::<i32, i32>(42) {
+ Ok(_) => false,
+ Err(_) => true,
+ };
+ match Some(42) {
+ Some(_) => true,
+ None => false,
+ };
+
+ match None::<()> {
+ Some(_) => false,
+ None => true,
+ };
+}
takes_bool(x);
issue5504();
+ issue5697();
let _ = if let Some(_) = gen_opt() {
1
if let Some(_) = m!() {}
while let Some(_) = m!() {}
}
+
+// None of these should be linted because none of the suggested methods
+// are `const fn` without toggling a feature.
+const fn issue5697() {
+ if let Ok(_) = Ok::<i32, i32>(42) {}
+
+ if let Err(_) = Err::<i32, i32>(42) {}
+
+ if let Some(_) = Some(42) {}
+
+ if let None = None::<()> {}
+
+ while let Ok(_) = Ok::<i32, i32>(10) {}
+
+ while let Err(_) = Ok::<i32, i32>(10) {}
+
+ while let Some(_) = Some(42) {}
+
+ while let None = None::<()> {}
+
+ match Ok::<i32, i32>(42) {
+ Ok(_) => true,
+ Err(_) => false,
+ };
+
+ match Err::<i32, i32>(42) {
+ Ok(_) => false,
+ Err(_) => true,
+ };
+ match Some(42) {
+ Some(_) => true,
+ None => false,
+ };
+
+ match None::<()> {
+ Some(_) => false,
+ None => true,
+ };
+}
| -------^^^^^^^------ help: try this: `if opt.is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:92:20
+ --> $DIR/redundant_pattern_matching.rs:93:20
|
LL | let _ = if let Some(_) = gen_opt() {
| -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:94:19
+ --> $DIR/redundant_pattern_matching.rs:95:19
|
LL | } else if let None = gen_opt() {
| -------^^^^------------ help: try this: `if gen_opt().is_none()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:96:19
+ --> $DIR/redundant_pattern_matching.rs:97:19
|
LL | } else if let Ok(_) = gen_res() {
| -------^^^^^------------ help: try this: `if gen_res().is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:98:19
+ --> $DIR/redundant_pattern_matching.rs:99:19
|
LL | } else if let Err(_) = gen_res() {
| -------^^^^^^------------ help: try this: `if gen_res().is_err()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:131:19
+ --> $DIR/redundant_pattern_matching.rs:132:19
|
LL | while let Some(_) = r#try!(result_opt()) {}
| ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:132:16
+ --> $DIR/redundant_pattern_matching.rs:133:16
|
LL | if let Some(_) = r#try!(result_opt()) {}
| -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:138:12
+ --> $DIR/redundant_pattern_matching.rs:139:12
|
LL | if let Some(_) = m!() {}
| -------^^^^^^^------- help: try this: `if m!().is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:139:15
+ --> $DIR/redundant_pattern_matching.rs:140:15
|
LL | while let Some(_) = m!() {}
| ----------^^^^^^^------- help: try this: `while m!().is_some()`
--- /dev/null
+// run-rustfix
+
+#![feature(const_result)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(unused)]
+
+// Test that results are linted with the feature enabled.
+
+const fn issue_5697() {
+ if Ok::<i32, i32>(42).is_ok() {}
+
+ if Err::<i32, i32>(42).is_err() {}
+
+ while Ok::<i32, i32>(10).is_ok() {}
+
+ while Ok::<i32, i32>(10).is_err() {}
+
+ Ok::<i32, i32>(42).is_ok();
+
+ Err::<i32, i32>(42).is_err();
+
+ // These should not be linted until `const_option` is implemented.
+ // See https://github.com/rust-lang/rust/issues/67441
+
+ if let Some(_) = Some(42) {}
+
+ if let None = None::<()> {}
+
+ while let Some(_) = Some(42) {}
+
+ while let None = None::<()> {}
+
+ match Some(42) {
+ Some(_) => true,
+ None => false,
+ };
+
+ match None::<()> {
+ Some(_) => false,
+ None => true,
+ };
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+
+#![feature(const_result)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(unused)]
+
+// Test that results are linted with the feature enabled.
+
+const fn issue_5697() {
+ if let Ok(_) = Ok::<i32, i32>(42) {}
+
+ if let Err(_) = Err::<i32, i32>(42) {}
+
+ while let Ok(_) = Ok::<i32, i32>(10) {}
+
+ while let Err(_) = Ok::<i32, i32>(10) {}
+
+ match Ok::<i32, i32>(42) {
+ Ok(_) => true,
+ Err(_) => false,
+ };
+
+ match Err::<i32, i32>(42) {
+ Ok(_) => false,
+ Err(_) => true,
+ };
+
+ // These should not be linted until `const_option` is implemented.
+ // See https://github.com/rust-lang/rust/issues/67441
+
+ if let Some(_) = Some(42) {}
+
+ if let None = None::<()> {}
+
+ while let Some(_) = Some(42) {}
+
+ while let None = None::<()> {}
+
+ match Some(42) {
+ Some(_) => true,
+ None => false,
+ };
+
+ match None::<()> {
+ Some(_) => false,
+ None => true,
+ };
+}
+
+fn main() {}
--- /dev/null
+error: redundant pattern matching, consider using `is_ok()`
+ --> $DIR/redundant_pattern_matching_const_result.rs:10:12
+ |
+LL | if let Ok(_) = Ok::<i32, i32>(42) {}
+ | -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
+ |
+ = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+
+error: redundant pattern matching, consider using `is_err()`
+ --> $DIR/redundant_pattern_matching_const_result.rs:12:12
+ |
+LL | if let Err(_) = Err::<i32, i32>(42) {}
+ | -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
+
+error: redundant pattern matching, consider using `is_ok()`
+ --> $DIR/redundant_pattern_matching_const_result.rs:14:15
+ |
+LL | while let Ok(_) = Ok::<i32, i32>(10) {}
+ | ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+ --> $DIR/redundant_pattern_matching_const_result.rs:16:15
+ |
+LL | while let Err(_) = Ok::<i32, i32>(10) {}
+ | ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
+
+error: redundant pattern matching, consider using `is_ok()`
+ --> $DIR/redundant_pattern_matching_const_result.rs:18:5
+ |
+LL | / match Ok::<i32, i32>(42) {
+LL | | Ok(_) => true,
+LL | | Err(_) => false,
+LL | | };
+ | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+ --> $DIR/redundant_pattern_matching_const_result.rs:23:5
+ |
+LL | / match Err::<i32, i32>(42) {
+LL | | Ok(_) => false,
+LL | | Err(_) => true,
+LL | | };
+ | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
+
+error: aborting due to 6 previous errors
+
std::mem::forget(mem::replace(&mut v, new_v));
}
+ unsafe {
+ let taken_v = mem::replace(&mut v, mem::MaybeUninit::uninit().assume_init());
+ let new_v = might_panic(taken_v);
+ std::mem::forget(mem::replace(&mut v, new_v));
+ }
+
unsafe {
let taken_v = mem::replace(&mut v, mem::zeroed());
let new_v = might_panic(taken_v);
--> $DIR/repl_uninit.rs:15:23
|
LL | let taken_v = mem::replace(&mut v, mem::uninitialized());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(&mut v)`
|
= note: `-D clippy::mem-replace-with-uninit` implied by `-D warnings`
- = help: consider using the `take_mut` crate instead
-error: replacing with `mem::zeroed()`
+error: replacing with `mem::MaybeUninit::uninit().assume_init()`
--> $DIR/repl_uninit.rs:21:23
|
+LL | let taken_v = mem::replace(&mut v, mem::MaybeUninit::uninit().assume_init());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(&mut v)`
+
+error: replacing with `mem::zeroed()`
+ --> $DIR/repl_uninit.rs:27:23
+ |
LL | let taken_v = mem::replace(&mut v, mem::zeroed());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider using a default value or the `take_mut` crate instead
error: replacing with `mem::uninitialized()`
- --> $DIR/repl_uninit.rs:33:28
+ --> $DIR/repl_uninit.rs:39:28
|
LL | let taken_u = unsafe { mem::replace(uref, mem::uninitialized()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider using the `take_mut` crate instead
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(uref)`
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
pub enum CompareMode {
Nll,
Polonius,
+ Chalk,
}
impl CompareMode {
match *self {
CompareMode::Nll => "nll",
CompareMode::Polonius => "polonius",
+ CompareMode::Chalk => "chalk",
}
}
match s.as_str() {
"nll" => CompareMode::Nll,
"polonius" => CompareMode::Polonius,
+ "chalk" => CompareMode::Chalk,
x => panic!("unknown --compare-mode option: {}", x),
}
}
let mut props = EarlyProps::default();
let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some();
+ let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target);
+ let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);
+ let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target);
+ let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
iter_header(testfile, None, rdr, &mut |ln| {
// we should check if any only-<platform> exists and if it exists
props.ignore = true;
}
- if !rustc_has_sanitizer_support && config.parse_needs_sanitizer_support(ln) {
+ if !rustc_has_sanitizer_support
+ && config.parse_name_directive(ln, "needs-sanitizer-support")
+ {
+ props.ignore = true;
+ }
+
+ if !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address") {
+ props.ignore = true;
+ }
+
+ if !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak") {
+ props.ignore = true;
+ }
+
+ if !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory") {
+ props.ignore = true;
+ }
+
+ if !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread") {
props.ignore = true;
}
}
fn version_to_int(version: &str) -> u32 {
- let version_without_suffix = version.split('-').next().unwrap();
+ let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap();
let components: Vec<u32> = version_without_suffix
.split('.')
.map(|s| s.parse().expect("Malformed version component"))
self.parse_name_directive(line, "needs-profiler-support")
}
- fn parse_needs_sanitizer_support(&self, line: &str) -> bool {
- self.parse_name_directive(line, "needs-sanitizer-support")
- }
-
/// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86`
/// or `normalize-stderr-32bit`.
fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirective {
match self.compare_mode {
Some(CompareMode::Nll) => name == "compare-mode-nll",
Some(CompareMode::Polonius) => name == "compare-mode-polonius",
+ Some(CompareMode::Chalk) => name == "compare-mode-chalk",
None => false,
} ||
(cfg!(debug_assertions) && name == "debug") ||
config.debugger = Some(Debugger::Lldb);
assert!(parse_rs(&config, "// ignore-lldb").ignore);
}
+
+#[test]
+fn sanitizers() {
+ let mut config = config();
+
+ // Target that supports all sanitizers:
+ config.target = "x86_64-unknown-linux-gnu".to_owned();
+ assert!(!parse_rs(&config, "// needs-sanitizer-address").ignore);
+ assert!(!parse_rs(&config, "// needs-sanitizer-leak").ignore);
+ assert!(!parse_rs(&config, "// needs-sanitizer-memory").ignore);
+ assert!(!parse_rs(&config, "// needs-sanitizer-thread").ignore);
+
+ // Target that doesn't support sanitizers:
+ config.target = "wasm32-unknown-emscripten".to_owned();
+ assert!(parse_rs(&config, "// needs-sanitizer-address").ignore);
+ assert!(parse_rs(&config, "// needs-sanitizer-leak").ignore);
+ assert!(parse_rs(&config, "// needs-sanitizer-memory").ignore);
+ assert!(parse_rs(&config, "// needs-sanitizer-thread").ignore);
+}
use crate::errors::{Error, ErrorKind};
use crate::runtest::ProcRes;
use serde::Deserialize;
-use serde_json;
use std::path::{Path, PathBuf};
use std::str::FromStr;
#![crate_name = "compiletest"]
-#![feature(vec_remove_item)]
-#![deny(warnings)]
// The `test` crate is the only unstable feature
// allowed here, just to share similar code.
#![feature(test)]
use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS};
use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, Pretty, TestPaths};
use crate::util::logv;
-use env_logger;
-use getopts;
use getopts::Options;
use log::*;
use std::env;
#[cfg(unix)]
mod imp {
- use libc;
use std::io;
use std::io::prelude::*;
use std::mem;
use crate::json;
use crate::util::get_pointer_width;
use crate::util::{logv, PathBufExt};
-use diff;
use regex::{Captures, Regex};
use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
Some(CompareMode::Polonius) => {
rustc.args(&["-Zpolonius", "-Zborrowck=mir"]);
}
+ Some(CompareMode::Chalk) => {
+ rustc.args(&["-Zchalk"]);
+ }
None => {}
}
("xcore", "xcore"),
];
+pub const ASAN_SUPPORTED_TARGETS: &'static [&'static str] = &[
+ "aarch64-fuchsia",
+ "aarch64-unknown-linux-gnu",
+ "x86_64-apple-darwin",
+ "x86_64-fuchsia",
+ "x86_64-unknown-linux-gnu",
+];
+
+pub const LSAN_SUPPORTED_TARGETS: &'static [&'static str] =
+ &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
+
+pub const MSAN_SUPPORTED_TARGETS: &'static [&'static str] =
+ &["aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu"];
+
+pub const TSAN_SUPPORTED_TARGETS: &'static [&'static str] =
+ &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
+
pub fn matches_os(triple: &str, name: &str) -> bool {
// For the wasm32 bare target we ignore anything also ignored on emscripten
// and then we also recognize `wasm32-bare` as the os for the target
#![feature(rustc_private)]
-#![deny(warnings)]
extern crate env_logger;
extern crate rustc_ast;
impl Error for StrError {}
impl std::fmt::Display for StrError {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
}
impl std::fmt::Display for WithContext {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.context)
}
}
//! A few whitelisted exceptions are allowed as there's known bugs in rustdoc,
//! but this should catch the majority of "broken link" cases.
-#![deny(warnings)]
-
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::env;
-Subproject commit faff9a7ad9f2d07c1702bd8be392134d27e3eaf8
+Subproject commit fd8101247749c5be6850d5cb5096f01a1867e5ba
//! Here is also where we bake in the support to spawn the QEMU emulator as
//! well.
-#![deny(warnings)]
-
use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
Command::new("adb").arg("shell").arg("/data/tmp/testd").spawn().unwrap();
}
-fn start_qemu_emulator(target: &str, rootfs: &Path, server: &Path, tmpdir: &Path) {
+fn prepare_rootfs(target: &str, rootfs: &Path, server: &Path, rootfs_img: &Path) {
+ t!(fs::copy(server, rootfs.join("testd")));
+
+ match target {
+ "arm-unknown-linux-gnueabihf" | "aarch64-unknown-linux-gnu" => {
+ prepare_rootfs_cpio(rootfs, rootfs_img)
+ }
+ "riscv64gc-unknown-linux-gnu" => prepare_rootfs_ext4(rootfs, rootfs_img),
+ _ => panic!("{} is not supported", target),
+ }
+}
+
+fn prepare_rootfs_cpio(rootfs: &Path, rootfs_img: &Path) {
// Generate a new rootfs image now that we've updated the test server
// executable. This is the equivalent of:
//
// find $rootfs -print 0 | cpio --null -o --format=newc > rootfs.img
- t!(fs::copy(server, rootfs.join("testd")));
- let rootfs_img = tmpdir.join("rootfs.img");
let mut cmd = Command::new("cpio");
cmd.arg("--null")
.arg("-o")
t!(io::copy(&mut child.stdout.take().unwrap(), &mut t!(File::create(&rootfs_img))));
assert!(t!(child.wait()).success());
+ fn add_files(w: &mut dyn Write, root: &Path, cur: &Path) {
+ for entry in t!(cur.read_dir()) {
+ let entry = t!(entry);
+ let path = entry.path();
+ let to_print = path.strip_prefix(root).unwrap();
+ t!(write!(w, "{}\u{0}", to_print.to_str().unwrap()));
+ if t!(entry.file_type()).is_dir() {
+ add_files(w, root, &path);
+ }
+ }
+ }
+}
+
+fn prepare_rootfs_ext4(rootfs: &Path, rootfs_img: &Path) {
+ let mut dd = Command::new("dd");
+ dd.arg("if=/dev/zero")
+ .arg(&format!("of={}", rootfs_img.to_string_lossy()))
+ .arg("bs=1M")
+ .arg("count=1024");
+ let mut dd_child = t!(dd.spawn());
+ assert!(t!(dd_child.wait()).success());
+
+ let mut mkfs = Command::new("mkfs.ext4");
+ mkfs.arg("-d").arg(rootfs).arg(rootfs_img);
+ let mut mkfs_child = t!(mkfs.spawn());
+ assert!(t!(mkfs_child.wait()).success());
+}
+
+fn start_qemu_emulator(target: &str, rootfs: &Path, server: &Path, tmpdir: &Path) {
+ let rootfs_img = &tmpdir.join("rootfs.img");
+ prepare_rootfs(target, rootfs, server, rootfs_img);
+
// Start up the emulator, in the background
match target {
"arm-unknown-linux-gnueabihf" => {
.arg("virtio-net-device,netdev=net0,mac=00:00:00:00:00:00");
t!(cmd.spawn());
}
- _ => panic!("cannot start emulator for: {}" < target),
- }
-
- fn add_files(w: &mut dyn Write, root: &Path, cur: &Path) {
- for entry in t!(cur.read_dir()) {
- let entry = t!(entry);
- let path = entry.path();
- let to_print = path.strip_prefix(root).unwrap();
- t!(write!(w, "{}\u{0}", to_print.to_str().unwrap()));
- if t!(entry.file_type()).is_dir() {
- add_files(w, root, &path);
- }
+ "riscv64gc-unknown-linux-gnu" => {
+ let mut cmd = Command::new("qemu-system-riscv64");
+ cmd.arg("-nographic")
+ .arg("-machine")
+ .arg("virt")
+ .arg("-m")
+ .arg("1024")
+ .arg("-bios")
+ .arg("none")
+ .arg("-kernel")
+ .arg("/tmp/bbl")
+ .arg("-append")
+ .arg("quiet console=ttyS0 root=/dev/vda rw")
+ .arg("-netdev")
+ .arg("user,id=net0,hostfwd=tcp::12345-:12345")
+ .arg("-device")
+ .arg("virtio-net-device,netdev=net0,mac=00:00:00:00:00:00")
+ .arg("-device")
+ .arg("virtio-blk-device,drive=hd0")
+ .arg("-drive")
+ .arg(&format!("file={},format=raw,id=hd0", &rootfs_img.to_string_lossy()));
+ t!(cmd.spawn());
}
+ _ => panic!("cannot start emulator for: {}", target),
}
}
//! themselves having support libraries. All data over the TCP sockets is in a
//! basically custom format suiting our needs.
-#![deny(warnings)]
-
#[cfg(not(windows))]
use std::fs::Permissions;
#[cfg(not(windows))]
-Subproject commit 8d7a7167c15b9154755588c39b22b2336c89ca68
+Subproject commit fb46b914c11b06828680cb526e2abe9e1d69b868
license = "MIT OR Apache-2.0"
edition = "2018"
-[features]
-linkcheck = ["mdbook-linkcheck", "codespan-reporting", "codespan"]
-
[dependencies]
clap = "2.25.0"
-failure = "0.1"
-mdbook-linkcheck = { version = "0.5.0", optional = true }
-# Keep in sync with mdbook-linkcheck.
-codespan = { version = "0.5", optional = true }
-codespan-reporting = { version = "0.5", optional = true }
-
-
-# A noop dependency that changes in the Rust repository, it's a bit of a hack.
-# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
-# for more information.
-rustc-workspace-hack = "1.0.0"
[dependencies.mdbook]
-version = "0.3.7"
+version = "0.4.0"
default-features = false
features = ["search"]
.about("Tests that a book's Rust code samples compile")
.arg_from_usage(dir_message),
)
- .subcommand(
- SubCommand::with_name("linkcheck")
- .about("Run linkcheck with mdBook 3")
- .arg_from_usage(dir_message),
- )
.get_matches();
// Check which subcomamnd the user ran...
handle_error(e);
}
}
- ("linkcheck", Some(sub_matches)) => {
- #[cfg(feature = "linkcheck")]
- {
- let (diags, files) = linkcheck(sub_matches).expect("Error while linkchecking.");
- if !diags.is_empty() {
- let color = codespan_reporting::term::termcolor::ColorChoice::Auto;
- let mut writer =
- codespan_reporting::term::termcolor::StandardStream::stderr(color);
- let cfg = codespan_reporting::term::Config::default();
-
- for diag in diags {
- codespan_reporting::term::emit(&mut writer, &cfg, &files, &diag)
- .expect("Unable to emit linkcheck error.");
- }
-
- std::process::exit(101);
- }
- }
-
- #[cfg(not(feature = "linkcheck"))]
- {
- // This avoids the `unused_binding` lint.
- println!(
- "mdbook-linkcheck is disabled, but arguments were passed: {:?}",
- sub_matches
- );
- }
- }
(_, _) => unreachable!(),
};
}
-#[cfg(feature = "linkcheck")]
-pub fn linkcheck(
- args: &ArgMatches<'_>,
-) -> Result<(Vec<codespan_reporting::diagnostic::Diagnostic>, codespan::Files), failure::Error> {
- use mdbook_linkcheck::Reason;
-
- let book_dir = get_book_dir(args);
- let src_dir = book_dir.join("src");
- let book = MDBook::load(&book_dir).unwrap();
- let linkck_cfg = mdbook_linkcheck::get_config(&book.config)?;
- let mut files = codespan::Files::new();
- let target_files = mdbook_linkcheck::load_files_into_memory(&book.book, &mut files);
- let cache = mdbook_linkcheck::Cache::default();
-
- let (links, incomplete) = mdbook_linkcheck::extract_links(target_files, &files);
-
- let outcome =
- mdbook_linkcheck::validate(&links, &linkck_cfg, &src_dir, &cache, &files, incomplete)?;
-
- let mut is_real_error = false;
-
- for link in outcome.invalid_links.iter() {
- match &link.reason {
- Reason::FileNotFound | Reason::TraversesParentDirectories => {
- is_real_error = true;
- }
- Reason::UnsuccessfulServerResponse(status) => {
- if status.as_u16() == 429 {
- eprintln!("Received 429 (TOO_MANY_REQUESTS) for link `{}`", link.link.uri);
- } else if status.is_client_error() {
- is_real_error = true;
- } else {
- eprintln!("Unsuccessful server response for link `{}`", link.link.uri);
- }
- }
- Reason::Client(err) => {
- if err.is_timeout() {
- eprintln!("Timeout for link `{}`", link.link.uri);
- } else if err.is_server_error() {
- eprintln!("Server error for link `{}`", link.link.uri);
- } else if !err.is_http() {
- eprintln!("Non-HTTP-related error for link: {} {}", link.link.uri, err);
- } else {
- is_real_error = true;
- }
- }
- }
- }
-
- if is_real_error {
- Ok((outcome.generate_diagnostics(&files, linkck_cfg.warning_policy), files))
- } else {
- Ok((vec![], files))
- }
-}
-
// Build command implementation
pub fn build(args: &ArgMatches<'_>) -> Result3<()> {
let book_dir = get_book_dir(args);
- let mut book = MDBook::load(&book_dir)?;
+ let mut book = load_book(&book_dir)?;
// Set this to allow us to catch bugs in advance.
book.config.build.create_missing = false;
fn test(args: &ArgMatches<'_>) -> Result3<()> {
let book_dir = get_book_dir(args);
- let mut book = MDBook::load(&book_dir)?;
+ let mut book = load_book(&book_dir)?;
book.test(vec![])
}
}
}
+fn load_book(book_dir: &Path) -> Result3<MDBook> {
+ let mut book = MDBook::load(book_dir)?;
+ book.config.set("output.html.input-404", "").unwrap();
+ Ok(book)
+}
+
fn handle_error(error: mdbook::errors::Error) -> ! {
eprintln!("Error: {}", error);
- for cause in error.iter().skip(1) {
+ for cause in error.chain().skip(1) {
eprintln!("\tCaused By: {}", cause);
}
serde_json = { version = "1.0.31", features = ["raw_value"] }
smallvec-0_6 = { package = "smallvec", version = "0.6", features = ['union', 'may_dangle'] }
smallvec = { version = "1.0", features = ['union', 'may_dangle'] }
-syn = { version = "0.15", features = ['full', 'extra-traits'] }
-syn-1 = { package = "syn", version = "1", features = ['fold', 'full', 'extra-traits', 'visit'] }
+syn = { version = "1", features = ['fold', 'full', 'extra-traits', 'visit'] }
url = { version = "2.0", features = ['serde'] }
[target.'cfg(not(windows))'.dependencies]
break;
}
var entry = expected[key];
+
+ if (exact_check == true && entry.length !== results[key].length) {
+ error_text.push(queryName + "==> Expected exactly " + entry.length +
+ " results but found " + results[key].length + " in '" + key + "'");
+ }
+
var prev_pos = -1;
for (var i = 0; i < entry.length; ++i) {
var entry_pos = lookForEntry(entry[i], results[key]);
}
function runChecks(testFile, loaded, index) {
- var loadedFile = loadContent(
- readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
+ var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;';
+ if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
+ testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
+ }
+ var loadedFile = loadContent(testFileContent);
const expected = loadedFile.EXPECTED;
const query = loadedFile.QUERY;
-Subproject commit aedff61f7ac4fc2b287ff76d33f2584e1f63a3af
+Subproject commit c1e9b7b87493c5197c4330693bdf4ccb30a90971
const EXCEPTIONS: &[(&str, &str)] = &[
("mdbook", "MPL-2.0"), // mdbook
("openssl", "Apache-2.0"), // cargo, mdbook
- ("toml-query", "MPL-2.0"), // mdbook
- ("toml-query_derive", "MPL-2.0"), // mdbook
- ("is-match", "MPL-2.0"), // mdbook
("rdrand", "ISC"), // mdbook, rustfmt
("fuchsia-cprng", "BSD-3-Clause"), // mdbook, rustfmt
("fuchsia-zircon-sys", "BSD-3-Clause"), // rustdoc, rustc, cargo
("bitmaps", "MPL-2.0+"), // cargo via im-rc
// FIXME: this dependency violates the documentation comment above:
("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
- ("dunce", "CC0-1.0"), // mdbook-linkcheck
- ("codespan-reporting", "Apache-2.0"), // mdbook-linkcheck
- ("codespan", "Apache-2.0"), // mdbook-linkcheck
("crossbeam-channel", "MIT/Apache-2.0 AND BSD-2-Clause"), // cargo
];
"cc",
"cfg-if",
"chalk-derive",
- "chalk-engine",
"chalk-ir",
- "chalk-macros",
"cloudabi",
"cmake",
"compiler_builtins",
level: Status::Unstable,
since: None,
has_gate_test: false,
- // FIXME(#57563): #57563 is now used as a common tracking issue,
- // although we would like to have specific tracking issues for each
- // `rustc_const_unstable` in the future.
- tracking_issue: NonZeroU32::new(57563),
+ tracking_issue: find_attr_val(line, "issue").and_then(handle_issue_none),
};
mf(Ok((feature_name, feature)), file, i + 1);
continue;
//! etc. This is run by default on `./x.py test` and as part of the auto
//! builders. The tidy checks can be executed with `./x.py test tidy`.
-#![deny(warnings)]
-
use tidy::*;
use std::env;
// std testing crates, okay for now at least
"src/libcore/tests",
"src/liballoc/tests/lib.rs",
+ "src/liballoc/benches/lib.rs",
// The `VaList` implementation must have platform specific code.
// The Windows implementation of a `va_list` is always a character
// pointer regardless of the target architecture. As a result,
//! Auto-generate stub docs for the unstable book
-#![deny(warnings)]
-
use std::collections::BTreeSet;
use std::env;
use std::fs::{self, File};
]
[notify-zulip."I-prioritize"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
topic = "I-prioritize #{number} {title}"
-message_on_add = "@*WG-prioritization* issue #{number} has been requested for prioritization."
+message_on_add = """\
+@*WG-prioritization/alerts* issue #{number} has been requested for prioritization.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#Unprioritized-I-prioritize)
+- Priority?
+- Regression?
+- Notify people/groups?
+- Needs `I-nominated`?
+"""
message_on_remove = "Issue #{number}'s prioritization request has been removed."
[notify-zulip."I-nominated"]
required_labels = ["T-compiler"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
topic = "I-prioritize #{number} {title}"
-message_on_add = "@*WG-prioritization* #{number} has been nominated for discussion in `T-compiler` meeting."
+message_on_add = """\
+@*WG-prioritization/alerts* #{number} has been nominated for discussion in `T-compiler` meeting.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#I-nominated)
+- Already discussed?
+- Worth the meeting time?
+- Add agenda entry:
+ - Why nominated?
+ - Assignee?
+ - Issue? PR? What's the status?
+ - Summary and important details?
+"""
message_on_remove = "#{number}'s nomination has been removed."
[notify-zulip."beta-nominated"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
topic = "Backport #{number} {title}"
-message_on_add = "@*WG-prioritization* PR #{number} has been requested for beta backport."
+message_on_add = """\
+@*WG-prioritization/alerts* PR #{number} has been requested for beta backport.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations)
+Prepare agenda entry:
+- Why nominated?
+- Author, assignee?
+- Important details?
+"""
message_on_remove = "PR #{number}'s beta backport request has been removed."
[notify-zulip."stable-nominated"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
topic = "Backport #{number} {title}"
-message_on_add = "@*WG-prioritization* PR #{number} has been requested for stable backport."
+message_on_add = """\
+@*WG-prioritization/alerts* PR #{number} has been requested for stable backport.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations)
+Prepare agenda entry:
+- Why nominated?
+- Author, assignee?
+- Important details?
+"""
message_on_remove = "PR #{number}'s stable backport request has been removed."
[notify-zulip."S-waiting-on-team"]
required_labels = ["T-compiler"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
topic = "S-waiting-on-team #{number} {title}"
-message_on_add = "@*WG-prioritization* PR #{number} is waiting on `T-compiler`."
+message_on_add = """\
+@*WG-prioritization/alerts* PR #{number} is waiting on `T-compiler`.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#PR%E2%80%99s-waiting-on-team)
+- Prepare agenda entry:
+ - What is it waiting for?
+ - Important details?
+- Could be resolved quickly? Tag `I-nominated`.
+"""
message_on_remove = "PR #{number}'s is no longer waiting on `T-compiler`."
[notify-zulip."P-critical"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
topic = "P-critical #{number} {title}"
-message_on_add = "@*WG-prioritization* issue #{number} has been assigned `P-critical`."
+message_on_add = """\
+@*WG-prioritization/alerts* issue #{number} has been assigned `P-critical`.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions)
+- Notify people/groups?
+- Assign if possible?
+- Add to agenda:
+ - Assignee?
+ - Summary and important details?
+- Other actions to move forward?
+"""
[notify-zulip."P-high"]
-required_labels = ["regression-from-stable-to-*"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+required_labels = ["regression-from-stable-to-[bn]*"] # only nightly and beta regressions
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
topic = "P-high regression #{number} {title}"
-message_on_add = "@*WG-prioritization* issue #{number} has been assigned `P-high` and is a regression."
+message_on_add = """\
+@*WG-prioritization/alerts* issue #{number} has been assigned `P-high` and is a regression.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions)
+Is issue assigned? If not:
+- Try to find an assignee?
+- Otherwise add to agenda:
+ - Mark as unassigned.
+ - Summary and important details?
+"""