source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
dependencies = [
- "getrandom 0.2.8",
+ "getrandom",
"once_cell",
"version_check",
]
dependencies = [
"compiler_builtins",
"core",
- "rand 0.7.3",
+ "rand",
"rand_xorshift",
]
"rustc-demangle",
]
+[[package]]
+name = "base16ct"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
+
+[[package]]
+name = "base64ct"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf"
+
[[package]]
name = "bitflags"
version = "1.3.2"
"toml",
]
+[[package]]
+name = "build_helper"
+version = "0.1.0"
+
[[package]]
name = "bump-stage0"
version = "0.1.0"
"toml",
]
+[[package]]
+name = "bumpalo"
+version = "3.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
+
[[package]]
name = "bytecount"
version = "0.6.2"
"opener",
"openssl",
"os_info",
+ "pasetors",
"pathdiff",
"percent-encoding",
"pretty_env_logger",
"tar",
"tempfile",
"termcolor",
+ "time 0.3.17",
"toml_edit",
"unicode-width",
"unicode-xid",
"glob",
"itertools",
"lazy_static",
+ "pasetors",
+ "serde",
"serde_json",
"snapbox",
"tar",
"termcolor",
+ "time 0.3.17",
"toml_edit",
"url",
"winapi",
"num-integer",
"num-traits",
"serde",
- "time",
+ "time 0.1.43",
"winapi",
]
dependencies = [
"atty",
"bitflags",
- "clap_derive",
+ "clap_derive 3.2.18",
"clap_lex 0.2.2",
"indexmap",
"once_cell",
dependencies = [
"atty",
"bitflags",
+ "clap_derive 4.0.13",
"clap_lex 0.3.0",
+ "once_cell",
"strsim",
"termcolor",
]
"syn",
]
+[[package]]
+name = "clap_derive"
+version = "4.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c42f169caba89a7d512b5418b09864543eeb4d497416c917d7137863bd2076ad"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "clap_lex"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82a90734b3d5dcf656e7624cca6bce9c3a90ee11f900e80141a7427ccfb3d317"
+[[package]]
+name = "const-oid"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b"
+
[[package]]
name = "content_inspector"
version = "0.2.4"
name = "core"
version = "0.0.0"
dependencies = [
- "rand 0.7.3",
+ "rand",
"rand_xorshift",
]
[[package]]
name = "crates-io"
-version = "0.35.0"
+version = "0.35.1"
dependencies = [
"anyhow",
"curl",
"cfg-if",
]
+[[package]]
+name = "crypto-bigint"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef"
+dependencies = [
+ "generic-array",
+ "rand_core",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "crypto-common"
-version = "0.1.2"
+version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
+ "typenum",
]
[[package]]
"quote",
]
+[[package]]
+name = "ct-codecs"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3b7eb4404b8195a9abb6356f4ac07d8ba267045c8d6d220ac4dc992e6cc75df"
+
[[package]]
name = "ctor"
version = "0.1.26"
"syn",
]
+[[package]]
+name = "der"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
+dependencies = [
+ "const-oid",
+ "pem-rfc7468",
+ "zeroize",
+]
+
[[package]]
name = "derive-new"
version = "0.5.8"
[[package]]
name = "digest"
-version = "0.10.2"
+version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837"
+checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
dependencies = [
"block-buffer",
"crypto-common",
+ "subtle",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541"
+[[package]]
+name = "ecdsa"
+version = "0.14.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c"
+dependencies = [
+ "der",
+ "elliptic-curve",
+ "rfc6979",
+ "signature",
+]
+
+[[package]]
+name = "ed25519-compact"
+version = "2.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a3d382e8464107391c8706b4c14b087808ecb909f6c15c34114bc42e53a9e4c"
+dependencies = [
+ "getrandom",
+]
+
[[package]]
name = "either"
version = "1.6.0"
"serde_json",
]
+[[package]]
+name = "elliptic-curve"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3"
+dependencies = [
+ "base16ct",
+ "crypto-bigint",
+ "der",
+ "digest",
+ "ff",
+ "generic-array",
+ "group",
+ "hkdf",
+ "pem-rfc7468",
+ "pkcs8",
+ "rand_core",
+ "sec1",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "ena"
version = "0.14.0"
"instant",
]
+[[package]]
+name = "ff"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
+dependencies = [
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
+name = "fiat-crypto"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a214f5bb88731d436478f3ae1f8a277b62124089ba9fb67f4f93fb100ef73c90"
+
[[package]]
name = "filetime"
version = "0.2.14"
"unicode-width",
]
-[[package]]
-name = "getrandom"
-version = "0.1.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi 0.9.0+wasi-snapshot-preview1",
-]
-
[[package]]
name = "getrandom"
version = "0.2.8"
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if",
+ "js-sys",
"libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi",
+ "wasm-bindgen",
]
[[package]]
"regex",
]
+[[package]]
+name = "group"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
+dependencies = [
+ "ff",
+ "rand_core",
+ "subtle",
+]
+
[[package]]
name = "gsgdt"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
+[[package]]
+name = "hkdf"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
+dependencies = [
+ "hmac",
+]
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
[[package]]
name = "home"
version = "0.5.3"
checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe"
dependencies = [
"bitmaps",
- "rand_core 0.6.2",
+ "rand_core",
"rand_xoshiro",
"sized-chunks",
"typenum",
"libc",
]
+[[package]]
+name = "js-sys"
+version = "0.3.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
+dependencies = [
+ "wasm-bindgen",
+]
+
[[package]]
name = "jsondocck"
version = "0.1.0"
version = "0.1.0"
dependencies = [
"anyhow",
+ "clap 4.0.15",
"fs-err",
"rustdoc-json-types",
+ "serde",
"serde_json",
]
dependencies = [
"colored",
"env_logger 0.9.0",
- "getrandom 0.2.8",
+ "getrandom",
"lazy_static",
"libc",
"libffi",
"libloading",
"log",
"measureme",
- "rand 0.8.5",
+ "rand",
"regex",
"rustc-workspace-hack",
"rustc_version",
"num-traits",
]
+[[package]]
+name = "orion"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2baf7fd2e326e3895c681176788dd227fcd8369350e53c570592d8563fecbb6"
+dependencies = [
+ "fiat-crypto",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "os_info"
version = "3.5.0"
[[package]]
name = "owo-colors"
-version = "3.4.0"
+version = "3.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
+
+[[package]]
+name = "p384"
+version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b"
+checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa"
+dependencies = [
+ "ecdsa",
+ "elliptic-curve",
+ "sha2",
+]
[[package]]
name = "packed_simd_2"
"windows-sys",
]
+[[package]]
+name = "pasetors"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed20c4c21d893414f42e0cbfebe8a8036b5ae9b0264611fb6504e395eda6ceec"
+dependencies = [
+ "ct-codecs",
+ "ed25519-compact",
+ "getrandom",
+ "orion",
+ "p384",
+ "rand_core",
+ "regex",
+ "serde",
+ "serde_json",
+ "sha2",
+ "subtle",
+ "time 0.3.17",
+ "zeroize",
+]
+
[[package]]
name = "pathdiff"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
+[[package]]
+name = "pem-rfc7468"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac"
+dependencies = [
+ "base64ct",
+]
+
[[package]]
name = "percent-encoding"
version = "2.1.0"
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
dependencies = [
"phf_shared",
- "rand 0.8.5",
+ "rand",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+[[package]]
+name = "pkcs8"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba"
+dependencies = [
+ "der",
+ "spki",
+]
+
[[package]]
name = "pkg-config"
version = "0.3.25"
"proc-macro2",
]
-[[package]]
-name = "rand"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
-dependencies = [
- "getrandom 0.1.16",
- "libc",
- "rand_chacha 0.2.2",
- "rand_core 0.5.1",
- "rand_hc",
-]
-
[[package]]
name = "rand"
version = "0.8.5"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
- "rand_chacha 0.3.0",
- "rand_core 0.6.2",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
-dependencies = [
- "ppv-lite86",
- "rand_core 0.5.1",
+ "rand_chacha",
+ "rand_core",
]
[[package]]
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
dependencies = [
"ppv-lite86",
- "rand_core 0.6.2",
+ "rand_core",
]
[[package]]
name = "rand_core"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-dependencies = [
- "getrandom 0.1.16",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
-dependencies = [
- "getrandom 0.2.8",
-]
-
-[[package]]
-name = "rand_hc"
-version = "0.2.0"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
- "rand_core 0.5.1",
+ "getrandom",
]
[[package]]
name = "rand_xorshift"
-version = "0.2.0"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8"
+checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
dependencies = [
- "rand_core 0.5.1",
+ "rand_core",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa"
dependencies = [
- "rand_core 0.6.2",
+ "rand_core",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [
- "getrandom 0.2.8",
+ "getrandom",
"redox_syscall",
]
"walkdir",
]
+[[package]]
+name = "rfc6979"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb"
+dependencies = [
+ "crypto-bigint",
+ "hmac",
+ "zeroize",
+]
+
[[package]]
name = "rls"
version = "2.0.0"
[[package]]
name = "rustc-build-sysroot"
-version = "0.4.0"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20c4b4625eeb148cccf82d5e9b90ad7fab3b11a0204cf75cc7fa04981a0fdffd"
+checksum = "d65b1271cdac365b71b59570ea35d945dea2dd2cc47eba3d33b4bd1e0190ac6d"
dependencies = [
"anyhow",
"rustc_version",
dependencies = [
"bstr 0.2.17",
"clap 3.2.20",
+ "getrandom",
"libc",
"libz-sys",
- "rand 0.8.5",
+ "rand",
"regex",
"serde_json",
"syn",
version = "0.0.0"
dependencies = [
"bitflags",
- "rand 0.8.5",
+ "rand",
"rand_xoshiro",
"rustc_data_structures",
"rustc_index",
"rustc_span",
"rustc_symbol_mangling",
"rustc_target",
+ "rustc_type_ir",
"serde_json",
"smallvec",
"snap",
"rustc_serialize",
"rustc_span",
"rustc_target",
+ "rustc_type_ir",
"serde",
"serde_json",
"termcolor",
name = "rustc_incremental"
version = "0.0.0"
dependencies = [
- "rand 0.8.5",
+ "rand",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
"rustc_session",
"rustc_span",
"rustc_target",
+ "serde",
+ "serde_json",
"smallvec",
"tracing",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+[[package]]
+name = "sec1"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928"
+dependencies = [
+ "base16ct",
+ "der",
+ "generic-array",
+ "pkcs8",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "security-framework"
version = "2.0.0"
[[package]]
name = "semver"
-version = "1.0.12"
+version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
+checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
dependencies = [
"serde",
]
[[package]]
name = "serde"
-version = "1.0.147"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.147"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "serde_json"
-version = "1.0.85"
+version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
+checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
dependencies = [
"indexmap",
"itoa",
[[package]]
name = "sha2"
-version = "0.10.1"
+version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec"
+checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
dependencies = [
"cfg-if",
"cpufeatures",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d"
+[[package]]
+name = "signature"
+version = "1.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
+dependencies = [
+ "digest",
+ "rand_core",
+]
+
[[package]]
name = "similar"
version = "2.1.0"
"uuid",
]
+[[package]]
+name = "spki"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b"
+dependencies = [
+ "base64ct",
+ "der",
+]
+
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
"panic_abort",
"panic_unwind",
"profiler_builtins",
- "rand 0.7.3",
+ "rand",
+ "rand_xorshift",
"rustc-demangle",
"std_detect",
"unwind",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi",
]
[[package]]
"syn",
]
+[[package]]
+name = "subtle"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
+
[[package]]
name = "syn"
-version = "1.0.102"
+version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "termcolor"
-version = "1.1.2"
+version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
"lazy_static",
"miropt-test-tools",
"regex",
+ "semver",
+ "termcolor",
"walkdir",
]
"winapi",
]
+[[package]]
+name = "time"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
+dependencies = [
+ "itoa",
+ "serde",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
+
+[[package]]
+name = "time-macros"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2"
+dependencies = [
+ "time-core",
+]
+
[[package]]
name = "tinystr"
version = "0.7.0"
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
dependencies = [
"cfg-if",
- "rand 0.8.5",
+ "rand",
"static_assertions",
]
[[package]]
name = "typenum"
-version = "1.12.0"
+version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
+checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "ucd-parse"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
- "getrandom 0.2.8",
+ "getrandom",
]
[[package]]
"winapi-util",
]
-[[package]]
-name = "wasi"
-version = "0.9.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
-
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
"rustc-std-workspace-core",
]
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
+
[[package]]
name = "winapi"
version = "0.3.9"
"synstructure",
]
+[[package]]
+name = "zeroize"
+version = "1.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
+
[[package]]
name = "zerovec"
version = "0.9.0"
"library/std",
"library/test",
"src/rustdoc-json-types",
+ "src/tools/build_helper",
"src/tools/cargotest",
"src/tools/clippy",
"src/tools/clippy/clippy_dev",
The Rust build system uses a Python script called `x.py` to build the compiler,
which manages the bootstrapping process. It lives at the root of the project.
-The `x.py` command can be run directly on most systems in the following format:
+The `x.py` command can be run directly on most Unix systems in the following format:
```sh
./x.py <subcommand> [flags]
```
-This is how the documentation and examples assume you are running `x.py`.
-
-Systems such as Ubuntu 20.04 LTS do not create the necessary `python` command by default when Python is installed that allows `x.py` to be run directly. In that case, you can either create a symlink for `python` (Ubuntu provides the `python-is-python3` package for this), or run `x.py` using Python itself:
+This is how the documentation and examples assume you are running `x.py`. Some alternative ways are:
```sh
-# Python 3
-python3 x.py <subcommand> [flags]
+# On a Unix shell if you don't have the necessary `python3` command
+./x <subcommand> [flags]
+
+# On the Windows Command Prompt (if .py files are configured to run Python)
+x.py <subcommand> [flags]
-# Python 2.7
-python2.7 x.py <subcommand> [flags]
+# You can also run Python yourself, e.g.:
+python x.py <subcommand> [flags]
```
More information about `x.py` can be found
PatKind::MacCall(mac) => TyKind::MacCall(mac.clone()),
// `&mut? P` can be reinterpreted as `&mut? T` where `T` is `P` reparsed as a type.
PatKind::Ref(pat, mutbl) => {
- pat.to_ty().map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?
+ pat.to_ty().map(|ty| TyKind::Ref(None, MutTy { ty, mutbl: *mutbl }))?
}
// A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array,
// when `P` can be reparsed as a type `T`.
ExprKind::Paren(expr) => expr.to_ty().map(TyKind::Paren)?,
ExprKind::AddrOf(BorrowKind::Ref, mutbl, expr) => {
- expr.to_ty().map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?
+ expr.to_ty().map(|ty| TyKind::Ref(None, MutTy { ty, mutbl: *mutbl }))?
}
ExprKind::Repeat(expr, expr_len) => {
impl Ty {
pub fn peel_refs(&self) -> &Self {
let mut final_ty = self;
- while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind {
+ while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
final_ty = ty;
}
final_ty
/// A raw pointer (`*const T` or `*mut T`).
Ptr(MutTy),
/// A reference (`&'a T` or `&'a mut T`).
- Rptr(Option<Lifetime>, MutTy),
+ Ref(Option<Lifetime>, MutTy),
/// A bare function (e.g., `fn(usize) -> bool`).
BareFn(P<BareFnTy>),
/// The never type (`!`).
Ok(())
}
Self::Placeholder { operand_idx, modifier: Some(modifier), .. } => {
- write!(f, "{{{}:{}}}", operand_idx, modifier)
+ write!(f, "{{{operand_idx}:{modifier}}}")
}
Self::Placeholder { operand_idx, modifier: None, .. } => {
- write!(f, "{{{}}}", operand_idx)
+ write!(f, "{{{operand_idx}}}")
}
}
}
use fmt::Write;
let mut out = String::new();
for p in s.iter() {
- let _ = write!(out, "{}", p);
+ let _ = write!(out, "{p}");
}
out
}
if ident.name == kw::SelfLower {
return match self.ty.kind {
TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
- TyKind::Rptr(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => {
+ TyKind::Ref(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => {
Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
}
_ => Some(respan(
Mutability::Not,
P(Ty {
id: DUMMY_NODE_ID,
- kind: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl }),
+ kind: TyKind::Ref(lt, MutTy { ty: infer_ty, mutbl }),
span,
tokens: None,
}),
/// `extern` qualifier on a function item or function type.
#[derive(Clone, Copy, Encodable, Decodable, Debug)]
pub enum Extern {
+ /// No explicit extern keyword was used
+ ///
+ /// E.g. `fn foo() {}`
None,
+ /// An explicit extern keyword was used, but with implicit ABI
+ ///
+ /// E.g. `extern fn foo() {}`
+ ///
+ /// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`)
Implicit(Span),
+ /// An explicit extern keyword was used with an explicit ABI
+ ///
+ /// E.g. `extern "C" fn foo() {}`
Explicit(StrLit, Span),
}
/// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
#[derive(Clone, Copy, Encodable, Decodable, Debug)]
pub struct FnHeader {
+ /// The `unsafe` keyword, if any
pub unsafety: Unsafe,
+ /// The `async` keyword, if any
pub asyncness: Async,
+ /// The `const` keyword, if any
pub constness: Const,
+ /// The `extern` keyword and corresponding ABI string, if any
pub ext: Extern,
}
match &self.kind {
AttrKind::Normal(normal) => normal.tokens.as_ref(),
kind @ AttrKind::DocComment(..) => {
- panic!("Called tokens on doc comment attr {:?}", kind)
+ panic!("Called tokens on doc comment attr {kind:?}")
}
}
}
Some(match &mut self.kind {
AttrKind::Normal(normal) => &mut normal.tokens,
kind @ AttrKind::DocComment(..) => {
- panic!("Called tokens_mut on doc comment attr {:?}", kind)
+ panic!("Called tokens_mut on doc comment attr {kind:?}")
}
})
}
AttrKind::Normal(normal) => normal
.tokens
.as_ref()
- .unwrap_or_else(|| panic!("attribute is missing tokens: {:?}", self))
+ .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
.to_attr_token_stream()
.to_tokenstream(),
&AttrKind::DocComment(comment_kind, data) => TokenStream::new(vec![TokenTree::Token(
impl AllocatorKind {
pub fn fn_name(&self, base: Symbol) -> String {
match *self {
- AllocatorKind::Global => format!("__rg_{}", base),
- AllocatorKind::Default => format!("__rdl_{}", base),
+ AllocatorKind::Global => format!("__rg_{base}"),
+ AllocatorKind::Default => format!("__rdl_{base}"),
}
}
}
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never | TyKind::CVarArgs => {}
TyKind::Slice(ty) => vis.visit_ty(ty),
TyKind::Ptr(mt) => vis.visit_mt(mt),
- TyKind::Rptr(lt, mt) => {
+ TyKind::Ref(lt, mt) => {
visit_opt(lt, |lt| noop_visit_lifetime(lt, vis));
vis.visit_mt(mt);
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Lit { kind, symbol, suffix } = *self;
match kind {
- Byte => write!(f, "b'{}'", symbol)?,
- Char => write!(f, "'{}'", symbol)?,
- Str => write!(f, "\"{}\"", symbol)?,
+ Byte => write!(f, "b'{symbol}'")?,
+ Char => write!(f, "'{symbol}'")?,
+ Str => write!(f, "\"{symbol}\"")?,
StrRaw(n) => write!(
f,
"r{delim}\"{string}\"{delim}",
delim = "#".repeat(n as usize),
string = symbol
)?,
- ByteStr => write!(f, "b\"{}\"", symbol)?,
+ ByteStr => write!(f, "b\"{symbol}\"")?,
ByteStrRaw(n) => write!(
f,
"br{delim}\"{string}\"{delim}",
delim = "#".repeat(n as usize),
string = symbol
)?,
- Integer | Float | Bool | Err => write!(f, "{}", symbol)?,
+ Integer | Float | Bool | Err => write!(f, "{symbol}")?,
}
if let Some(suffix) = suffix {
- write!(f, "{}", suffix)?;
+ write!(f, "{suffix}")?;
}
Ok(())
_ => return None,
},
SingleQuote => match joint.kind {
- Ident(name, false) => Lifetime(Symbol::intern(&format!("'{}", name))),
+ Ident(name, false) => Lifetime(Symbol::intern(&format!("'{name}"))),
_ => return None,
},
assert!(
found,
- "Failed to find trailing delimited group in: {:?}",
- target_tokens
+ "Failed to find trailing delimited group in: {target_tokens:?}"
);
}
let mut flat: SmallVec<[_; 1]> = SmallVec::new();
InvalidIntSuffix,
InvalidFloatSuffix,
NonDecimalFloat(u32),
- IntTooLarge,
+ IntTooLarge(u32),
}
impl LitKind {
match *self {
LitKind::Byte(b) => {
let b: String = ascii::escape_default(b).map(Into::<char>::into).collect();
- write!(f, "b'{}'", b)?;
+ write!(f, "b'{b}'")?;
}
LitKind::Char(ch) => write!(f, "'{}'", escape_char_symbol(ch))?,
LitKind::Str(sym, StrStyle::Cooked) => write!(f, "\"{}\"", escape_string_symbol(sym))?,
)?;
}
LitKind::Int(n, ty) => {
- write!(f, "{}", n)?;
+ write!(f, "{n}")?;
match ty {
ast::LitIntType::Unsigned(ty) => write!(f, "{}", ty.name())?,
ast::LitIntType::Signed(ty) => write!(f, "{}", ty.name())?,
}
}
LitKind::Float(symbol, ty) => {
- write!(f, "{}", symbol)?;
+ write!(f, "{symbol}")?;
match ty {
ast::LitFloatType::Suffixed(ty) => write!(f, "{}", ty.name())?,
ast::LitFloatType::Unsuffixed => {}
// but these kinds of errors are already reported by the lexer.
let from_lexer =
base < 10 && s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base));
- if from_lexer { LitError::LexerError } else { LitError::IntTooLarge }
+ if from_lexer { LitError::LexerError } else { LitError::IntTooLarge(base) }
})
}
#[derive(Copy, Clone, Debug)]
pub enum LifetimeCtxt {
/// Appears in a reference type.
- Rptr,
+ Ref,
/// Appears as a bound on a type or another lifetime.
Bound,
/// Appears as a generic argument.
match &typ.kind {
TyKind::Slice(ty) | TyKind::Paren(ty) => visitor.visit_ty(ty),
TyKind::Ptr(mutable_type) => visitor.visit_ty(&mutable_type.ty),
- TyKind::Rptr(opt_lifetime, mutable_type) => {
- walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Rptr);
+ TyKind::Ref(opt_lifetime, mutable_type) => {
+ walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref);
visitor.visit_ty(&mutable_type.ty)
}
TyKind::Tup(tuple_element_types) => {
Err(supported_abis) => {
let mut abis = format!("`{}`", supported_abis[0]);
for m in &supported_abis[1..] {
- let _ = write!(abis, ", `{}`", m);
+ let _ = write!(abis, ", `{m}`");
}
self.tcx.sess.emit_err(InvalidAbiClobberAbi {
abi_span: *abi_span,
let sub = if !valid_modifiers.is_empty() {
let mut mods = format!("`{}`", valid_modifiers[0]);
for m in &valid_modifiers[1..] {
- let _ = write!(mods, ", `{}`", m);
+ let _ = write!(mods, ", `{m}`");
}
InvalidAsmTemplateModifierRegClassSub::SupportModifier {
class_name: class.name(),
}
_ => {
// Replace the ident for bindings that aren't simple.
- let name = format!("__arg{}", index);
+ let name = format!("__arg{index}");
let ident = Ident::from_str(&name);
(ident, false)
param.id,
¶m.kind,
¶m.bounds,
+ param.colon_span,
+ generics.span,
itctx,
PredicateOrigin::GenericParam,
)
id: NodeId,
kind: &GenericParamKind,
bounds: &[GenericBound],
+ colon_span: Option<Span>,
+ parent_span: Span,
itctx: &ImplTraitContext,
origin: PredicateOrigin,
) -> Option<hir::WherePredicate<'hir>> {
let ident = self.lower_ident(ident);
let param_span = ident.span;
- let span = bounds
- .iter()
- .fold(Some(param_span.shrink_to_hi()), |span: Option<Span>, bound| {
- let bound_span = bound.span();
- // We include bounds that come from a `#[derive(_)]` but point at the user's code,
- // as we use this method to get a span appropriate for suggestions.
- if !bound_span.can_be_used_for_suggestions() {
- None
- } else if let Some(span) = span {
- Some(span.to(bound_span))
- } else {
- Some(bound_span)
- }
- })
- .unwrap_or(param_span.shrink_to_hi());
+
+ // Reconstruct the span of the entire predicate from the individual generic bounds.
+ let span_start = colon_span.unwrap_or_else(|| param_span.shrink_to_hi());
+ let span = bounds.iter().fold(span_start, |span_accum, bound| {
+ match bound.span().find_ancestor_inside(parent_span) {
+ Some(bound_span) => span_accum.to(bound_span),
+ None => span_accum,
+ }
+ });
+ let span = self.lower_span(span);
+
match kind {
GenericParamKind::Const { .. } => None,
GenericParamKind::Type { .. } => {
ImplTraitPosition::ImplReturn => "`impl` method return",
};
- write!(f, "{}", name)
+ write!(f, "{name}")
}
}
fn orig_local_def_id(&self, node: NodeId) -> LocalDefId {
self.orig_opt_local_def_id(node)
- .unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
+ .unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
}
/// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
}
fn local_def_id(&self, node: NodeId) -> LocalDefId {
- self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
+ self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
}
/// Get the previously recorded `to` local def id given the `from` local def id, obtained using
/// Intercept all spans entering HIR.
/// Mark a span as relative to the current owning item.
fn lower_span(&self, span: Span) -> Span {
- if self.tcx.sess.opts.unstable_opts.incremental_relative_spans {
+ if self.tcx.sess.opts.incremental_relative_spans() {
span.with_parent(Some(self.current_hir_id_owner.def_id))
} else {
// Do not make spans relative when not using incremental compilation.
TyKind::Err => hir::TyKind::Err,
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
- TyKind::Rptr(region, mt) => {
+ TyKind::Ref(region, mt) => {
let region = region.unwrap_or_else(|| {
let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
self.resolver.get_lifetime_res(t.id)
Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
});
let lifetime = self.lower_lifetime(®ion);
- hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
+ hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx))
}
TyKind::BareFn(f) => {
let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
// Given we are only considering `ImplicitSelf` types, we needn't consider
// the case where we have a mutable pattern to a reference as that would
// no longer be an `ImplicitSelf`.
- TyKind::Rptr(_, mt) if mt.ty.kind.is_implicit_self() => match mt.mutbl {
+ TyKind::Ref(_, mt) if mt.ty.kind.is_implicit_self() => match mt.mutbl {
hir::Mutability::Not => hir::ImplicitSelfKind::ImmRef,
hir::Mutability::Mut => hir::ImplicitSelfKind::MutRef,
},
fn lower_trait_ref(&mut self, p: &TraitRef, itctx: &ImplTraitContext) -> hir::TraitRef<'hir> {
let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
hir::QPath::Resolved(None, path) => path,
- qpath => panic!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
+ qpath => panic!("lower_trait_ref: unexpected QPath `{qpath:?}`"),
};
hir::TraitRef { path, hir_ref_id: self.lower_node_id(p.ref_id) }
}
) -> (hir::GenericParam<'hir>, Option<hir::WherePredicate<'hir>>, hir::TyKind<'hir>) {
// Add a definition for the in-band `Param`.
let def_id = self.local_def_id(node_id);
+ let span = self.lower_span(span);
// Set the name to `impl Bound1 + Bound2`.
let param = hir::GenericParam {
def_id,
name: ParamName::Plain(self.lower_ident(ident)),
pure_wrt_drop: false,
- span: self.lower_span(span),
+ span,
kind: hir::GenericParamKind::Type { default: None, synthetic: true },
colon_span: None,
};
node_id,
&GenericParamKind::Type { default: None },
bounds,
+ /* colon_span */ None,
+ span,
&ImplTraitContext::Universal,
hir::PredicateOrigin::ImplTrait,
);
let ty = hir::TyKind::Path(hir::QPath::Resolved(
None,
self.arena.alloc(hir::Path {
- span: self.lower_span(span),
+ span,
res,
segments:
arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
visit::walk_ty(self, t);
self.current_binders.pop();
}
- TyKind::Rptr(None, _) => {
+ TyKind::Ref(None, _) => {
self.record_elided_anchor(t.id, t.span);
visit::walk_ty(self, t);
}
data: Symbol,
) -> String {
match (comment_kind, attr_style) {
- (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{}", data),
- (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{}", data),
- (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{}*/", data),
- (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{}*/", data),
+ (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{data}"),
+ (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{data}"),
+ (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{data}*/"),
+ (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{data}*/"),
}
}
pub fn literal_to_string(lit: token::Lit) -> String {
let token::Lit { kind, symbol, suffix } = lit;
let mut out = match kind {
- token::Byte => format!("b'{}'", symbol),
- token::Char => format!("'{}'", symbol),
- token::Str => format!("\"{}\"", symbol),
+ token::Byte => format!("b'{symbol}'"),
+ token::Char => format!("'{symbol}'"),
+ token::Str => format!("\"{symbol}\""),
token::StrRaw(n) => {
format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
}
- token::ByteStr => format!("b\"{}\"", symbol),
+ token::ByteStr => format!("b\"{symbol}\""),
token::ByteStrRaw(n) => {
format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
}
self.word("*");
self.print_mt(mt, true);
}
- ast::TyKind::Rptr(lifetime, mt) => {
+ ast::TyKind::Ref(lifetime, mt) => {
self.word("&");
self.print_opt_lifetime(lifetime);
self.print_mt(mt, false);
ast::VisibilityKind::Restricted { path, shorthand, .. } => {
let path = Self::to_string(|s| s.print_path(path, false, 0));
if *shorthand && (path == "crate" || path == "self" || path == "super") {
- self.word_nbsp(format!("pub({})", path))
+ self.word_nbsp(format!("pub({path})"))
} else {
- self.word_nbsp(format!("pub(in {})", path))
+ self.word_nbsp(format!("pub(in {path})"))
}
}
ast::VisibilityKind::Inherited => {}
fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &Features) {
let (cfg, feature, has_feature) = gated_cfg;
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
- let explain = format!("`cfg({})` is experimental and subject to change", cfg);
+ let explain = format!("`cfg({cfg})` is experimental and subject to change");
feature_err(sess, *feature, cfg_span, &explain).emit();
}
}
}
pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
- assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {:?}", attr);
+ assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {attr:?}");
use ReprAttr::*;
let mut acc = Vec::new();
let diagnostic = &sess.parse_sess.span_diagnostic;
// Manual implementation to be able to format `expected` items correctly.
impl<'a> IntoDiagnostic<'a> for UnknownMetaItem<'_> {
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
- let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
+ let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
let mut diag = handler.struct_span_err_with_code(
self.span,
fluent::attr_unknown_meta_item,
place: &str,
borrow_place: &str,
value_place: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
self.infcx.tcx.sess.create_err(crate::session_diagnostics::MoveBorrow {
place,
span,
desc: &str,
borrow_span: Span,
borrow_desc: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
span,
old_loan_span: Span,
old_opt_via: &str,
old_load_end_span: Option<Span>,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let via =
|msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) };
let mut err = struct_span_err!(
desc: &str,
old_loan_span: Span,
old_load_end_span: Option<Span>,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
new_loan_span,
&self,
span: Span,
desc: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0594, "cannot assign to {}", desc)
}
span: Span,
path: &str,
reason: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,)
}
immutable_place: &str,
immutable_section: &str,
action: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
mutate_span,
&self,
span: Span,
yield_span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
span,
pub(crate) fn cannot_borrow_across_destructor(
&self,
borrow_span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(
self,
borrow_span,
&self,
span: Span,
path: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0597, "{} does not live long enough", path,)
}
return_kind: &str,
reference_desc: &str,
path_desc: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
span,
closure_kind: &str,
borrowed_path: &str,
capture_span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ scope: &str,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
closure_span,
E0373,
- "{} may outlive the current function, but it borrows {}, which is owned by the current \
- function",
- closure_kind,
- borrowed_path,
+ "{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \
+ which is owned by the current {scope}",
);
err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
.span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path));
pub(crate) fn thread_local_value_does_not_live_long_enough(
&self,
span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",)
}
pub(crate) fn temporary_value_borrowed_for_too_long(
&self,
span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",)
}
err.span_note(
MultiSpan::from_spans(reinit_spans),
&if reinits <= 3 {
- format!("these {} reinitializations might get skipped", reinits)
+ format!("these {reinits} reinitializations might get skipped")
} else {
format!(
"these 3 reinitializations and {} other{} might get skipped",
if !seen_spans.contains(&move_span) {
if !closure {
- self.suggest_ref_or_clone(mpi, move_span, &mut err, &mut in_pattern);
+ self.suggest_ref_or_clone(
+ mpi,
+ move_span,
+ &mut err,
+ &mut in_pattern,
+ move_spans,
+ );
}
self.explain_captures(
err.span_label(
span,
format!(
- "value {} here after {}move",
+ "value {} here after {partial_str}move",
desired_action.as_verb_in_past_tense(),
- partial_str
),
);
}
&format!(
"consider creating a fresh reborrow of {} here",
self.describe_place(moved_place)
- .map(|n| format!("`{}`", n))
+ .map(|n| format!("`{n}`"))
.unwrap_or_else(|| "the mutable reference".to_string()),
),
"&mut *",
DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
);
let note_msg = match opt_name {
- Some(name) => format!("`{}`", name),
+ Some(name) => format!("`{name}`"),
None => "value".to_owned(),
};
if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, ¬e_msg) {
} = use_spans
{
err.note(&format!(
- "{} occurs due to deref coercion to `{}`",
+ "{} occurs due to deref coercion to `{deref_target_ty}`",
desired_action.as_noun(),
- deref_target_ty
));
// Check first whether the source is accessible (issue #87060)
move_span: Span,
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
in_pattern: &mut bool,
+ move_spans: UseSpans<'_>,
) {
struct ExpressionFinder<'hir> {
expr_span: Span,
}
}
let typeck = self.infcx.tcx.typeck(self.mir_def_id());
- let hir_id = hir.get_parent_node(expr.hir_id);
+ let hir_id = hir.parent_id(expr.hir_id);
if let Some(parent) = hir.find(hir_id) {
let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
) = call_expr.kind
{
// Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
+ } else if let UseSpans::FnSelfUse {
+ kind: CallKind::Normal { .. },
+ ..
+ } = move_spans {
+ // We already suggest cloning for these cases in `explain_captures`.
} else {
self.suggest_cloning(err, ty, move_span);
}
// that are *partially* initialized by assigning to a field of an uninitialized
// binding. We differentiate between them for more accurate wording here.
"isn't fully initialized"
- } else if spans
- .iter()
- .filter(|i| {
- // We filter these to avoid misleading wording in cases like the following,
- // where `x` has an `init`, but it is in the same place we're looking at:
- // ```
- // let x;
- // x += 1;
- // ```
- !i.contains(span)
- // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`
- && !visitor
- .errors
- .iter()
- .map(|(sp, _)| *sp)
- .any(|sp| span < sp && !sp.contains(span))
- })
- .count()
- == 0
- {
+ } else if !spans.iter().any(|i| {
+ // We filter these to avoid misleading wording in cases like the following,
+ // where `x` has an `init`, but it is in the same place we're looking at:
+ // ```
+ // let x;
+ // x += 1;
+ // ```
+ !i.contains(span)
+ // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`
+ && !visitor
+ .errors
+ .iter()
+ .map(|(sp, _)| *sp)
+ .any(|sp| span < sp && !sp.contains(span))
+ }) {
show_assign_sugg = true;
"isn't initialized"
} else {
//
// then just use the normal error. The closure isn't escaping
// and `move` will not help here.
+ (
+ Some(name),
+ BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _),
+ ) => self.report_escaping_closure_capture(
+ borrow_spans,
+ borrow_span,
+ &RegionName {
+ name: self.synthesize_region_name(),
+ source: RegionNameSource::Static,
+ },
+ ConstraintCategory::CallArgument(None),
+ var_or_use_span,
+ &format!("`{}`", name),
+ "block",
+ ),
(
Some(name),
BorrowExplanation::MustBeValidFor {
category,
span,
&format!("`{}`", name),
+ "function",
),
(
name,
Some(err)
}
+ #[instrument(level = "debug", skip(self))]
fn report_escaping_closure_capture(
&mut self,
use_span: UseSpans<'tcx>,
category: ConstraintCategory<'tcx>,
constraint_span: Span,
captured_var: &str,
+ scope: &str,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
let tcx = self.infcx.tcx;
let args_span = use_span.args_or_use();
None => "closure",
};
- let mut err =
- self.cannot_capture_in_long_lived_closure(args_span, kind, captured_var, var_span);
+ let mut err = self.cannot_capture_in_long_lived_closure(
+ args_span,
+ kind,
+ captured_var,
+ var_span,
+ scope,
+ );
err.span_suggestion_verbose(
sugg_span,
&format!(
if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
err.note(
"async blocks are not executed immediately and must either take a \
- reference or ownership of outside variables they use",
+ reference or ownership of outside variables they use",
);
} else {
- let msg = format!("function requires argument type to outlive `{}`", fr_name);
+ let msg = format!("{scope} requires argument type to outlive `{fr_name}`");
err.span_note(constraint_span, &msg);
}
}
// Need to use the `rustc_middle::ty` types to compare against the
// `return_region`. Then use the `rustc_hir` type to get only
// the lifetime span.
- if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind {
+ if let hir::TyKind::Ref(lifetime, _) = &fn_decl.inputs[index].kind {
// With access to the lifetime, we can get
// the span of it.
arguments.push((*argument, lifetime.ident.span));
let return_ty = sig.output().skip_binder();
let mut return_span = fn_decl.output.span();
if let hir::FnRetTy::Return(ty) = &fn_decl.output {
- if let hir::TyKind::Rptr(lifetime, _) = ty.kind {
+ if let hir::TyKind::Ref(lifetime, _) = ty.kind {
return_span = lifetime.ident.span;
}
}
if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) {
err.span_label(
var_or_use_span,
- format!("{}borrow later {}", borrow_desc, message),
+ format!("{borrow_desc}borrow later {message}"),
);
}
} else {
let capture_kind_label = message;
err.span_label(
var_or_use_span,
- format!("{}borrow later {}", borrow_desc, capture_kind_label),
+ format!("{borrow_desc}borrow later {capture_kind_label}"),
);
err.span_label(path_span, path_label);
}
};
// We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) {
- err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message));
+ err.span_label(var_or_use_span, format!("{borrow_desc}{message}"));
} else {
// path_span must be `Some` as otherwise the if condition is true
let path_span = path_span.unwrap();
let capture_kind_label = message;
err.span_label(
var_or_use_span,
- format!("{}borrow later {}", borrow_desc, capture_kind_label),
+ format!("{borrow_desc}borrow later {capture_kind_label}"),
);
err.span_label(path_span, path_label);
}
match local_names[dropped_local] {
Some(local_name) if !local_decl.from_compiler_desugaring() => {
let message = format!(
- "{B}borrow might be used here, when `{LOC}` is dropped \
- and runs the {DTOR} for {TYPE}",
- B = borrow_desc,
- LOC = local_name,
- TYPE = type_desc,
- DTOR = dtor_desc
+ "{borrow_desc}borrow might be used here, when `{local_name}` is dropped \
+ and runs the {dtor_desc} for {type_desc}",
);
err.span_label(body.source_info(drop_loc).span, message);
err.span_label(
local_decl.source_info.span,
format!(
- "a temporary with access to the {B}borrow \
+ "a temporary with access to the {borrow_desc}borrow \
is created here ...",
- B = borrow_desc
),
);
let message = format!(
- "... and the {B}borrow might be used here, \
+ "... and the {borrow_desc}borrow might be used here, \
when that temporary is dropped \
- and runs the {DTOR} for {TYPE}",
- B = borrow_desc,
- TYPE = type_desc,
- DTOR = dtor_desc
+ and runs the {dtor_desc} for {type_desc}",
);
err.span_label(body.source_info(drop_loc).span, message);
err.span_label(
span,
format!(
- "{}requires that `{}` is borrowed for `{}`",
+ "{}requires that `{desc}` is borrowed for `{region_name}`",
category.description(),
- desc,
- region_name,
),
);
} else {
err.span_label(
span,
format!(
- "{}requires that {}borrow lasts for `{}`",
+ "{}requires that {borrow_desc}borrow lasts for `{region_name}`",
category.description(),
- borrow_desc,
- region_name,
),
);
};
if region_name.was_named() { region_name.name } else { kw::UnderscoreLifetime };
let msg = format!(
- "you can add a bound to the {}to make it last less than `'static` and match `{}`",
+ "you can add a bound to the {}to make it last less than `'static` and match `{region_name}`",
category.description(),
- region_name,
);
err.span_suggestion_verbose(
span.shrink_to_hi(),
&msg,
- format!(" + {}", suggestable_name),
+ format!(" + {suggestable_name}"),
Applicability::Unspecified,
);
}
/// First span returned points to the location of the conflicting use
/// Second span if `Some` is returned in the case of closures and points
/// to the use of the path
+ #[instrument(level = "debug", skip(self))]
fn later_use_kind(
&self,
borrow: &BorrowData<'tcx>,
let block = &self.body.basic_blocks[location.block];
let kind = if let Some(&Statement {
- kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)),
+ kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), place)),
..
}) = block.statements.get(location.statement_index)
{
- LaterUseKind::FakeLetRead
+ if let Some(l) = place.as_local()
+ && let local_decl = &self.body.local_decls[l]
+ && local_decl.ty.is_closure()
+ {
+ LaterUseKind::ClosureCapture
+ } else {
+ LaterUseKind::FakeLetRead
+ }
} else if self.was_captured_by_trait_object(borrow) {
LaterUseKind::TraitCapture
} else if location.statement_index == block.statements.len() {
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::GeneratorKind;
-use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{LateBoundRegionConversionTime, TyCtxtInferExt};
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{
AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
use rustc_span::def_id::LocalDefId;
use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
use rustc_target::abi::VariantIdx;
-use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::{
+ type_known_to_meet_bound_modulo_regions, Obligation, ObligationCause,
+};
use super::borrow_set::BorrowData;
use super::MirBorrowckCtxt;
move_prefix: &str,
) {
let message = format!(
- "{}move occurs because {} has type `{}`, which does not implement the `Copy` trait",
- move_prefix, place_desc, ty,
+ "{move_prefix}move occurs because {place_desc} has type `{ty}`, which does not implement the `Copy` trait",
);
if let Some(span) = span {
err.span_label(span, message);
BorrowedContentSource::OverloadedDeref(ty) => ty
.ty_adt_def()
.and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
- name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
+ name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),
_ => None,
})
- .unwrap_or_else(|| format!("dereference of `{}`", ty)),
- BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
+ .unwrap_or_else(|| format!("dereference of `{ty}`")),
+ BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{ty}`"),
}
}
BorrowedContentSource::OverloadedDeref(ty) => ty
.ty_adt_def()
.and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
- name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
+ name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),
_ => None,
})
- .unwrap_or_else(|| format!("dereference of `{}`", ty)),
- BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
+ .unwrap_or_else(|| format!("dereference of `{ty}`")),
+ BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{ty}`"),
}
}
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
let place_name = self
.describe_place(moved_place.as_ref())
- .map(|n| format!("`{}`", n))
+ .map(|n| format!("`{n}`"))
.unwrap_or_else(|| "value".to_owned());
match kind {
CallKind::FnCall { fn_trait_id, .. }
err.span_label(
fn_call_span,
&format!(
- "{} {}moved due to this call{}",
- place_name, partially_str, loop_message
+ "{place_name} {partially_str}moved due to this call{loop_message}",
),
);
err.span_note(
err.span_label(
fn_call_span,
&format!(
- "{} {}moved due to usage in operator{}",
- place_name, partially_str, loop_message
+ "{place_name} {partially_str}moved due to usage in operator{loop_message}",
),
);
if self.fn_self_span_reported.insert(fn_span) {
}
CallKind::Normal { self_arg, desugaring, method_did } => {
let self_arg = self_arg.unwrap();
+ let tcx = self.infcx.tcx;
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
- let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
- let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
+ let ty = moved_place.ty(self.body, tcx).ty;
+ let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
Some(def_id) => {
let infcx = self.infcx.tcx.infer_ctxt().build();
type_known_to_meet_bound_modulo_regions(
&infcx,
self.param_env,
- infcx.tcx.mk_imm_ref(
- infcx.tcx.lifetimes.re_erased,
- infcx.tcx.erase_regions(ty),
- ),
+ tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)),
def_id,
DUMMY_SP,
)
err.span_suggestion_verbose(
move_span.shrink_to_lo(),
&format!(
- "consider iterating over a slice of the `{}`'s content to \
+ "consider iterating over a slice of the `{ty}`'s content to \
avoid moving into the `for` loop",
- ty,
),
"&",
Applicability::MaybeIncorrect,
err.span_label(
fn_call_span,
&format!(
- "{} {}moved due to this implicit call to `.into_iter()`{}",
- place_name, partially_str, loop_message
+ "{place_name} {partially_str}moved due to this implicit call to `.into_iter()`{loop_message}",
),
);
// If the moved place was a `&mut` ref, then we can
&format!(
"consider creating a fresh reborrow of {} here",
self.describe_place(moved_place.as_ref())
- .map(|n| format!("`{}`", n))
+ .map(|n| format!("`{n}`"))
.unwrap_or_else(|| "the mutable reference".to_string()),
),
"&mut *",
err.span_label(
fn_call_span,
&format!(
- "{} {}moved due to this method call{}",
- place_name, partially_str, loop_message
+ "{place_name} {partially_str}moved due to this method call{loop_message}",
),
);
+ let infcx = tcx.infer_ctxt().build();
+ let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
+ if let ty::Adt(def, substs) = ty.kind()
+ && Some(def.did()) == tcx.lang_items().pin_type()
+ && let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
+ && let self_ty = infcx.replace_bound_vars_with_fresh_vars(
+ fn_call_span,
+ LateBoundRegionConversionTime::FnCall,
+ tcx.fn_sig(method_did).input(0),
+ )
+ && infcx.can_eq(self.param_env, ty, self_ty).is_ok()
+ {
+ err.span_suggestion_verbose(
+ fn_call_span.shrink_to_lo(),
+ "consider reborrowing the `Pin` instead of moving it",
+ "as_mut().".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ if let Some(clone_trait) = tcx.lang_items().clone_trait()
+ && let trait_ref = tcx.mk_trait_ref(clone_trait, [ty])
+ && let o = Obligation::new(
+ tcx,
+ ObligationCause::dummy(),
+ self.param_env,
+ ty::Binder::dummy(trait_ref),
+ )
+ && infcx.predicate_must_hold_modulo_regions(&o)
+ {
+ err.span_suggestion_verbose(
+ fn_call_span.shrink_to_lo(),
+ "you can `clone` the value and consume it, but this might not be \
+ your desired behavior",
+ "clone().".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
}
- let tcx = self.infcx.tcx;
// Avoid pointing to the same function in multiple different
// error messages.
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
if move_span != span || !loop_message.is_empty() {
err.span_label(
move_span,
- format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
+ format!("value {partially_str}moved{move_msg} here{loop_message}"),
);
}
// If the move error occurs due to a loop, don't show
if loop_message.is_empty() {
move_spans.var_span_label(
err,
- format!("variable {}moved due to use{}", partially_str, move_spans.describe()),
+ format!("variable {partially_str}moved due to use{}", move_spans.describe()),
"moved",
);
}
// the verbs used in some diagnostic messages.
let act;
let acted_on;
+ let mut suggest = true;
+ let mut mut_error = None;
+ let mut count = 1;
let span = match error_access {
AccessKind::Mutate => {
let borrow_spans = self.borrow_spans(span, location);
let borrow_span = borrow_spans.args_or_use();
- err = self.cannot_borrow_path_as_mutable_because(borrow_span, &item_msg, &reason);
- borrow_spans.var_span_label(
- &mut err,
- format!(
- "mutable borrow occurs due to use of {} in closure",
- self.describe_any_place(access_place.as_ref()),
- ),
- "mutable",
- );
+ match the_place_err {
+ PlaceRef { local, projection: [] }
+ if self.body.local_decls[local].can_be_made_mutable() =>
+ {
+ let span = self.body.local_decls[local].source_info.span;
+ mut_error = Some(span);
+ if let Some((buffer, c)) = self.get_buffered_mut_error(span) {
+ // We've encountered a second (or more) attempt to mutably borrow an
+ // immutable binding, so the likely problem is with the binding
+ // declaration, not the use. We collect these in a single diagnostic
+ // and make the binding the primary span of the error.
+ err = buffer;
+ count = c + 1;
+ if count == 2 {
+ err.replace_span_with(span, false);
+ err.span_label(span, "not mutable");
+ }
+ suggest = false;
+ } else {
+ err = self.cannot_borrow_path_as_mutable_because(
+ borrow_span,
+ &item_msg,
+ &reason,
+ );
+ }
+ }
+ _ => {
+ err = self.cannot_borrow_path_as_mutable_because(
+ borrow_span,
+ &item_msg,
+ &reason,
+ );
+ }
+ }
+ if suggest {
+ borrow_spans.var_span_label(
+ &mut err,
+ format!(
+ "mutable borrow occurs due to use of {} in closure",
+ self.describe_any_place(access_place.as_ref()),
+ ),
+ "mutable",
+ );
+ }
borrow_span
}
};
ProjectionElem::Deref,
],
} => {
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
if let Some(span) = get_mut_span_in_struct_field(
self.infcx.tcx,
.unwrap_or(false) =>
{
let decl = &self.body.local_decls[local];
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
if let Some(mir::Statement {
source_info,
kind:
pat_span: _,
},
)))) => {
- err.span_note(sp, "the binding is already a mutable borrow");
+ if suggest {
+ err.span_note(sp, "the binding is already a mutable borrow");
+ }
}
_ => {
err.span_note(
} else {
err.span_help(source_info.span, "try removing `&mut` here");
}
- } else if decl.mutability == Mutability::Not
- && !matches!(
+ } else if decl.mutability == Mutability::Not {
+ if matches!(
decl.local_info,
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
hir::ImplicitSelfKind::MutRef
- ))))
- )
- {
- err.span_suggestion_verbose(
- decl.source_info.span.shrink_to_lo(),
- "consider making the binding mutable",
- "mut ",
- Applicability::MachineApplicable,
- );
+ ),)))
+ ) {
+ err.note(
+ "as `Self` may be unsized, this call attempts to take `&mut &mut self`",
+ );
+ err.note("however, `&mut self` expands to `self: &mut Self`, therefore `self` cannot be borrowed mutably");
+ } else {
+ err.span_suggestion_verbose(
+ decl.source_info.span.shrink_to_lo(),
+ "consider making the binding mutable",
+ "mut ",
+ Applicability::MachineApplicable,
+ );
+ };
}
}
let local_decl = &self.body.local_decls[local];
assert_eq!(local_decl.mutability, Mutability::Not);
- err.span_label(span, format!("cannot {ACT}", ACT = act));
- err.span_suggestion(
- local_decl.source_info.span,
- "consider changing this to be mutable",
- format!("mut {}", self.local_names[local].unwrap()),
- Applicability::MachineApplicable,
- );
- let tcx = self.infcx.tcx;
- if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
- self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+ if count < 10 {
+ err.span_label(span, format!("cannot {act}"));
+ }
+ if suggest {
+ err.span_suggestion_verbose(
+ local_decl.source_info.span.shrink_to_lo(),
+ "consider changing this to be mutable",
+ "mut ".to_string(),
+ Applicability::MachineApplicable,
+ );
+ let tcx = self.infcx.tcx;
+ if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
+ self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+ }
}
}
let captured_place = &self.upvars[upvar_index.index()].place;
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
let upvar_hir_id = captured_place.get_root_variable();
.span_to_snippet(span)
.map_or(false, |snippet| snippet.starts_with("&mut ")) =>
{
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
err.span_suggestion(
span,
"try removing `&mut` here",
PlaceRef { local, projection: [ProjectionElem::Deref] }
if self.body.local_decls[local].is_ref_for_guard() =>
{
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
err.note(
"variables bound in patterns are immutable until the end of the pattern guard",
);
Some((true, err_help_span, suggested_code)) => {
let (is_trait_sig, local_trait) = self.is_error_in_trait(local);
if !is_trait_sig {
- err.span_suggestion(
+ err.span_suggestion_verbose(
err_help_span,
&format!(
"consider changing this to be a mutable {pointer_desc}"
Applicability::MachineApplicable,
);
} else if let Some(x) = local_trait {
- err.span_suggestion(
+ err.span_suggestion_verbose(
x,
&format!(
"consider changing that to be a mutable {pointer_desc}"
err.span_label(
span,
format!(
- "`{NAME}` is a `{SIGIL}` {DESC}, \
- so the data it refers to cannot be {ACTED_ON}",
- NAME = name,
- SIGIL = pointer_sigil,
- DESC = pointer_desc,
- ACTED_ON = acted_on
+ "`{name}` is a `{pointer_sigil}` {pointer_desc}, \
+ so the data it refers to cannot be {acted_on}",
),
);
}
_ => {
err.span_label(
span,
- format!(
- "cannot {ACT} through `{SIGIL}` {DESC}",
- ACT = act,
- SIGIL = pointer_sigil,
- DESC = pointer_desc
- ),
+ format!("cannot {act} through `{pointer_sigil}` {pointer_desc}"),
);
}
}
}
PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => {
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
match opt_source {
Some(BorrowedContentSource::OverloadedDeref(ty)) => {
err.help(&format!(
"trait `DerefMut` is required to modify through a dereference, \
- but it is not implemented for `{ty}`",
+ but it is not implemented for `{ty}`",
));
}
Some(BorrowedContentSource::OverloadedIndex(ty)) => {
err.help(&format!(
"trait `IndexMut` is required to modify indexed content, \
- but it is not implemented for `{ty}`",
+ but it is not implemented for `{ty}`",
));
self.suggest_map_index_mut_alternatives(ty, &mut err, span);
}
}
_ => {
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
}
}
- self.buffer_error(err);
+ if let Some(span) = mut_error {
+ self.buffer_mut_error(span, err, count);
+ } else {
+ self.buffer_error(err);
+ }
}
fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) {
let hir = self.infcx.tcx.hir();
let closure_id = self.mir_hir_id();
let closure_span = self.infcx.tcx.def_span(self.mir_def_id());
- let fn_call_id = hir.get_parent_node(closure_id);
+ let fn_call_id = hir.parent_id(closure_id);
let node = hir.get(fn_call_id);
let def_id = hir.enclosing_body_owner(fn_call_id);
let mut look_at_return = true;
{
let lt_name = &src[1..ws_pos];
let ty = &src[ws_pos..];
- return (true, highlight_span, format!("&{} mut{}", lt_name, ty));
+ return (true, highlight_span, format!("&{lt_name} mut{ty}"));
}
let ty_mut = local_decl.ty.builtin_deref(true).unwrap();
// Now we're dealing with the actual struct that we're going to suggest a change to,
// we can expect a field that is an immutable reference to a type.
&& let hir::Node::Field(field) = node
- && let hir::TyKind::Rptr(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
+ && let hir::TyKind::Ref(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
{
return Some(lt.ident.span.between(ty.span));
}
let mut diag = if suggested.len() == 1 {
mbcx.infcx.tcx.sess.diagnostic().struct_help(&match suggested.last().unwrap() {
SuggestedConstraint::Outlives(a, bs) => {
- let bs: SmallVec<[String; 2]> = bs.iter().map(|r| format!("{}", r)).collect();
- format!("add bound `{}: {}`", a, bs.join(" + "))
+ let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
+ format!("add bound `{a}: {}`", bs.join(" + "))
}
SuggestedConstraint::Equal(a, b) => {
- format!("`{}` and `{}` must be the same: replace one with the other", a, b)
+ format!("`{a}` and `{b}` must be the same: replace one with the other")
}
- SuggestedConstraint::Static(a) => format!("replace `{}` with `'static`", a),
+ SuggestedConstraint::Static(a) => format!("replace `{a}` with `'static`"),
})
} else {
// Create a new diagnostic.
for constraint in suggested {
match constraint {
SuggestedConstraint::Outlives(a, bs) => {
- let bs: SmallVec<[String; 2]> =
- bs.iter().map(|r| format!("{}", r)).collect();
- diag.help(&format!("add bound `{}: {}`", a, bs.join(" + ")));
+ let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
+ diag.help(&format!("add bound `{a}: {}`", bs.join(" + ")));
}
SuggestedConstraint::Equal(a, b) => {
diag.help(&format!(
- "`{}` and `{}` must be the same: replace one with the other",
- a, b
+ "`{a}` and `{b}` must be the same: replace one with the other",
));
}
SuggestedConstraint::Static(a) => {
- diag.help(&format!("replace `{}` with `'static`", a));
+ diag.help(&format!("replace `{a}` with `'static`"));
}
}
}
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
+use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
-use rustc_hir::{self as hir, Item, ItemKind, Node};
use rustc_infer::infer::{
error_reporting::nice_region_error::{
self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
// buffered in the `MirBorrowckCtxt`.
let mut outlives_suggestion = OutlivesSuggestionBuilder::default();
+ let mut last_unexpected_hidden_region: Option<(Span, Ty<'_>, ty::OpaqueTypeKey<'tcx>)> =
+ None;
for nll_error in nll_errors.into_iter() {
match nll_error {
let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
let named_key = self.regioncx.name_regions(self.infcx.tcx, key);
let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
- self.buffer_error(unexpected_hidden_region_diagnostic(
+ let mut diag = unexpected_hidden_region_diagnostic(
self.infcx.tcx,
span,
named_ty,
named_region,
named_key,
- ));
+ );
+ if last_unexpected_hidden_region != Some((span, named_ty, named_key)) {
+ self.buffer_error(diag);
+ last_unexpected_hidden_region = Some((span, named_ty, named_key));
+ } else {
+ diag.delay_as_bug();
+ }
}
RegionErrorKind::BoundUniversalRegionError {
outlives_suggestion.add_suggestion(self);
}
- fn get_impl_ident_and_self_ty_from_trait(
- &self,
- def_id: DefId,
- trait_objects: &FxIndexSet<DefId>,
- ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
- let tcx = self.infcx.tcx;
- match tcx.hir().get_if_local(def_id) {
- Some(Node::ImplItem(impl_item)) => {
- match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
- {
- Some(Node::Item(Item {
- kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
- ..
- })) => Some((impl_item.ident, self_ty)),
- _ => None,
- }
- }
- Some(Node::TraitItem(trait_item)) => {
- let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
- match tcx.hir().find_by_def_id(trait_did.def_id) {
- Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
- // The method being called is defined in the `trait`, but the `'static`
- // obligation comes from the `impl`. Find that `impl` so that we can point
- // at it in the suggestion.
- let trait_did = trait_did.to_def_id();
- match tcx
- .hir()
- .trait_impls(trait_did)
- .iter()
- .filter_map(|&impl_did| {
- match tcx.hir().get_if_local(impl_did.to_def_id()) {
- Some(Node::Item(Item {
- kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
- ..
- })) if trait_objects.iter().all(|did| {
- // FIXME: we should check `self_ty` against the receiver
- // type in the `UnifyReceiver` context, but for now, use
- // this imperfect proxy. This will fail if there are
- // multiple `impl`s for the same trait like
- // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
- // In that case, only the first one will get suggestions.
- let mut traits = vec![];
- let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
- hir_v.visit_ty(self_ty);
- !traits.is_empty()
- }) =>
- {
- Some(self_ty)
- }
- _ => None,
- }
- })
- .next()
- {
- Some(self_ty) => Some((trait_item.ident, self_ty)),
- _ => None,
- }
- }
- _ => None,
- }
- }
- _ => None,
- }
- }
-
/// Report an error because the universal region `fr` was required to outlive
/// `outlived_fr` but it is not known to do so. For example:
///
);
(desc, note)
}
- _ => panic!("Unexpected type {:?}", ty),
+ _ => panic!("Unexpected type {ty:?}"),
};
diag.note(&format!("requirement occurs because of {desc}",));
diag.note(¬e);
let lifetime = if f.has_name() { fr_name.name } else { kw::UnderscoreLifetime };
let arg = match param.param.pat.simple_ident() {
- Some(simple_ident) => format!("argument `{}`", simple_ident),
+ Some(simple_ident) => format!("argument `{simple_ident}`"),
None => "the argument".to_string(),
};
- let captures = format!("captures data from {}", arg);
+ let captures = format!("captures data from {arg}");
return nice_region_error::suggest_new_region_bound(
self.infcx.tcx,
Some(arg),
captures,
Some((param.param_ty_span, param.param_ty.to_string())),
+ self.infcx.tcx.is_suitable_region(f).map(|r| r.def_id),
);
}
}
visitor.visit_ty(param.param_ty);
let Some((ident, self_ty)) =
- self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &visitor.0) else {return};
+ NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &visitor.0) else { return; };
self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
}
/// increment the counter.
///
/// This is _not_ idempotent. Call `give_region_a_name` when possible.
- fn synthesize_region_name(&self) -> Symbol {
+ pub(crate) fn synthesize_region_name(&self) -> Symbol {
let c = self.next_region_name.replace_with(|counter| *counter + 1);
- Symbol::intern(&format!("'{:?}", c))
+ Symbol::intern(&format!("'{c:?}"))
}
/// Maps from an internal MIR region vid to something that we can
//
// &
// - let's call the lifetime of this reference `'1`
- (
- ty::Ref(region, referent_ty, _),
- hir::TyKind::Rptr(_lifetime, referent_hir_ty),
- ) => {
+ (ty::Ref(region, referent_ty, _), hir::TyKind::Ref(_lifetime, referent_hir_ty)) => {
if region.to_region_vid() == needle_fr {
// Just grab the first character, the `&`.
let source_map = self.infcx.tcx.sess.source_map();
// programs, so we need to use delay_span_bug here. See #82126.
self.infcx.tcx.sess.delay_span_bug(
hir_arg.span(),
- &format!("unmatched subst and hir arg: found {:?} vs {:?}", kind, hir_arg),
+ &format!("unmatched subst and hir arg: found {kind:?} vs {hir_arg:?}"),
);
}
}
} else {
span_bug!(
hir_ty.span,
- "bounds from lowered return type of async fn did not match expected format: {:?}",
- opaque_ty
+ "bounds from lowered return type of async fn did not match expected format: {opaque_ty:?}",
);
}
}
upvars: &[Upvar<'tcx>],
fr: RegionVid,
) -> Option<(Option<Symbol>, Span)> {
- debug!("get_var_name_and_span_for_region(fr={:?})", fr);
+ debug!("get_var_name_and_span_for_region(fr={fr:?})");
assert!(self.universal_regions().is_universal_region(fr));
debug!("get_var_name_and_span_for_region: attempting upvar");
) -> Option<usize> {
let upvar_index =
self.universal_regions().defining_ty.upvar_tys().position(|upvar_ty| {
- debug!("get_upvar_index_for_region: upvar_ty={:?}", upvar_ty);
+ debug!("get_upvar_index_for_region: upvar_ty={upvar_ty:?}");
tcx.any_free_region_meets(&upvar_ty, |r| {
let r = r.to_region_vid();
- debug!("get_upvar_index_for_region: r={:?} fr={:?}", r, fr);
+ debug!("get_upvar_index_for_region: r={r:?} fr={fr:?}");
r == fr
})
})?;
let upvar_ty = self.universal_regions().defining_ty.upvar_tys().nth(upvar_index);
debug!(
- "get_upvar_index_for_region: found {:?} in upvar {} which has type {:?}",
- fr, upvar_index, upvar_ty,
+ "get_upvar_index_for_region: found {fr:?} in upvar {upvar_index} which has type {upvar_ty:?}",
);
Some(upvar_index)
upvar_index: usize,
) -> (Symbol, Span) {
let upvar_hir_id = upvars[upvar_index].place.get_root_variable();
- debug!("get_upvar_name_and_span_for_region: upvar_hir_id={:?}", upvar_hir_id);
+ debug!("get_upvar_name_and_span_for_region: upvar_hir_id={upvar_hir_id:?}");
let upvar_name = tcx.hir().name(upvar_hir_id);
let upvar_span = tcx.hir().span(upvar_hir_id);
debug!(
- "get_upvar_name_and_span_for_region: upvar_name={:?} upvar_span={:?}",
- upvar_name, upvar_span
+ "get_upvar_name_and_span_for_region: upvar_name={upvar_name:?} upvar_span={upvar_span:?}",
);
(upvar_name, upvar_span)
let argument_index =
self.universal_regions().unnormalized_input_tys.iter().skip(implicit_inputs).position(
|arg_ty| {
- debug!("get_argument_index_for_region: arg_ty = {:?}", arg_ty);
+ debug!("get_argument_index_for_region: arg_ty = {arg_ty:?}");
tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr)
},
)?;
debug!(
- "get_argument_index_for_region: found {:?} in argument {} which has type {:?}",
- fr,
- argument_index,
+ "get_argument_index_for_region: found {fr:?} in argument {argument_index} which has type {:?}",
self.universal_regions().unnormalized_input_tys[argument_index],
);
) -> (Option<Symbol>, Span) {
let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs();
let argument_local = Local::new(implicit_inputs + argument_index + 1);
- debug!("get_argument_name_and_span_for_region: argument_local={:?}", argument_local);
+ debug!("get_argument_name_and_span_for_region: argument_local={argument_local:?}");
let argument_name = local_names[argument_local];
let argument_span = body.local_decls[argument_local].source_info.span;
debug!(
- "get_argument_name_and_span_for_region: argument_name={:?} argument_span={:?}",
- argument_name, argument_span
+ "get_argument_name_and_span_for_region: argument_name={argument_name:?} argument_span={argument_span:?}",
);
(argument_name, argument_span)
) -> Result<(), Box<dyn Error>> {
for (index, c) in columns.iter().enumerate() {
let tail = if index == columns.len() - 1 { "\n" } else { "\t" };
- write!(out, "{:?}{}", c.to_string(location_table), tail)?;
+ write!(out, "{:?}{tail}", c.to_string(location_table))?;
}
Ok(())
}
/// local place can be mutated.
//
// FIXME: @nikomatsakis suggested that this flag could be removed with the following modifications:
-// - Merge `check_access_permissions()` and `check_if_reassignment_to_immutable_state()`.
// - Split `is_mutable()` into `is_assignable()` (can be directly assigned) and
// `is_declared_mutable()`.
// - Take flow state into consideration in `is_assignable()` for local variables.
// Write of P[i] or *P requires P init'd.
self.check_if_assigned_path_is_moved(location, place_span, flow_state);
- // Special case: you can assign an immutable local variable
- // (e.g., `x = ...`) so long as it has never been initialized
- // before (at this point in the flow).
- if let Some(local) = place_span.0.as_local() {
- if let Mutability::Not = self.body.local_decls[local].mutability {
- // check for reassignments to immutable local variables
- self.check_if_reassignment_to_immutable_state(
- location, local, place_span, flow_state,
- );
- return;
- }
- }
-
- // Otherwise, use the normal access permission rules.
self.access_place(
location,
place_span,
}
}
- fn check_if_reassignment_to_immutable_state(
- &mut self,
- location: Location,
- local: Local,
- place_span: (Place<'tcx>, Span),
- flow_state: &Flows<'cx, 'tcx>,
- ) {
- debug!("check_if_reassignment_to_immutable_state({:?})", local);
-
- // Check if any of the initializations of `local` have happened yet:
- if let Some(init_index) = self.is_local_ever_initialized(local, flow_state) {
- // And, if so, report an error.
- let init = &self.move_data.inits[init_index];
- let span = init.span(&self.body);
- self.report_illegal_reassignment(location, place_span, span, place_span.0);
- }
- }
-
fn check_if_full_path_is_moved(
&mut self,
location: Location,
// partial initialization, do not complain about mutability
// errors except for actual mutation (as opposed to an attempt
// to do a partial initialization).
- let previously_initialized =
- self.is_local_ever_initialized(place.local, flow_state).is_some();
+ let previously_initialized = self.is_local_ever_initialized(place.local, flow_state);
// at this point, we have set up the error reporting state.
- if previously_initialized {
- self.report_mutability_error(place, span, the_place_err, error_access, location);
+ if let Some(init_index) = previously_initialized {
+ if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) {
+ // If this is a mutate access to an immutable local variable with no projections
+ // report the error as an illegal reassignment
+ let init = &self.move_data.inits[init_index];
+ let assigned_span = init.span(&self.body);
+ self.report_illegal_reassignment(location, (place, span), assigned_span, place);
+ } else {
+ self.report_mutability_error(place, span, the_place_err, error_access, location)
+ }
true
} else {
false
/// same primary span come out in a consistent order.
buffered_move_errors:
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>)>,
+ buffered_mut_errors: FxHashMap<Span, (DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)>,
/// Diagnostics to be reported buffer.
buffered: Vec<Diagnostic>,
/// Set to Some if we emit an error during borrowck
BorrowckErrors {
tcx,
buffered_move_errors: BTreeMap::new(),
+ buffered_mut_errors: Default::default(),
buffered: Default::default(),
tainted_by_errors: None,
}
}
}
+ pub fn get_buffered_mut_error(
+ &mut self,
+ span: Span,
+ ) -> Option<(DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)> {
+ self.errors.buffered_mut_errors.remove(&span)
+ }
+
+ pub fn buffer_mut_error(
+ &mut self,
+ span: Span,
+ t: DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ count: usize,
+ ) {
+ self.errors.buffered_mut_errors.insert(span, (t, count));
+ }
+
pub fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
// Buffer any move errors that we collected and de-duplicated.
for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
// We have already set tainted for this error, so just buffer it.
diag.buffer(&mut self.errors.buffered);
}
+ for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
+ if count > 10 {
+ diag.note(&format!("...and {} other attempted mutable borrows", count - 10));
+ }
+ diag.buffer(&mut self.errors.buffered);
+ }
if !self.errors.buffered.is_empty() {
self.errors.buffered.sort_by_key(|diag| diag.sort_span);
use std::fmt;
-use rustc_infer::infer::canonical::Canonical;
-use rustc_infer::traits::query::NoSolution;
+use rustc_infer::infer::{canonical::Canonical, InferOk};
use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::{self, ToPredicate, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
use rustc_span::def_id::DefId;
use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
-use rustc_trait_selection::traits::query::Fallible;
+use rustc_trait_selection::traits::query::{Fallible, NoSolution};
+use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
use crate::diagnostics::{ToUniverseInfo, UniverseInfo};
value
})
}
+
+ #[instrument(skip(self), level = "debug")]
+ pub(super) fn ascribe_user_type(
+ &mut self,
+ mir_ty: Ty<'tcx>,
+ user_ty: ty::UserType<'tcx>,
+ span: Span,
+ ) {
+ // FIXME: Ideally MIR types are normalized, but this is not always true.
+ let mir_ty = self.normalize(mir_ty, Locations::All(span));
+
+ self.fully_perform_op(
+ Locations::All(span),
+ ConstraintCategory::Boring,
+ self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty, user_ty)),
+ )
+ .unwrap_or_else(|err| {
+ span_mirbug!(
+ self,
+ span,
+ "ascribe_user_type `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
+ );
+ });
+ }
+
+ /// *Incorrectly* skips the WF checks we normally do in `ascribe_user_type`.
+ ///
+ /// FIXME(#104478, #104477): This is a hack for backward-compatibility.
+ #[instrument(skip(self), level = "debug")]
+ pub(super) fn ascribe_user_type_skip_wf(
+ &mut self,
+ mir_ty: Ty<'tcx>,
+ user_ty: ty::UserType<'tcx>,
+ span: Span,
+ ) {
+ let ty::UserType::Ty(user_ty) = user_ty else { bug!() };
+
+ // A fast path for a common case with closure input/output types.
+ if let ty::Infer(_) = user_ty.kind() {
+ self.eq_types(user_ty, mir_ty, Locations::All(span), ConstraintCategory::Boring)
+ .unwrap();
+ return;
+ }
+
+ let mir_ty = self.normalize(mir_ty, Locations::All(span));
+ let cause = ObligationCause::dummy_with_span(span);
+ let param_env = self.param_env;
+ let op = |infcx: &'_ _| {
+ let ocx = ObligationCtxt::new_in_snapshot(infcx);
+ let user_ty = ocx.normalize(&cause, param_env, user_ty);
+ ocx.eq(&cause, param_env, user_ty, mir_ty)?;
+ if !ocx.select_all_or_error().is_empty() {
+ return Err(NoSolution);
+ }
+ Ok(InferOk { value: (), obligations: vec![] })
+ };
+
+ self.fully_perform_op(
+ Locations::All(span),
+ ConstraintCategory::Boring,
+ type_op::custom::CustomTypeOp::new(op, || "ascribe_user_type_skip_wf".to_string()),
+ )
+ .unwrap_or_else(|err| {
+ span_mirbug!(
+ self,
+ span,
+ "ascribe_user_type_skip_wf `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
+ );
+ });
+ }
}
use rustc_index::vec::Idx;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::mir::*;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{self, Ty};
use rustc_span::Span;
use crate::universal_regions::UniversalRegions;
use super::{Locations, TypeChecker};
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
+ /// Check explicit closure signature annotation,
+ /// e.g., `|x: FxHashMap<_, &'static u32>| ...`.
+ #[instrument(skip(self, body), level = "debug")]
+ pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
+ let mir_def_id = body.source.def_id().expect_local();
+ if !self.tcx().is_closure(mir_def_id.to_def_id()) {
+ return;
+ }
+ let Some(user_provided_poly_sig) =
+ self.tcx().typeck(mir_def_id).user_provided_sigs.get(&mir_def_id)
+ else {
+ return;
+ };
+
+ // Instantiate the canonicalized variables from user-provided signature
+ // (e.g., the `_` in the code above) with fresh variables.
+ // Then replace the bound items in the fn sig with fresh variables,
+ // so that they represent the view from "inside" the closure.
+ let user_provided_sig = self
+ .instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig);
+ let user_provided_sig = self.infcx.replace_bound_vars_with_fresh_vars(
+ body.span,
+ LateBoundRegionConversionTime::FnCall,
+ user_provided_sig,
+ );
+
+ for (&user_ty, arg_decl) in user_provided_sig.inputs().iter().zip(
+ // In MIR, closure args begin with an implicit `self`. Skip it!
+ body.args_iter().skip(1).map(|local| &body.local_decls[local]),
+ ) {
+ self.ascribe_user_type_skip_wf(
+ arg_decl.ty,
+ ty::UserType::Ty(user_ty),
+ arg_decl.source_info.span,
+ );
+ }
+
+ // If the user explicitly annotated the output type, enforce it.
+ let output_decl = &body.local_decls[RETURN_PLACE];
+ self.ascribe_user_type_skip_wf(
+ output_decl.ty,
+ ty::UserType::Ty(user_provided_sig.output()),
+ output_decl.source_info.span,
+ );
+ }
+
#[instrument(skip(self, body, universal_regions), level = "debug")]
pub(super) fn equate_inputs_and_outputs(
&mut self,
debug!(?normalized_output_ty);
debug!(?normalized_input_tys);
- let mir_def_id = body.source.def_id().expect_local();
-
- // If the user explicitly annotated the input types, extract
- // those.
- //
- // e.g., `|x: FxHashMap<_, &'static u32>| ...`
- let user_provided_sig = if !self.tcx().is_closure(mir_def_id.to_def_id()) {
- None
- } else {
- let typeck_results = self.tcx().typeck(mir_def_id);
-
- typeck_results.user_provided_sigs.get(&mir_def_id).map(|user_provided_poly_sig| {
- // Instantiate the canonicalized variables from
- // user-provided signature (e.g., the `_` in the code
- // above) with fresh variables.
- let poly_sig = self.instantiate_canonical_with_fresh_inference_vars(
- body.span,
- &user_provided_poly_sig,
- );
-
- // Replace the bound items in the fn sig with fresh
- // variables, so that they represent the view from
- // "inside" the closure.
- self.infcx.replace_bound_vars_with_fresh_vars(
- body.span,
- LateBoundRegionConversionTime::FnCall,
- poly_sig,
- )
- })
- };
-
- debug!(?normalized_input_tys, ?body.local_decls);
-
// Equate expected input tys with those in the MIR.
for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
if argument_index + 1 >= body.local_decls.len() {
);
}
- if let Some(user_provided_sig) = user_provided_sig {
- for (argument_index, &user_provided_input_ty) in
- user_provided_sig.inputs().iter().enumerate()
- {
- // In MIR, closures begin an implicit `self`, so
- // argument N is stored in local N+2.
- let local = Local::new(argument_index + 2);
- let mir_input_ty = body.local_decls[local].ty;
- let mir_input_span = body.local_decls[local].source_info.span;
-
- // If the user explicitly annotated the input types, enforce those.
- let user_provided_input_ty =
- self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
-
- self.equate_normalized_input_or_output(
- user_provided_input_ty,
- mir_input_ty,
- mir_input_span,
- );
- }
- }
-
debug!(
"equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}",
body.yield_ty(),
terr
);
};
-
- // If the user explicitly annotated the output types, enforce those.
- // Note that this only happens for closures.
- if let Some(user_provided_sig) = user_provided_sig {
- let user_provided_output_ty = user_provided_sig.output();
- let user_provided_output_ty =
- self.normalize(user_provided_output_ty, Locations::All(output_span));
- if let Err(err) = self.eq_types(
- user_provided_output_ty,
- mir_output_ty,
- Locations::All(output_span),
- ConstraintCategory::BoringNoLocation,
- ) {
- span_mirbug!(
- self,
- Location::START,
- "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
- mir_output_ty,
- user_provided_output_ty,
- err
- );
- }
- }
}
#[instrument(skip(self), level = "debug")]
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::VariantIdx;
-use rustc_trait_selection::traits::query::type_op;
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
}
checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
+ checker.check_signature_annotation(&body);
+
liveness::generate(
&mut checker,
body,
check_err(self, promoted_body, ty, promoted_ty);
}
} else {
- if let Err(terr) = self.cx.fully_perform_op(
- locations,
- ConstraintCategory::Boring,
- self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
- constant.literal.ty(),
+ self.cx.ascribe_user_type(
+ constant.literal.ty(),
+ UserType::TypeOf(
uv.def.did,
UserSubsts { substs: uv.substs, user_self_ty: None },
- )),
- ) {
- span_mirbug!(
- self,
- constant,
- "bad constant type {:?} ({:?})",
- constant,
- terr
- );
- }
+ ),
+ locations.span(&self.cx.body),
+ );
}
} else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
let unnormalized_ty = tcx.type_of(static_def_id);
debug!(?self.user_type_annotations);
for user_annotation in self.user_type_annotations {
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
- let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
- debug!(?annotation);
- match annotation {
- UserType::Ty(mut ty) => {
- ty = self.normalize(ty, Locations::All(span));
-
- if let Err(terr) = self.eq_types(
- ty,
- inferred_ty,
- Locations::All(span),
- ConstraintCategory::BoringNoLocation,
- ) {
- span_mirbug!(
- self,
- user_annotation,
- "bad user type ({:?} = {:?}): {:?}",
- ty,
- inferred_ty,
- terr
- );
- }
-
- self.prove_predicate(
- ty::Binder::dummy(ty::PredicateKind::WellFormed(inferred_ty.into())),
- Locations::All(span),
- ConstraintCategory::TypeAnnotation,
- );
- }
- UserType::TypeOf(def_id, user_substs) => {
- if let Err(terr) = self.fully_perform_op(
- Locations::All(span),
- ConstraintCategory::BoringNoLocation,
- self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
- inferred_ty,
- def_id,
- user_substs,
- )),
- ) {
- span_mirbug!(
- self,
- user_annotation,
- "bad user type AscribeUserType({:?}, {:?} {:?}, type_of={:?}): {:?}",
- inferred_ty,
- def_id,
- user_substs,
- self.tcx().type_of(def_id),
- terr,
- );
- }
- }
- }
+ self.ascribe_user_type(inferred_ty, annotation, span);
}
}
// `let names: &'static _ = &["field1", "field2"];`
let names_let = if is_struct {
let lt_static = Some(cx.lifetime_static(span));
- let ty_static_ref =
- cx.ty_rptr(span, cx.ty_infer(span), lt_static, ast::Mutability::Not);
+ let ty_static_ref = cx.ty_ref(span, cx.ty_infer(span), lt_static, ast::Mutability::Not);
Some(cx.stmt_let_ty(
span,
false,
);
let ty_slice = cx.ty(
span,
- ast::TyKind::Slice(cx.ty_rptr(span, ty_dyn_debug, None, ast::Mutability::Not)),
+ ast::TyKind::Slice(cx.ty_ref(span, ty_dyn_debug, None, ast::Mutability::Not)),
);
let values_let = cx.stmt_let_ty(
span,
false,
Ident::new(sym::values, span),
- Some(cx.ty_rptr(span, ty_slice, None, ast::Mutability::Not)),
+ Some(cx.ty_ref(span, ty_slice, None, ast::Mutability::Not)),
cx.expr_array_ref(span, value_exprs),
);
match self {
Ref(ty, mutbl) => {
let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
- cx.ty_rptr(span, raw_ty, None, *mutbl)
+ cx.ty_ref(span, raw_ty, None, *mutbl)
}
Path(p) => p.to_ty(cx, span, self_ty, self_generics),
Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)),
sp,
true,
cx.std_path(&[sym::option, sym::Option, sym::None]),
- vec![GenericArg::Type(cx.ty_rptr(
+ vec![GenericArg::Type(cx.ty_ref(
sp,
cx.ty_ident(sp, Ident::new(sym::str, sp)),
Some(lt),
if show_doc_note {
diag.note(concat!(
stringify!($kind),
- " formatting not supported; see the documentation for `std::fmt`",
+ " formatting is not supported; see the documentation for `std::fmt`",
));
}
if suggestions.len() > 0 {
.item_static(
span,
Ident::new(sym::_DECLS, span),
- cx.ty_rptr(
+ cx.ty_ref(
span,
cx.ty(
span,
) -> RValue<'gcc> {
// FIXME(antoyo): remove when having a proper API.
let gcc_func = unsafe { std::mem::transmute(func) };
- let call = if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() {
+ let call = if self.functions.borrow().values().any(|value| *value == gcc_func) {
self.function_call(func, args, funclet)
}
else {
pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> {
let function: Function<'gcc> = unsafe { std::mem::transmute(value) };
- debug_assert!(self.functions.borrow().values().find(|value| **value == function).is_some(),
+ debug_assert!(self.functions.borrow().values().any(|value| *value == function),
"{:?} ({:?}) is not a function", value, value.get_type());
function
}
);
}
-fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool {
- // LLVM prior to version 12 had known miscompiles in the presence of
- // noalias attributes (see #54878), but we don't support earlier
- // versions at all anymore. We now enable mutable noalias by default.
- cx.tcx.sess.opts.unstable_opts.mutable_noalias.unwrap_or(true)
-}
-
const ABI_AFFECTING_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 1] =
[(ArgAttribute::InReg, llvm::AttributeKind::InReg)];
attrs.push(llattr.create_attr(cx.llcx));
}
}
- if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) {
- attrs.push(llvm::AttributeKind::NoAlias.create_attr(cx.llcx));
- }
} else if cx.tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) {
// If we're not optimising, *but* memory sanitizer is on, emit noundef, since it affects
// memory sanitizer's behavior.
use crate::value::Value;
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
-use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
+use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphization};
use rustc_codegen_ssa::mir::operand::OperandRef;
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::*;
_ => bug!(),
},
None => {
- span_invalid_monomorphization_error(
- tcx.sess,
+ tcx.sess.emit_err(InvalidMonomorphization::BasicIntegerType {
span,
- &format!(
- "invalid monomorphization of `{}` intrinsic: \
- expected basic integer type, found `{}`",
- name, ty
- ),
- );
+ name,
+ ty,
+ });
return;
}
}
llret_ty: &'ll Type,
span: Span,
) -> Result<&'ll Value, ()> {
- // macros for error handling:
- #[allow(unused_macro_rules)]
- macro_rules! emit_error {
- ($msg: tt) => {
- emit_error!($msg, )
- };
- ($msg: tt, $($fmt: tt)*) => {
- span_invalid_monomorphization_error(
- bx.sess(), span,
- &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
- name, $($fmt)*));
- }
- }
-
macro_rules! return_error {
- ($($fmt: tt)*) => {
- {
- emit_error!($($fmt)*);
- return Err(());
- }
- }
+ ($diag: expr) => {{
+ bx.sess().emit_err($diag);
+ return Err(());
+ }};
}
macro_rules! require {
- ($cond: expr, $($fmt: tt)*) => {
+ ($cond: expr, $diag: expr) => {
if !$cond {
- return_error!($($fmt)*);
+ return_error!($diag);
}
};
}
macro_rules! require_simd {
- ($ty: expr, $position: expr) => {
- require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty)
+ ($ty: expr, $diag: expr) => {
+ require!($ty.is_simd(), $diag)
};
}
let arg_tys = sig.inputs();
if name == sym::simd_select_bitmask {
- require_simd!(arg_tys[1], "argument");
+ require_simd!(
+ arg_tys[1],
+ InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
+ );
+
let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
let expected_int_bits = (len.max(8) - 1).next_power_of_two();
let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty));
bx.load(int_ty, ptr, Align::ONE)
}
- _ => return_error!(
- "invalid bitmask `{}`, expected `u{}` or `[u8; {}]`",
+ _ => return_error!(InvalidMonomorphization::InvalidBitmask {
+ span,
+ name,
mask_ty,
expected_int_bits,
expected_bytes
- ),
+ }),
};
let i1 = bx.type_i1();
}
// every intrinsic below takes a SIMD vector as its first argument
- require_simd!(arg_tys[0], "input");
+ require_simd!(arg_tys[0], InvalidMonomorphization::SimdInput { span, name, ty: arg_tys[0] });
let in_ty = arg_tys[0];
let comparison = match name {
let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx());
if let Some(cmp_op) = comparison {
- require_simd!(ret_ty, "return");
+ require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
+
require!(
in_len == out_len,
- "expected return type with length {} (same as input type `{}`), \
- found `{}` with length {}",
- in_len,
- in_ty,
- ret_ty,
- out_len
+ InvalidMonomorphization::ReturnLengthInputType {
+ span,
+ name,
+ in_len,
+ in_ty,
+ ret_ty,
+ out_len
+ }
);
require!(
bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
- "expected return type with integer elements, found `{}` with non-integer `{}`",
- ret_ty,
- out_ty
+ InvalidMonomorphization::ReturnIntegerType { span, name, ret_ty, out_ty }
);
return Ok(compare_simd_types(
span_bug!(span, "could not evaluate shuffle index array length")
})
}
- _ => return_error!(
- "simd_shuffle index must be an array of `u32`, got `{}`",
- args[2].layout.ty
- ),
+ _ => return_error!(InvalidMonomorphization::SimdShuffle {
+ span,
+ name,
+ ty: args[2].layout.ty
+ }),
}
} else {
stripped.parse().unwrap_or_else(|_| {
})
};
- require_simd!(ret_ty, "return");
+ require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
require!(
out_len == n,
- "expected return type of length {}, found `{}` with length {}",
- n,
- ret_ty,
- out_len
+ InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len }
);
require!(
in_elem == out_ty,
- "expected return element type `{}` (element of input `{}`), \
- found `{}` with element type `{}`",
- in_elem,
- in_ty,
- ret_ty,
- out_ty
+ InvalidMonomorphization::ReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty }
);
let total_len = u128::from(in_len) * 2;
let val = bx.const_get_elt(vector, i as u64);
match bx.const_to_opt_u128(val, true) {
None => {
- emit_error!("shuffle index #{} is not a constant", arg_idx);
+ bx.sess().emit_err(InvalidMonomorphization::ShuffleIndexNotConstant {
+ span,
+ name,
+ arg_idx,
+ });
None
}
Some(idx) if idx >= total_len => {
- emit_error!(
- "shuffle index #{} is out of bounds (limit {})",
+ bx.sess().emit_err(InvalidMonomorphization::ShuffleIndexOutOfBounds {
+ span,
+ name,
arg_idx,
- total_len
- );
+ total_len,
+ });
None
}
Some(idx) => Some(bx.const_i32(idx as i32)),
if name == sym::simd_insert {
require!(
in_elem == arg_tys[2],
- "expected inserted type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- arg_tys[2]
+ InvalidMonomorphization::InsertedType {
+ span,
+ name,
+ in_elem,
+ in_ty,
+ out_ty: arg_tys[2]
+ }
);
return Ok(bx.insert_element(
args[0].immediate(),
if name == sym::simd_extract {
require!(
ret_ty == in_elem,
- "expected return type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- ret_ty
+ InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
);
return Ok(bx.extract_element(args[0].immediate(), args[1].immediate()));
}
if name == sym::simd_select {
let m_elem_ty = in_elem;
let m_len = in_len;
- require_simd!(arg_tys[1], "argument");
+ require_simd!(
+ arg_tys[1],
+ InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
+ );
let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
require!(
m_len == v_len,
- "mismatched lengths: mask length `{}` != other vector length `{}`",
- m_len,
- v_len
+ InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
);
match m_elem_ty.kind() {
ty::Int(_) => {}
- _ => return_error!("mask element type is `{}`, expected `i_`", m_elem_ty),
+ _ => return_error!(InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }),
}
// truncate the mask to a vector of i1s
let i1 = bx.type_i1();
args[0].immediate(),
i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()),
),
- _ => return_error!(
- "vector argument `{}`'s element type `{}`, expected integer element type",
+ _ => return_error!(InvalidMonomorphization::VectorArgument {
+ span,
+ name,
in_ty,
in_elem
- ),
+ }),
};
// Shift the MSB to the right by "in_elem_bitwidth - 1" into the first bit position.
let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty));
return Ok(bx.load(array_ty, ptr, Align::ONE));
}
- _ => return_error!(
- "cannot return `{}`, expected `u{}` or `[u8; {}]`",
+ _ => return_error!(InvalidMonomorphization::CannotReturn {
+ span,
+ name,
ret_ty,
expected_int_bits,
expected_bytes
- ),
+ }),
}
}
span: Span,
args: &[OperandRef<'tcx, &'ll Value>],
) -> Result<&'ll Value, ()> {
- #[allow(unused_macro_rules)]
- macro_rules! emit_error {
- ($msg: tt) => {
- emit_error!($msg, )
- };
- ($msg: tt, $($fmt: tt)*) => {
- span_invalid_monomorphization_error(
- bx.sess(), span,
- &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
- name, $($fmt)*));
- }
- }
macro_rules! return_error {
- ($($fmt: tt)*) => {
- {
- emit_error!($($fmt)*);
- return Err(());
- }
- }
+ ($diag: expr) => {{
+ bx.sess().emit_err($diag);
+ return Err(());
+ }};
}
let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() {
match f.bit_width() {
32 => ("f32", elem_ty),
64 => ("f64", elem_ty),
- _ => {
- return_error!(
- "unsupported element type `{}` of floating-point vector `{}`",
- f.name_str(),
- in_ty
- );
- }
+ _ => return_error!(InvalidMonomorphization::FloatingPointVector {
+ span,
+ name,
+ f_ty: *f,
+ in_ty,
+ }),
}
} else {
- return_error!("`{}` is not a floating-point type", in_ty);
+ return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty });
};
let vec_ty = bx.type_vector(elem_ty, in_len);
sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)),
sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)),
sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)),
- _ => return_error!("unrecognized intrinsic `{}`", name),
+ _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }),
};
let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
let f = bx.declare_cfn(llvm_name, llvm::UnnamedAddr::No, fn_ty);
// * M: any integer width is supported, will be truncated to i1
// All types must be simd vector types
- require_simd!(in_ty, "first");
- require_simd!(arg_tys[1], "second");
- require_simd!(arg_tys[2], "third");
- require_simd!(ret_ty, "return");
+ require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
+ require_simd!(
+ arg_tys[1],
+ InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
+ );
+ require_simd!(
+ arg_tys[2],
+ InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
+ );
+ require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
// Of the same length:
let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
require!(
in_len == out_len,
- "expected {} argument with length {} (same as input type `{}`), \
- found `{}` with length {}",
- "second",
- in_len,
- in_ty,
- arg_tys[1],
- out_len
+ InvalidMonomorphization::SecondArgumentLength {
+ span,
+ name,
+ in_len,
+ in_ty,
+ arg_ty: arg_tys[1],
+ out_len
+ }
);
require!(
in_len == out_len2,
- "expected {} argument with length {} (same as input type `{}`), \
- found `{}` with length {}",
- "third",
- in_len,
- in_ty,
- arg_tys[2],
- out_len2
+ InvalidMonomorphization::ThirdArgumentLength {
+ span,
+ name,
+ in_len,
+ in_ty,
+ arg_ty: arg_tys[2],
+ out_len: out_len2
+ }
);
// The return type must match the first argument type
- require!(ret_ty == in_ty, "expected return type `{}`, found `{}`", in_ty, ret_ty);
+ require!(
+ ret_ty == in_ty,
+ InvalidMonomorphization::ExpectedReturnType { span, name, in_ty, ret_ty }
+ );
// This counts how many pointers
fn ptr_count(t: Ty<'_>) -> usize {
_ => {
require!(
false,
- "expected element type `{}` of second argument `{}` \
- to be a pointer to the element type `{}` of the first \
- argument `{}`, found `{}` != `*_ {}`",
- element_ty1,
- arg_tys[1],
- in_elem,
- in_ty,
- element_ty1,
- in_elem
+ InvalidMonomorphization::ExpectedElementType {
+ span,
+ name,
+ expected_element: element_ty1,
+ second_arg: arg_tys[1],
+ in_elem,
+ in_ty,
+ mutability: ExpectedPointerMutability::Not,
+ }
);
unreachable!();
}
_ => {
require!(
false,
- "expected element type `{}` of third argument `{}` \
- to be a signed integer type",
- element_ty2,
- arg_tys[2]
+ InvalidMonomorphization::ThirdArgElementType {
+ span,
+ name,
+ expected_element: element_ty2,
+ third_arg: arg_tys[2]
+ }
);
}
}
// * M: any integer width is supported, will be truncated to i1
// All types must be simd vector types
- require_simd!(in_ty, "first");
- require_simd!(arg_tys[1], "second");
- require_simd!(arg_tys[2], "third");
+ require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
+ require_simd!(
+ arg_tys[1],
+ InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
+ );
+ require_simd!(
+ arg_tys[2],
+ InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
+ );
// Of the same length:
let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx());
let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
require!(
in_len == element_len1,
- "expected {} argument with length {} (same as input type `{}`), \
- found `{}` with length {}",
- "second",
- in_len,
- in_ty,
- arg_tys[1],
- element_len1
+ InvalidMonomorphization::SecondArgumentLength {
+ span,
+ name,
+ in_len,
+ in_ty,
+ arg_ty: arg_tys[1],
+ out_len: element_len1
+ }
);
require!(
in_len == element_len2,
- "expected {} argument with length {} (same as input type `{}`), \
- found `{}` with length {}",
- "third",
- in_len,
- in_ty,
- arg_tys[2],
- element_len2
+ InvalidMonomorphization::ThirdArgumentLength {
+ span,
+ name,
+ in_len,
+ in_ty,
+ arg_ty: arg_tys[2],
+ out_len: element_len2
+ }
);
// This counts how many pointers
_ => {
require!(
false,
- "expected element type `{}` of second argument `{}` \
- to be a pointer to the element type `{}` of the first \
- argument `{}`, found `{}` != `*mut {}`",
- element_ty1,
- arg_tys[1],
- in_elem,
- in_ty,
- element_ty1,
- in_elem
+ InvalidMonomorphization::ExpectedElementType {
+ span,
+ name,
+ expected_element: element_ty1,
+ second_arg: arg_tys[1],
+ in_elem,
+ in_ty,
+ mutability: ExpectedPointerMutability::Mut,
+ }
);
unreachable!();
}
_ => {
require!(
false,
- "expected element type `{}` of third argument `{}` \
- be a signed integer type",
- element_ty2,
- arg_tys[2]
+ InvalidMonomorphization::ThirdArgElementType {
+ span,
+ name,
+ expected_element: element_ty2,
+ third_arg: arg_tys[2]
+ }
);
}
}
if name == sym::$name {
require!(
ret_ty == in_elem,
- "expected return type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- ret_ty
+ InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
);
return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {
32 => bx.const_real(bx.type_f32(), $identity),
64 => bx.const_real(bx.type_f64(), $identity),
v => return_error!(
- r#"
-unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
- sym::$name,
- in_ty,
- in_elem,
- v,
- ret_ty
+ InvalidMonomorphization::UnsupportedSymbolOfSize {
+ span,
+ name,
+ symbol: sym::$name,
+ in_ty,
+ in_elem,
+ size: v,
+ ret_ty
+ }
),
}
};
Ok(bx.$float_reduce(acc, args[0].immediate()))
}
- _ => return_error!(
- "unsupported {} from `{}` with element `{}` to `{}`",
- sym::$name,
+ _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
+ span,
+ name,
+ symbol: sym::$name,
in_ty,
in_elem,
ret_ty
- ),
+ }),
};
}
};
if name == sym::$name {
require!(
ret_ty == in_elem,
- "expected return type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- ret_ty
+ InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
);
return match in_elem.kind() {
ty::Int(_i) => Ok(bx.$int_red(args[0].immediate(), true)),
ty::Uint(_u) => Ok(bx.$int_red(args[0].immediate(), false)),
ty::Float(_f) => Ok(bx.$float_red(args[0].immediate())),
- _ => return_error!(
- "unsupported {} from `{}` with element `{}` to `{}`",
- sym::$name,
+ _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
+ span,
+ name,
+ symbol: sym::$name,
in_ty,
in_elem,
ret_ty
- ),
+ }),
};
}
};
let input = if !$boolean {
require!(
ret_ty == in_elem,
- "expected return type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- ret_ty
+ InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
);
args[0].immediate()
} else {
match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {}
- _ => return_error!(
- "unsupported {} from `{}` with element `{}` to `{}`",
- sym::$name,
+ _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
+ span,
+ name,
+ symbol: sym::$name,
in_ty,
in_elem,
ret_ty
- ),
+ }),
}
// boolean reductions operate on vectors of i1s:
let r = bx.$red(input);
Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) })
}
- _ => return_error!(
- "unsupported {} from `{}` with element `{}` to `{}`",
- sym::$name,
+ _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
+ span,
+ name,
+ symbol: sym::$name,
in_ty,
in_elem,
ret_ty
- ),
+ }),
};
}
};
bitwise_red!(simd_reduce_any: vector_reduce_or, true);
if name == sym::simd_cast_ptr {
- require_simd!(ret_ty, "return");
+ require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
require!(
in_len == out_len,
- "expected return type with length {} (same as input type `{}`), \
- found `{}` with length {}",
- in_len,
- in_ty,
- ret_ty,
- out_len
+ InvalidMonomorphization::ReturnLengthInputType {
+ span,
+ name,
+ in_len,
+ in_ty,
+ ret_ty,
+ out_len
+ }
);
match in_elem.kind() {
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
});
assert!(!check_sized); // we are in codegen, so we shouldn't see these types
- require!(metadata.is_unit(), "cannot cast fat pointer `{}`", in_elem)
+ require!(
+ metadata.is_unit(),
+ InvalidMonomorphization::CastFatPointer { span, name, ty: in_elem }
+ );
+ }
+ _ => {
+ return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem })
}
- _ => return_error!("expected pointer, got `{}`", in_elem),
}
match out_elem.kind() {
ty::RawPtr(p) => {
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
});
assert!(!check_sized); // we are in codegen, so we shouldn't see these types
- require!(metadata.is_unit(), "cannot cast to fat pointer `{}`", out_elem)
+ require!(
+ metadata.is_unit(),
+ InvalidMonomorphization::CastFatPointer { span, name, ty: out_elem }
+ );
+ }
+ _ => {
+ return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem })
}
- _ => return_error!("expected pointer, got `{}`", out_elem),
}
if in_elem == out_elem {
}
if name == sym::simd_expose_addr {
- require_simd!(ret_ty, "return");
+ require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
require!(
in_len == out_len,
- "expected return type with length {} (same as input type `{}`), \
- found `{}` with length {}",
- in_len,
- in_ty,
- ret_ty,
- out_len
+ InvalidMonomorphization::ReturnLengthInputType {
+ span,
+ name,
+ in_len,
+ in_ty,
+ ret_ty,
+ out_len
+ }
);
match in_elem.kind() {
ty::RawPtr(_) => {}
- _ => return_error!("expected pointer, got `{}`", in_elem),
+ _ => {
+ return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem })
+ }
}
match out_elem.kind() {
ty::Uint(ty::UintTy::Usize) => {}
- _ => return_error!("expected `usize`, got `{}`", out_elem),
+ _ => return_error!(InvalidMonomorphization::ExpectedUsize { span, name, ty: out_elem }),
}
return Ok(bx.ptrtoint(args[0].immediate(), llret_ty));
}
if name == sym::simd_from_exposed_addr {
- require_simd!(ret_ty, "return");
+ require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
require!(
in_len == out_len,
- "expected return type with length {} (same as input type `{}`), \
- found `{}` with length {}",
- in_len,
- in_ty,
- ret_ty,
- out_len
+ InvalidMonomorphization::ReturnLengthInputType {
+ span,
+ name,
+ in_len,
+ in_ty,
+ ret_ty,
+ out_len
+ }
);
match in_elem.kind() {
ty::Uint(ty::UintTy::Usize) => {}
- _ => return_error!("expected `usize`, got `{}`", in_elem),
+ _ => return_error!(InvalidMonomorphization::ExpectedUsize { span, name, ty: in_elem }),
}
match out_elem.kind() {
ty::RawPtr(_) => {}
- _ => return_error!("expected pointer, got `{}`", out_elem),
+ _ => {
+ return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem })
+ }
}
return Ok(bx.inttoptr(args[0].immediate(), llret_ty));
}
if name == sym::simd_cast || name == sym::simd_as {
- require_simd!(ret_ty, "return");
+ require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
require!(
in_len == out_len,
- "expected return type with length {} (same as input type `{}`), \
- found `{}` with length {}",
- in_len,
- in_ty,
- ret_ty,
- out_len
+ InvalidMonomorphization::ReturnLengthInputType {
+ span,
+ name,
+ in_len,
+ in_ty,
+ ret_ty,
+ out_len
+ }
);
// casting cares about nominal type, not just structural type
if in_elem == out_elem {
}
require!(
false,
- "unsupported cast from `{}` with element `{}` to `{}` with element `{}`",
- in_ty,
- in_elem,
- ret_ty,
- out_elem
+ InvalidMonomorphization::UnsupportedCast {
+ span,
+ name,
+ in_ty,
+ in_elem,
+ ret_ty,
+ out_elem
+ }
);
}
macro_rules! arith_binary {
})*
_ => {},
}
- require!(false,
- "unsupported operation on `{}` with element `{}`",
- in_ty,
- in_elem)
+ require!(
+ false,
+ InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
+ );
})*
}
}
})*
_ => {},
}
- require!(false,
- "unsupported operation on `{}` with element `{}`",
- in_ty,
- in_elem)
+ require!(
+ false,
+ InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
+ );
})*
}
}
ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)),
ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)),
_ => {
- return_error!(
- "expected element type `{}` of vector type `{}` \
- to be a signed or unsigned integer type",
- arg_tys[0].simd_size_and_type(bx.tcx()).1,
- arg_tys[0]
- );
+ return_error!(InvalidMonomorphization::ExpectedVectorElementType {
+ span,
+ name,
+ expected_element: arg_tys[0].simd_size_and_type(bx.tcx()).1,
+ vector_type: arg_tys[0]
+ });
}
};
let llvm_intrinsic = &format!(
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
rustc_middle = { path = "../rustc_middle" }
+rustc_type_ir = { path = "../rustc_type_ir" }
rustc_attr = { path = "../rustc_attr" }
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
rustc_data_structures = { path = "../rustc_data_structures" }
use rustc_metadata::fs::{emit_wrapper_file, METADATA_FILENAME};
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
-use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Lto, Strip};
+use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
use rustc_session::cstore::DllImport;
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
Ok(())
}
+// Crate type is not passed when calculating the dylibs to include for LTO. In that case all
+// crate types must use the same dependency formats.
pub fn each_linked_rlib(
- sess: &Session,
info: &CrateInfo,
+ crate_type: Option<CrateType>,
f: &mut dyn FnMut(CrateNum, &Path),
) -> Result<(), errors::LinkRlibError> {
let crates = info.used_crates.iter();
- let mut fmts = None;
- let lto_active = matches!(sess.lto(), Lto::Fat | Lto::Thin);
- if lto_active {
+ let fmts = if crate_type.is_none() {
for combination in info.dependency_formats.iter().combinations(2) {
let (ty1, list1) = &combination[0];
let (ty2, list2) = &combination[1];
});
}
}
- }
-
- for (ty, list) in info.dependency_formats.iter() {
- match ty {
- CrateType::Executable
- | CrateType::Staticlib
- | CrateType::Cdylib
- | CrateType::ProcMacro => {
- fmts = Some(list);
- break;
- }
- CrateType::Dylib if lto_active => {
- fmts = Some(list);
- break;
- }
- _ => {}
+ if info.dependency_formats.is_empty() {
+ return Err(errors::LinkRlibError::MissingFormat);
}
- }
- let Some(fmts) = fmts else {
- return Err(errors::LinkRlibError::MissingFormat);
+ &info.dependency_formats[0].1
+ } else {
+ let fmts = info
+ .dependency_formats
+ .iter()
+ .find_map(|&(ty, ref list)| if Some(ty) == crate_type { Some(list) } else { None });
+
+ let Some(fmts) = fmts else {
+ return Err(errors::LinkRlibError::MissingFormat);
+ };
+
+ fmts
};
+
for &cnum in crates {
match fmts.get(cnum.as_usize() - 1) {
Some(&Linkage::NotLinked | &Linkage::Dynamic | &Linkage::IncludedFromDylib) => continue,
)?;
let mut all_native_libs = vec![];
- let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| {
- let name = codegen_results.crate_info.crate_name[&cnum];
- let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
-
- // Here when we include the rlib into our staticlib we need to make a
- // decision whether to include the extra object files along the way.
- // These extra object files come from statically included native
- // libraries, but they may be cfg'd away with #[link(cfg(..))].
- //
- // This unstable feature, though, only needs liblibc to work. The only
- // use case there is where musl is statically included in liblibc.rlib,
- // so if we don't want the included version we just need to skip it. As
- // a result the logic here is that if *any* linked library is cfg'd away
- // we just skip all object files.
- //
- // Clearly this is not sufficient for a general purpose feature, and
- // we'd want to read from the library's metadata to determine which
- // object files come from where and selectively skip them.
- let skip_object_files = native_libs.iter().any(|lib| {
- matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
- && !relevant_lib(sess, lib)
- });
+ let res = each_linked_rlib(
+ &codegen_results.crate_info,
+ Some(CrateType::Staticlib),
+ &mut |cnum, path| {
+ let name = codegen_results.crate_info.crate_name[&cnum];
+ let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
+
+ // Here when we include the rlib into our staticlib we need to make a
+ // decision whether to include the extra object files along the way.
+ // These extra object files come from statically included native
+ // libraries, but they may be cfg'd away with #[link(cfg(..))].
+ //
+ // This unstable feature, though, only needs liblibc to work. The only
+ // use case there is where musl is statically included in liblibc.rlib,
+ // so if we don't want the included version we just need to skip it. As
+ // a result the logic here is that if *any* linked library is cfg'd away
+ // we just skip all object files.
+ //
+ // Clearly this is not sufficient for a general purpose feature, and
+ // we'd want to read from the library's metadata to determine which
+ // object files come from where and selectively skip them.
+ let skip_object_files = native_libs.iter().any(|lib| {
+ matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
+ && !relevant_lib(sess, lib)
+ });
- let lto = are_upstream_rust_objects_already_included(sess)
- && !ignored_for_lto(sess, &codegen_results.crate_info, cnum);
+ let lto = are_upstream_rust_objects_already_included(sess)
+ && !ignored_for_lto(sess, &codegen_results.crate_info, cnum);
- // Ignoring obj file starting with the crate name
- // as simple comparison is not enough - there
- // might be also an extra name suffix
- let obj_start = name.as_str().to_owned();
+ // Ignoring obj file starting with the crate name
+ // as simple comparison is not enough - there
+ // might be also an extra name suffix
+ let obj_start = name.as_str().to_owned();
- ab.add_archive(
- path,
- Box::new(move |fname: &str| {
- // Ignore metadata files, no matter the name.
- if fname == METADATA_FILENAME {
- return true;
- }
+ ab.add_archive(
+ path,
+ Box::new(move |fname: &str| {
+ // Ignore metadata files, no matter the name.
+ if fname == METADATA_FILENAME {
+ return true;
+ }
- // Don't include Rust objects if LTO is enabled
- if lto && looks_like_rust_object_file(fname) {
- return true;
- }
+ // Don't include Rust objects if LTO is enabled
+ if lto && looks_like_rust_object_file(fname) {
+ return true;
+ }
- // Otherwise if this is *not* a rust object and we're skipping
- // objects then skip this file
- if skip_object_files && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) {
- return true;
- }
+ // Otherwise if this is *not* a rust object and we're skipping
+ // objects then skip this file
+ if skip_object_files
+ && (!fname.starts_with(&obj_start) || !fname.ends_with(".o"))
+ {
+ return true;
+ }
- // ok, don't skip this
- false
- }),
- )
- .unwrap();
+ // ok, don't skip this
+ false
+ }),
+ )
+ .unwrap();
- all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
- });
+ all_native_libs
+ .extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
+ },
+ );
if let Err(e) = res {
sess.emit_fatal(e);
}
if !lib_args.is_empty() {
sess.emit_note(errors::StaticLibraryNativeArtifacts);
// Prefix for greppability
- sess.emit_note(errors::NativeStaticLibs { arguments: lib_args.join(" ") });
+ // Note: This must not be translated as tools are allowed to depend on this exact string.
+ sess.note_without_error(&format!("native-static-libs: {}", &lib_args.join(" ")));
}
}
sess.target.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum);
let mut archive = archive_builder_builder.new_archive_builder(sess);
- if let Err(e) = archive.add_archive(
+ if let Err(error) = archive.add_archive(
cratepath,
Box::new(move |f| {
if f == METADATA_FILENAME {
false
}),
) {
- sess.fatal(&format!("failed to build archive from rlib: {}", e));
+ sess.emit_fatal(errors::RlibArchiveBuildFailure { error });
}
if archive.build(&dst) {
link_upstream(&dst);
// Implement the "linker flavor" part of -Zgcc-ld
// by asking cc to use some kind of lld.
cmd.arg("-fuse-ld=lld");
+
if !flavor.is_gnu() {
// Tell clang to use a non-default LLD flavor.
// Gcc doesn't understand the target option, but we currently assume
// that gcc is not used for Apple and Wasm targets (#97402).
- cmd.arg(format!("--target={}", sess.target.llvm_target));
+ //
+ // Note that we don't want to do that by default on macOS: e.g. passing a
+ // 10.7 target to LLVM works, but not to recent versions of clang/macOS, as
+ // shown in issue #101653 and the discussion in PR #101792.
+ //
+ // It could be required in some cases of cross-compiling with
+ // `-Zgcc-ld=lld`, but this is generally unspecified, and we don't know
+ // which specific versions of clang, macOS SDK, host and target OS
+ // combinations impact us here.
+ //
+ // So we do a simple first-approximation until we know more of what the
+ // Apple targets require (and which would be handled prior to hitting this
+ // `-Zgcc-ld=lld` codepath anyway), but the expectation is that until then
+ // this should be manually passed if needed. We specify the target when
+ // targeting a different linker flavor on macOS, and that's also always
+ // the case when targeting WASM.
+ if sess.target.linker_flavor != sess.host.linker_flavor {
+ cmd.arg(format!("--target={}", sess.target.llvm_target));
+ }
}
}
}
let sess = tcx.sess;
let mut each_linked_rlib_for_lto = Vec::new();
- drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| {
+ drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| {
if link::ignored_for_lto(sess, crate_info, cnum) {
return;
}
submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen,
};
use crate::common::{IntPredicate, RealPredicate, TypeKind};
+use crate::errors;
use crate::meth;
use crate::mir;
use crate::mir::operand::OperandValue;
let Some(llfn) = cx.declare_c_main(llfty) else {
// FIXME: We should be smart and show a better diagnostic here.
let span = cx.tcx().def_span(rust_main_def_id);
- cx.sess()
- .struct_span_err(span, "entry symbol `main` declared multiple times")
- .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead")
- .emit();
+ cx.sess().emit_err(errors::MultipleMainFunctions { span });
cx.sess().abort_if_errors();
bug!();
};
&metadata,
&exported_symbols::metadata_symbol_name(tcx),
);
- if let Err(err) = std::fs::write(&file_name, data) {
- tcx.sess.fatal(&format!("error writing metadata object file: {}", err));
+ if let Err(error) = std::fs::write(&file_name, data) {
+ tcx.sess.emit_fatal(errors::MetadataObjectFileWrite { error });
}
Some(CompiledModule {
name: metadata_cgu_name,
let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
let windows_subsystem = subsystem.map(|subsystem| {
if subsystem != sym::windows && subsystem != sym::console {
- tcx.sess.fatal(&format!(
- "invalid windows subsystem `{}`, only \
- `windows` and `console` are allowed",
- subsystem
- ));
+ tcx.sess.emit_fatal(errors::InvalidWindowsSubsystem { subsystem });
}
subsystem.to_string()
});
#![allow(non_camel_case_types)]
-use rustc_errors::struct_span_err;
use rustc_hir::LangItem;
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
-use rustc_session::Session;
use rustc_span::Span;
use crate::base;
}
}
-pub fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
- struct_span_err!(a, b, E0511, "{}", c).emit();
-}
-
pub fn asm_const_to_str<'tcx>(
tcx: TyCtxt<'tcx>,
sp: Span,
Err(e) => {
// Computing the layout can still fail here, e.g. if the target architecture
// cannot represent the type. See https://github.com/rust-lang/rust/issues/94961.
+ // FIXME: migrate once `rustc_middle::mir::interpret::InterpError` is translatable.
tcx.sess.fatal(&format!("{}", e));
}
}
IntoDiagnosticArg,
};
use rustc_macros::Diagnostic;
+use rustc_middle::ty::Ty;
use rustc_span::{Span, Symbol};
+use rustc_type_ir::FloatTy;
use std::borrow::Cow;
use std::io::Error;
use std::path::{Path, PathBuf};
#[diag(codegen_ssa_static_library_native_artifacts)]
pub struct StaticLibraryNativeArtifacts;
-#[derive(Diagnostic)]
-#[diag(codegen_ssa_native_static_libs)]
-pub struct NativeStaticLibs {
- pub arguments: String,
-}
-
#[derive(Diagnostic)]
#[diag(codegen_ssa_link_script_unavailable)]
pub struct LinkScriptUnavailable;
#[primary_span]
pub span: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_multiple_main_functions)]
+#[help]
+pub struct MultipleMainFunctions {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_metadata_object_file_write)]
+pub struct MetadataObjectFileWrite {
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_invalid_windows_subsystem)]
+pub struct InvalidWindowsSubsystem {
+ pub subsystem: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_erroneous_constant)]
+pub struct ErroneousConstant {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_polymorphic_constant_too_generic)]
+pub struct PolymorphicConstantTooGeneric {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_shuffle_indices_evaluation)]
+pub struct ShuffleIndicesEvaluation {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_missing_memory_ordering)]
+pub struct MissingMemoryOrdering;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unknown_atomic_ordering)]
+pub struct UnknownAtomicOrdering;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_atomic_compare_exchange)]
+pub struct AtomicCompareExchange;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unknown_atomic_operation)]
+pub struct UnknownAtomicOperation;
+
+#[derive(Diagnostic)]
+pub enum InvalidMonomorphization<'tcx> {
+ #[diag(codegen_ssa_invalid_monomorphization_basic_integer_type, code = "E0511")]
+ BasicIntegerType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_basic_float_type, code = "E0511")]
+ BasicFloatType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_float_to_int_unchecked, code = "E0511")]
+ FloatToIntUnchecked {
+ #[primary_span]
+ span: Span,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_floating_point_vector, code = "E0511")]
+ FloatingPointVector {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ f_ty: FloatTy,
+ in_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_floating_point_type, code = "E0511")]
+ FloatingPointType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_unrecognized_intrinsic, code = "E0511")]
+ UnrecognizedIntrinsic {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_simd_argument, code = "E0511")]
+ SimdArgument {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_simd_input, code = "E0511")]
+ SimdInput {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_simd_first, code = "E0511")]
+ SimdFirst {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_simd_second, code = "E0511")]
+ SimdSecond {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_simd_third, code = "E0511")]
+ SimdThird {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_simd_return, code = "E0511")]
+ SimdReturn {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_invalid_bitmask, code = "E0511")]
+ InvalidBitmask {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ mask_ty: Ty<'tcx>,
+ expected_int_bits: u64,
+ expected_bytes: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_return_length_input_type, code = "E0511")]
+ ReturnLengthInputType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_len: u64,
+ in_ty: Ty<'tcx>,
+ ret_ty: Ty<'tcx>,
+ out_len: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_second_argument_length, code = "E0511")]
+ SecondArgumentLength {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_len: u64,
+ in_ty: Ty<'tcx>,
+ arg_ty: Ty<'tcx>,
+ out_len: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_third_argument_length, code = "E0511")]
+ ThirdArgumentLength {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_len: u64,
+ in_ty: Ty<'tcx>,
+ arg_ty: Ty<'tcx>,
+ out_len: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_return_integer_type, code = "E0511")]
+ ReturnIntegerType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ret_ty: Ty<'tcx>,
+ out_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_simd_shuffle, code = "E0511")]
+ SimdShuffle {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_return_length, code = "E0511")]
+ ReturnLength {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_len: u64,
+ ret_ty: Ty<'tcx>,
+ out_len: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_return_element, code = "E0511")]
+ ReturnElement {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_elem: Ty<'tcx>,
+ in_ty: Ty<'tcx>,
+ ret_ty: Ty<'tcx>,
+ out_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_not_constant, code = "E0511")]
+ ShuffleIndexNotConstant {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ arg_idx: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds, code = "E0511")]
+ ShuffleIndexOutOfBounds {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ arg_idx: u64,
+ total_len: u128,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_inserted_type, code = "E0511")]
+ InsertedType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_elem: Ty<'tcx>,
+ in_ty: Ty<'tcx>,
+ out_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_return_type, code = "E0511")]
+ ReturnType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_elem: Ty<'tcx>,
+ in_ty: Ty<'tcx>,
+ ret_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_expected_return_type, code = "E0511")]
+ ExpectedReturnType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_ty: Ty<'tcx>,
+ ret_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_mismatched_lengths, code = "E0511")]
+ MismatchedLengths {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ m_len: u64,
+ v_len: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_mask_type, code = "E0511")]
+ MaskType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_vector_argument, code = "E0511")]
+ VectorArgument {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_ty: Ty<'tcx>,
+ in_elem: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_cannot_return, code = "E0511")]
+ CannotReturn {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ret_ty: Ty<'tcx>,
+ expected_int_bits: u64,
+ expected_bytes: u64,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_expected_element_type, code = "E0511")]
+ ExpectedElementType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ expected_element: Ty<'tcx>,
+ second_arg: Ty<'tcx>,
+ in_elem: Ty<'tcx>,
+ in_ty: Ty<'tcx>,
+ mutability: ExpectedPointerMutability,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_third_arg_element_type, code = "E0511")]
+ ThirdArgElementType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ expected_element: Ty<'tcx>,
+ third_arg: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size, code = "E0511")]
+ UnsupportedSymbolOfSize {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ symbol: Symbol,
+ in_ty: Ty<'tcx>,
+ in_elem: Ty<'tcx>,
+ size: u64,
+ ret_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol, code = "E0511")]
+ UnsupportedSymbol {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ symbol: Symbol,
+ in_ty: Ty<'tcx>,
+ in_elem: Ty<'tcx>,
+ ret_ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = "E0511")]
+ CastFatPointer {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_expected_pointer, code = "E0511")]
+ ExpectedPointer {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_expected_usize, code = "E0511")]
+ ExpectedUsize {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_unsupported_cast, code = "E0511")]
+ UnsupportedCast {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_ty: Ty<'tcx>,
+ in_elem: Ty<'tcx>,
+ ret_ty: Ty<'tcx>,
+ out_elem: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_unsupported_operation, code = "E0511")]
+ UnsupportedOperation {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ in_ty: Ty<'tcx>,
+ in_elem: Ty<'tcx>,
+ },
+
+ #[diag(codegen_ssa_invalid_monomorphization_expected_vector_element_type, code = "E0511")]
+ ExpectedVectorElementType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ expected_element: Ty<'tcx>,
+ vector_type: Ty<'tcx>,
+ },
+}
+
+pub enum ExpectedPointerMutability {
+ Mut,
+ Not,
+}
+
+impl IntoDiagnosticArg for ExpectedPointerMutability {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ match self {
+ ExpectedPointerMutability::Mut => DiagnosticArgValue::Str(Cow::Borrowed("*mut")),
+ ExpectedPointerMutability::Not => DiagnosticArgValue::Str(Cow::Borrowed("*_")),
+ }
+ }
+}
+use crate::errors;
use crate::mir::operand::OperandRef;
use crate::traits::*;
use rustc_middle::mir;
self.cx.tcx().const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None).map_err(|err| {
match err {
ErrorHandled::Reported(_) => {
- self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered");
+ self.cx.tcx().sess.emit_err(errors::ErroneousConstant { span: constant.span });
}
ErrorHandled::TooGeneric => {
- span_bug!(constant.span, "codegen encountered polymorphic constant: {:?}", err);
+ self.cx
+ .tcx()
+ .sess
+ .diagnostic()
+ .emit_bug(errors::PolymorphicConstantTooGeneric { span: constant.span });
}
}
err
(llval, c.ty())
})
.unwrap_or_else(|_| {
- bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time");
+ bx.tcx().sess.emit_err(errors::ShuffleIndicesEvaluation { span });
// We've errored, so we don't have to produce working code.
let ty = self.monomorphize(ty);
let llty = bx.backend_type(bx.layout_of(ty));
use super::operand::{OperandRef, OperandValue};
use super::place::PlaceRef;
use super::FunctionCx;
-use crate::common::{span_invalid_monomorphization_error, IntPredicate};
+use crate::common::IntPredicate;
+use crate::errors;
+use crate::errors::InvalidMonomorphization;
use crate::glue;
use crate::meth;
use crate::traits::*;
_ => bug!(),
},
None => {
- span_invalid_monomorphization_error(
- bx.tcx().sess,
- span,
- &format!(
- "invalid monomorphization of `{}` intrinsic: \
- expected basic integer type, found `{}`",
- name, ty
- ),
- );
+ bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
return;
}
}
_ => bug!(),
},
None => {
- span_invalid_monomorphization_error(
- bx.tcx().sess,
- span,
- &format!(
- "invalid monomorphization of `{}` intrinsic: \
- expected basic float type, found `{}`",
- name, arg_tys[0]
- ),
- );
+ bx.tcx().sess.emit_err(InvalidMonomorphization::BasicFloatType { span, name, ty: arg_tys[0] });
return;
}
}
sym::float_to_int_unchecked => {
if float_type_width(arg_tys[0]).is_none() {
- span_invalid_monomorphization_error(
- bx.tcx().sess,
- span,
- &format!(
- "invalid monomorphization of `float_to_int_unchecked` \
- intrinsic: expected basic float type, \
- found `{}`",
- arg_tys[0]
- ),
- );
+ bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { span, ty: arg_tys[0] });
return;
}
let Some((_width, signed)) = int_type_width_signed(ret_ty, bx.tcx()) else {
- span_invalid_monomorphization_error(
- bx.tcx().sess,
- span,
- &format!(
- "invalid monomorphization of `float_to_int_unchecked` \
- intrinsic: expected basic integer type, \
- found `{}`",
- ret_ty
- ),
- );
+ bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { span, ty: ret_ty });
return;
};
if signed {
use crate::common::{AtomicRmwBinOp, SynchronizationScope};
let Some((instruction, ordering)) = atomic.split_once('_') else {
- bx.sess().fatal("Atomic intrinsic missing memory ordering");
+ bx.sess().emit_fatal(errors::MissingMemoryOrdering);
};
let parse_ordering = |bx: &Bx, s| match s {
"release" => Release,
"acqrel" => AcquireRelease,
"seqcst" => SequentiallyConsistent,
- _ => bx.sess().fatal("unknown ordering in atomic intrinsic"),
+ _ => bx.sess().emit_fatal(errors::UnknownAtomicOrdering),
};
let invalid_monomorphization = |ty| {
- span_invalid_monomorphization_error(
- bx.tcx().sess,
- span,
- &format!(
- "invalid monomorphization of `{}` intrinsic: \
- expected basic integer type, found `{}`",
- name, ty
- ),
- );
+ bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
};
match instruction {
"cxchg" | "cxchgweak" => {
let Some((success, failure)) = ordering.split_once('_') else {
- bx.sess().fatal("Atomic compare-exchange intrinsic missing failure memory ordering");
+ bx.sess().emit_fatal(errors::AtomicCompareExchange);
};
let ty = substs.type_at(0);
if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
"min" => AtomicRmwBinOp::AtomicMin,
"umax" => AtomicRmwBinOp::AtomicUMax,
"umin" => AtomicRmwBinOp::AtomicUMin,
- _ => bx.sess().fatal("unknown atomic operation"),
+ _ => bx.sess().emit_fatal(errors::UnknownAtomicOperation),
};
let ty = substs.type_at(0);
let local_def_id = def_id.expect_local();
let hir_id = tcx.local_def_id_to_hir_id(local_def_id);
- let Some(parent) = tcx.hir().find_parent_node(hir_id) else { return false };
+ let Some(parent) = tcx.hir().opt_parent_id(hir_id) else { return false };
let parent_def = tcx.hir().get(parent);
if !matches!(
}
pub fn immediate_dominator(&self, node: Node) -> Node {
- assert!(self.is_reachable(node), "node {:?} is not reachable", node);
+ assert!(self.is_reachable(node), "node {node:?} is not reachable");
self.immediate_dominators[node].unwrap()
}
pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
- assert!(self.is_reachable(node), "node {:?} is not reachable", node);
+ assert!(self.is_reachable(node), "node {node:?} is not reachable");
Iter { dominators: self, node: Some(node) }
}
.map(G::Node::new)
.map(|node| match this.start_walk_from(node) {
WalkReturn::Complete { scc_index } => scc_index,
- WalkReturn::Cycle { min_depth } => panic!(
- "`start_walk_node({:?})` returned cycle with depth {:?}",
- node, min_depth
- ),
+ WalkReturn::Cycle { min_depth } => {
+ panic!("`start_walk_node({node:?})` returned cycle with depth {min_depth:?}")
+ }
})
.collect();
NodeState::NotVisited => return None,
NodeState::InCycleWith { parent } => panic!(
- "`find_state` returned `InCycleWith({:?})`, which ought to be impossible",
- parent
+ "`find_state` returned `InCycleWith({parent:?})`, which ought to be impossible"
),
})
}
previous_node = previous;
}
// Only InCycleWith nodes were added to the reverse linked list.
- other => panic!("Invalid previous link while compressing cycle: {:?}", other),
+ other => panic!("Invalid previous link while compressing cycle: {other:?}"),
}
debug!("find_state: parent_state = {:?}", node_state);
// NotVisited can not be part of a cycle since it should
// have instead gotten explored.
NodeState::NotVisited | NodeState::InCycleWith { .. } => {
- panic!("invalid parent state: {:?}", node_state)
+ panic!("invalid parent state: {node_state:?}")
}
}
}
let counter = COUNTER.fetch_add(1, Ordering::AcqRel);
- let file_path = dir.as_ref().join(format!("{:010}_{}.gv", counter, description));
+ let file_path = dir.as_ref().join(format!("{counter:010}_{description}.gv"));
let mut gv_file = BufWriter::new(File::create(file_path).unwrap());
}
fn node_id(&self, index: &Self::Node) -> dot::Id<'_> {
- dot::Id::new(format!("obligation_{}", index)).unwrap()
+ dot::Id::new(format!("obligation_{index}")).unwrap()
}
fn node_label(&self, index: &Self::Node) -> dot::LabelText<'_> {
// length can behave as a source of entropy for heap addresses, when
// ASLR is disabled and the heap is otherwise determinic.
let pid: u32 = process::id();
- let filename = format!("{}-{:07}.rustc_profile", crate_name, pid);
+ let filename = format!("{crate_name}-{pid:07}.rustc_profile");
let path = output_directory.join(&filename);
let profiler =
Profiler::with_counter(&path, measureme::counters::Counter::by_name(counter_name)?)?;
SmallVec::from_vec(data)
};
if let Err(e) = ffi::CStr::from_bytes_with_nul(&data) {
- panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
+ panic!("The string \"{s}\" cannot be converted into a CStr: {e}");
}
SmallCStr { data }
}
pub fn new_with_nul(s: &str) -> SmallCStr {
let b = s.as_bytes();
if let Err(e) = ffi::CStr::from_bytes_with_nul(b) {
- panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
+ panic!("The string \"{s}\" cannot be converted into a CStr: {e}");
}
SmallCStr { data: SmallVec::from_slice(s.as_bytes()) }
}
iter.into_iter().flat_map(|s| s.as_bytes()).copied().collect::<SmallVec<_>>();
data.push(0);
if let Err(e) = ffi::CStr::from_bytes_with_nul(&data) {
- panic!("The iterator {:?} cannot be converted into a CStr: {}", data, e);
+ panic!("The iterator {data:?} cannot be converted into a CStr: {e}");
}
Self { data }
}
use crate::stable_hasher::{HashStable, StableHasher, StableOrd};
use std::borrow::Borrow;
use std::cmp::Ordering;
+use std::fmt::Debug;
use std::mem;
use std::ops::{Bound, Index, IndexMut, RangeBounds};
/// stores data in a more compact way. It also supports accessing contiguous
/// ranges of elements as a slice, and slices of already sorted elements can be
/// inserted efficiently.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
pub struct SortedMap<K, V> {
data: Vec<(K, V)>,
}
}
}
+impl<K: Debug, V: Debug> Debug for SortedMap<K, V> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_map().entries(self.data.iter().map(|(a, b)| (a, b))).finish()
+ }
+}
+
#[cfg(test)]
mod tests;
// This should return just one element, otherwise it's a bug
assert!(
filter.next().is_none(),
- "Collection {:#?} should have just one matching element",
- self
+ "Collection {self:#?} should have just one matching element"
);
Some(value)
}
Ok(arg) => args.extend(arg),
Err(err) => rustc_session::early_error(
rustc_session::config::ErrorOutputType::default(),
- &format!("Failed to load argument file: {}", err),
+ &format!("Failed to load argument file: {err}"),
),
}
}
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Utf8Error(None) => write!(fmt, "Utf8 error"),
- Error::Utf8Error(Some(path)) => write!(fmt, "Utf8 error in {}", path),
- Error::IOError(path, err) => write!(fmt, "IO Error: {}: {}", path, err),
+ Error::Utf8Error(Some(path)) => write!(fmt, "Utf8 error in {path}"),
+ Error::IOError(path, err) => write!(fmt, "IO Error: {path}: {err}"),
}
}
}
fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
let upper_cased_code = code.to_ascii_uppercase();
- let normalised = if upper_cased_code.starts_with('E') {
- upper_cased_code
- } else {
- format!("E{0:0>4}", code)
- };
+ let normalised =
+ if upper_cased_code.starts_with('E') { upper_cased_code } else { format!("E{code:0>4}") };
match registry.try_find_description(&normalised) {
Ok(Some(description)) => {
let mut is_in_code_block = false;
if io::stdout().is_terminal() {
show_content_with_pager(&text);
} else {
- print!("{}", text);
+ print!("{text}");
}
}
Ok(None) => {
- early_error(output, &format!("no extended information for {}", code));
+ early_error(output, &format!("no extended information for {code}"));
}
Err(InvalidErrorCode) => {
- early_error(output, &format!("{} is not a valid error code", code));
+ early_error(output, &format!("{code} is not a valid error code"));
}
}
}
// If pager fails for whatever reason, we should still print the content
// to standard output
if fallback_to_println {
- print!("{}", content);
+ print!("{content}");
}
}
);
let id = rustc_session::output::find_crate_name(sess, attrs, input);
if *req == PrintRequest::CrateName {
- println!("{}", id);
+ println!("{id}");
continue;
}
let crate_types = collect_crate_types(sess, attrs);
}
if let Some(value) = value {
- Some(format!("{}=\"{}\"", name, value))
+ Some(format!("{name}=\"{value}\""))
} else {
Some(name.to_string())
}
cfgs.sort();
for cfg in cfgs {
- println!("{}", cfg);
+ println!("{cfg}");
}
}
CallingConventions => {
let stable = sess.target.options.supported_split_debuginfo.contains(split);
let unstable_ok = sess.unstable_options();
if stable || unstable_ok {
- println!("{}", split);
+ println!("{split}");
}
}
}
) {
let verbose = matches.opt_present("verbose");
- println!("{} {}", binary, version);
+ println!("{binary} {version}");
if verbose {
- println!("binary: {}", binary);
- println!("commit-hash: {}", commit_hash);
- println!("commit-date: {}", commit_date);
+ println!("binary: {binary}");
+ println!("commit-hash: {commit_hash}");
+ println!("commit-date: {commit_date}");
println!("host: {}", config::host_triple());
- println!("release: {}", release);
+ println!("release: {release}");
let debug_flags = matches.opt_strs("Z");
let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
.map(|&(name, ..)| ('C', name))
.chain(Z_OPTIONS.iter().map(|&(name, ..)| ('Z', name)))
.find(|&(_, name)| *opt == name.replace('_', "-"))
- .map(|(flag, _)| format!("{}. Did you mean `-{} {}`?", e, flag, opt)),
+ .map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")),
_ => None,
};
early_error(ErrorOutputType::default(), &msg.unwrap_or_else(|| e.to_string()));
} else {
result.push(a.to_string());
match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| option == **s) {
- Some(s) => result.push(format!("{}=[REDACTED]", s)),
+ Some(s) => result.push(format!("{s}=[REDACTED]")),
None => result.push(content),
}
}
};
// Invoke the default handler, which prints the actual panic message and optionally a backtrace
- // Don't do this for `ExplicitBug`, which has an unhelpful message and backtrace.
- if !info.payload().is::<rustc_errors::ExplicitBug>() {
+ // Don't do this for `GoodPathBug`, which already emits its own more useful backtrace.
+ if !info.payload().is::<rustc_errors::GoodPathBug>() {
(*DEFAULT_HOOK)(info);
// Separate the output with an empty line
// a .span_bug or .bug call has already printed what
// it wants to print.
- if !info.payload().is::<rustc_errors::ExplicitBug>() {
+ if !info.payload().is::<rustc_errors::ExplicitBug>()
+ && !info.payload().is::<rustc_errors::GoodPathBug>()
+ {
let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
handler.emit_diagnostic(&mut d);
}
let mut xs: Vec<Cow<'static, str>> = vec![
"the compiler unexpectedly panicked. this is a bug.".into(),
- format!("we would appreciate a bug report: {}", bug_report_url).into(),
+ format!("we would appreciate a bug report: {bug_report_url}").into(),
format!(
"rustc {} running on {}",
util::version_str!().unwrap_or("unknown_version"),
arg.into_string().unwrap_or_else(|arg| {
early_error(
ErrorOutputType::default(),
- &format!("argument {} is not valid Unicode: {:?}", i, arg),
+ &format!("argument {i} is not valid Unicode: {arg:?}"),
)
})
})
fn write_or_print(out: &str, ofile: Option<&Path>, sess: &Session) {
match ofile {
- None => print!("{}", out),
+ None => print!("{out}"),
Some(p) => {
if let Err(e) = std::fs::write(p, out) {
sess.emit_fatal(UnprettyDumpFail {
}
AstTree(PpAstTreeMode::Normal) => {
debug!("pretty printing AST tree");
- format!("{:#?}", krate)
+ format!("{krate:#?}")
}
_ => unreachable!(),
};
AstTree(PpAstTreeMode::Expanded) => {
debug!("pretty-printing expanded AST");
- format!("{:#?}", krate)
+ format!("{krate:#?}")
}
Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| {
E0205: include_str!("./error_codes/E0205.md"),
E0206: include_str!("./error_codes/E0206.md"),
E0207: include_str!("./error_codes/E0207.md"),
+E0208: include_str!("./error_codes/E0208.md"),
E0210: include_str!("./error_codes/E0210.md"),
E0211: include_str!("./error_codes/E0211.md"),
E0212: include_str!("./error_codes/E0212.md"),
E0458: include_str!("./error_codes/E0458.md"),
E0459: include_str!("./error_codes/E0459.md"),
E0460: include_str!("./error_codes/E0460.md"),
+E0461: include_str!("./error_codes/E0461.md"),
E0462: include_str!("./error_codes/E0462.md"),
E0463: include_str!("./error_codes/E0463.md"),
E0464: include_str!("./error_codes/E0464.md"),
E0510: include_str!("./error_codes/E0510.md"),
E0511: include_str!("./error_codes/E0511.md"),
E0512: include_str!("./error_codes/E0512.md"),
+E0514: include_str!("./error_codes/E0514.md"),
E0515: include_str!("./error_codes/E0515.md"),
E0516: include_str!("./error_codes/E0516.md"),
E0517: include_str!("./error_codes/E0517.md"),
E0518: include_str!("./error_codes/E0518.md"),
+E0519: include_str!("./error_codes/E0519.md"),
E0520: include_str!("./error_codes/E0520.md"),
E0521: include_str!("./error_codes/E0521.md"),
E0522: include_str!("./error_codes/E0522.md"),
E0637: include_str!("./error_codes/E0637.md"),
E0638: include_str!("./error_codes/E0638.md"),
E0639: include_str!("./error_codes/E0639.md"),
+E0640: include_str!("./error_codes/E0640.md"),
E0641: include_str!("./error_codes/E0641.md"),
E0642: include_str!("./error_codes/E0642.md"),
E0643: include_str!("./error_codes/E0643.md"),
E0714: include_str!("./error_codes/E0714.md"),
E0715: include_str!("./error_codes/E0715.md"),
E0716: include_str!("./error_codes/E0716.md"),
+E0711: include_str!("./error_codes/E0711.md"),
+E0717: include_str!("./error_codes/E0717.md"),
E0718: include_str!("./error_codes/E0718.md"),
E0719: include_str!("./error_codes/E0719.md"),
E0720: include_str!("./error_codes/E0720.md"),
// E0190, // deprecated: can only cast a &-pointer to an &-object
// E0194, // merged into E0403
// E0196, // cannot determine a type for this closure
- E0208, // internal error code
// E0209, // builtin traits can only be implemented on structs or enums
// E0213, // associated types are not accepted in this context
// E0215, // angle-bracket notation is not stable with `Fn`
// E0300, // unexpanded macro
// E0304, // expected signed integer constant
// E0305, // expected constant
- E0313, // lifetime of borrowed pointer outlives lifetime of captured
- // variable
+// E0313, // removed: found unreachable
// E0314, // closure outlives stack frame
// E0315, // cannot invoke closure outside of its lifetime
// E0319, // trait impls for defaulted traits allowed just for structs/enums
// E0421, // merged into 531
// E0427, // merged into 530
// E0456, // plugin `..` is not available for triple `..`
- E0461, // couldn't find crate `..` with expected target triple ..
- E0465, // multiple .. candidates for `..` found
+// E0465, // removed: merged with E0464
// E0467, // removed
// E0470, // removed
// E0471, // constant evaluation error (in pattern)
// E0488, // lifetime of variable does not enclose its declaration
// E0489, // type/lifetime parameter not in scope here
E0490, // a value of type `..` is borrowed for too long
- E0514, // metadata version mismatch
- E0519, // local crate and dependency have same (crate-name, disambiguator)
E0523, // two dependencies have same (crate-name, disambiguator) but different SVH
// E0526, // shuffle indices are not constant
// E0540, // multiple rustc_deprecated attributes
// E0629, // missing 'feature' (rustc_const_unstable)
// E0630, // rustc_const_unstable attribute must be paired with stable/unstable
// attribute
- E0640, // infer outlives requirements, internal error code
// E0645, // trait aliases not finished
// E0694, // an unknown tool name found in scoped attributes
// E0702, // replaced with a generic attribute input check
// E0707, // multiple elided lifetimes used in arguments of `async fn`
// E0709, // multiple different lifetimes used in arguments of `async fn`
- E0711, // a feature has been declared with conflicting stability attributes, internal error code
- E0717, // rustc_promotable without stability attribute, internal error code
// E0721, // `await` keyword
// E0723, // unstable feature in `const` context
// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
-A constant item was initialized with something that is not a constant
-expression.
+A non-`const` function was called in a `const` context.
Erroneous code example:
Some(1)
}
-const FOO: Option<u8> = create_some(); // error!
+// error: cannot call non-const fn `create_some` in constants
+const FOO: Option<u8> = create_some();
```
-The only functions that can be called in static or constant expressions are
-`const` functions, and struct/enum constructors.
+All functions used in a `const` context (constant or static expression) must
+be marked `const`.
To fix this error, you can declare `create_some` as a constant function:
```
-const fn create_some() -> Option<u8> { // declared as a const function
+// declared as a `const` function:
+const fn create_some() -> Option<u8> {
Some(1)
}
-const FOO: Option<u8> = create_some(); // ok!
-
-// These are also working:
-struct Bar {
- x: u8,
-}
-
-const OTHER_FOO: Option<u8> = Some(1);
-const BAR: Bar = Bar {x: 1};
+const FOO: Option<u8> = create_some(); // no error!
```
--- /dev/null
+#### This error code is internal to the compiler and will not be emitted with normal Rust code.
--- /dev/null
+Couldn't find crate `..` with expected target triple `..`.
+
+Example of erroneous code:
+
+`a.rs`
+```ignore (cannot-link-with-other-tests)
+#![crate_type = "lib"]
+
+fn foo() {}
+```
+
+`main.rs`
+```ignore (cannot-link-with-other-tests)
+extern crate a;
+
+fn main() {
+ a::foo();
+}
+```
+
+`a.rs` is then compiled with `--target powerpc-unknown-linux-gnu` and `b.rs`
+with `--target x86_64-unknown-linux-gnu`. `a.rs` is compiled into a binary
+format incompatible with `b.rs`; PowerPC and x86 are totally different
+architectures. This issue also extends to any difference in target triples, as
+`std` is operating-system specific.
+
+This error can be fixed by:
+ * Using [Cargo](../cargo/index.html), the Rust package manager, automatically
+ fixing this issue.
+ * Recompiling either crate so that they target a consistent target triple.
--- /dev/null
+Dependency compiled with different version of `rustc`.
+
+Example of erroneous code:
+
+`a.rs`
+```ignore (cannot-link-with-other-tests)
+// compiled with stable `rustc`
+
+#[crate_type = "lib"]
+```
+
+`b.rs`
+```ignore (cannot-link-with-other-tests)
+// compiled with nightly `rustc`
+
+#[crate_type = "lib"]
+
+extern crate a; // error: found crate `a` compiled by an incompatible version
+ // of rustc
+```
+
+This error is caused when the version of `rustc` used to compile a crate, as
+stored in the binary's metadata, differs from the version of one of its
+dependencies. Many parts of Rust binaries are considered unstable. For
+instance, the Rust ABI is not stable between compiler versions. This means that
+the compiler cannot be sure about *how* to call a function between compiler
+versions, and therefore this error occurs.
+
+This error can be fixed by:
+ * Using [Cargo](../cargo/index.html), the Rust package manager and
+ [Rustup](https://rust-lang.github.io/rustup/), the Rust toolchain installer,
+ automatically fixing this issue.
+ * Recompiling the crates with a uniform `rustc` version.
--- /dev/null
+The current crate is indistinguishable from one of its dependencies, in terms
+of metadata.
+
+Example of erroneous code:
+
+`a.rs`
+```ignore (cannot-link-with-other-tests)
+#![crate_name = "a"]
+#![crate_type = "lib"]
+
+pub fn foo() {}
+```
+
+`b.rs`
+```ignore (cannot-link-with-other-tests)
+#![crate_name = "a"]
+#![crate_type = "lib"]
+
+// error: the current crate is indistinguishable from one of its dependencies:
+// it has the same crate-name `a` and was compiled with the same
+// `-C metadata` arguments. This will result in symbol conflicts between
+// the two.
+extern crate a;
+
+pub fn foo() {}
+
+fn bar() {
+ a::foo(); // is this calling the local crate or the dependency?
+}
+```
+
+The above example compiles two crates with exactly the same name and
+`crate_type` (plus any other metadata). This causes an error because it becomes
+impossible for the compiler to distinguish between symbols (`pub` item names).
+
+This error can be fixed by:
+ * Using [Cargo](../cargo/index.html), the Rust package manager, automatically
+ fixing this issue.
+ * Recompiling the crate with different metadata (different name/
+ `crate_type`).
struct Packed(Aligned);
```
-Just like you cannot have both `align` and `packed` representation hints on a
+Just like you cannot have both `align` and `packed` representation hints on the
same type, a `packed` type cannot contain another type with the `align`
representation hint. However, you can do the opposite:
--- /dev/null
+#### This error code is internal to the compiler and will not be emitted with normal Rust code.
--- /dev/null
+#### This error code is internal to the compiler and will not be emitted with normal Rust code.
+
+Feature declared with conflicting stability requirements.
+
+```compile_fail,E0711
+// NOTE: this attribute is perma-unstable and should *never* be used outside of
+// stdlib and the compiler.
+#![feature(staged_api)]
+
+#![stable(feature = "...", since = "1.0.0")]
+
+#[stable(feature = "foo", since = "1.0.0")]
+fn foo_stable_1_0_0() {}
+
+// error: feature `foo` is declared stable since 1.29.0
+#[stable(feature = "foo", since = "1.29.0")]
+fn foo_stable_1_29_0() {}
+
+// error: feature `foo` is declared unstable
+#[unstable(feature = "foo", issue = "none")]
+fn foo_unstable() {}
+```
+
+In the above example, the `foo` feature is first defined to be stable since
+1.0.0, but is then re-declared stable since 1.29.0. This discrepancy in
+versions causes an error. Furthermore, `foo` is then re-declared as unstable,
+again the conflict causes an error.
+
+This error can be fixed by splitting the feature, this allows any
+stability requirements and removes any possibility of conflict.
--- /dev/null
+#### This error code is internal to the compiler and will not be emitted with normal Rust code.
+#### Note: this error code is no longer emitted by the compiler
+
Support for Non-Lexical Lifetimes (NLL) has been included in the Rust compiler
since 1.31, and has been enabled on the 2015 edition since 1.36. The new borrow
checker for NLL uncovered some bugs in the old borrow checker, which in some
codegen_ssa_static_library_native_artifacts = Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.
-codegen_ssa_native_static_libs = native-static-libs: {$arguments}
-
codegen_ssa_link_script_unavailable = can only use link script when linking with GNU-like linker
codegen_ssa_link_script_write_failure = failed to write link script to {$path}: {$error}
Don't know how to build archive of type: {$kind}
codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
+
+codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times
+ .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
+
+codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error}
+
+codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed
+
+codegen_ssa_erroneous_constant = erroneous constant encountered
+
+codegen_ssa_shuffle_indices_evaluation = could not evaluate shuffle_indices at compile time
+
+codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering
+
+codegen_ssa_unknown_atomic_ordering = unknown ordering in atomic intrinsic
+
+codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering
+
+codegen_ssa_unknown_atomic_operation = unknown atomic operation
+
+codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}`
+
+codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}`
+
+codegen_ssa_invalid_monomorphization_float_to_int_unchecked = invalid monomorphization of `float_to_int_unchecked` intrinsic: expected basic float type, found `{$ty}`
+
+codegen_ssa_invalid_monomorphization_floating_point_vector = invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$f_ty}` of floating-point vector `{$in_ty}`
+
+codegen_ssa_invalid_monomorphization_floating_point_type = invalid monomorphization of `{$name}` intrinsic: `{$in_ty}` is not a floating-point type
+
+codegen_ssa_invalid_monomorphization_unrecognized_intrinsic = invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`
+
+codegen_ssa_invalid_monomorphization_simd_argument = invalid monomorphization of `{$name}` intrinsic: expected SIMD argument type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_input = invalid monomorphization of `{$name}` intrinsic: expected SIMD input type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_first = invalid monomorphization of `{$name}` intrinsic: expected SIMD first type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_second = invalid monomorphization of `{$name}` intrinsic: expected SIMD second type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of `{$name}` intrinsic: expected SIMD return type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$mask_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
+
+codegen_ssa_polymorphic_constant_too_generic = codegen encountered polymorphic constant: TooGeneric
+
+codegen_ssa_invalid_monomorphization_return_length_input_type = invalid monomorphization of `{$name}` intrinsic: expected return type with length {$in_len} (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_len}
+
+codegen_ssa_invalid_monomorphization_second_argument_length = invalid monomorphization of `{$name}` intrinsic: expected second argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
+
+codegen_ssa_invalid_monomorphization_third_argument_length = invalid monomorphization of `{$name}` intrinsic: expected third argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
+
+codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}`
+
+codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}`
+
+codegen_ssa_invalid_monomorphization_return_length = invalid monomorphization of `{$name}` intrinsic: expected return type of length {$in_len}, found `{$ret_ty}` with length {$out_len}
+
+codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}`
+
+codegen_ssa_invalid_monomorphization_shuffle_index_not_constant = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is not a constant
+
+codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is out of bounds (limit {$total_len})
+
+codegen_ssa_invalid_monomorphization_inserted_type = invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}`
+
+codegen_ssa_invalid_monomorphization_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}`
+
+codegen_ssa_invalid_monomorphization_expected_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_ty}`, found `{$ret_ty}`
+
+codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
+
+codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_`
+
+codegen_ssa_invalid_monomorphization_vector_argument = invalid monomorphization of `{$name}` intrinsic: vector argument `{$in_ty}`'s element type `{$in_elem}`, expected integer element type
+
+codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
+
+codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}`
+
+codegen_ssa_invalid_monomorphization_third_arg_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of third argument `{$third_arg}` to be a signed integer type
+
+codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}`
+
+codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}`
+
+codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}`
+
+codegen_ssa_invalid_monomorphization_expected_pointer = invalid monomorphization of `{$name}` intrinsic: expected pointer, got `{$ty}`
+
+codegen_ssa_invalid_monomorphization_expected_usize = invalid monomorphization of `{$name}` intrinsic: expected `usize`, got `{$ty}`
+
+codegen_ssa_invalid_monomorphization_unsupported_cast = invalid monomorphization of `{$name}` intrinsic: unsupported cast from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` with element `{$out_elem}`
+
+codegen_ssa_invalid_monomorphization_unsupported_operation = invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}`
+
+codegen_ssa_invalid_monomorphization_expected_vector_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of vector type `{$vector_type}` to be a signed or unsigned integer type
infer_msl_trait_note = this has an implicit `'static` lifetime requirement
infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement
infer_suggest_add_let_for_letchains = consider adding `let`
+
+infer_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}`
+ .label = lifetime `{$named}` required
+
+infer_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type
+ .label = lifetime `{$named}` required
+
+infer_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}`
+
+infer_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type
+
+infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis ->
+ [true] ...
+ *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
+infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis ->
+ [true] ...
+ *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis ->
+ [true] ...
+ *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`...
+infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis ->
+ [true] ...
+ *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`
+infer_actual_impl_expl_expected_passive_two = {$leading_ellipsis ->
+ [true] ...
+ *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
+infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis ->
+ [true] ...
+ *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis ->
+ [true] ...
+ *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{lifetime_1}`...
+infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis ->
+ [true] ...
+ *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`
+infer_actual_impl_expl_expected_other_two = {$leading_ellipsis ->
+ [true] ...
+ *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
+infer_actual_impl_expl_expected_other_any = {$leading_ellipsis ->
+ [true] ...
+ *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_other_some = {$leading_ellipsis ->
+ [true] ...
+ *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`...
+infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis ->
+ [true] ...
+ *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`
+
+infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime ->
+ [true] , for some specific lifetime `'{$lifetime}`
+ *[false] {""}
+}
+infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime ->
+ [true] , for some specific lifetime `'{$lifetime}`
+ *[false] {""}
+}
+infer_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime ->
+ [true] , for some specific lifetime `'{$lifetime}`
+ *[false] {""}
+}
+
+infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough
+ .label_satisfy = doesn't satisfy where-clause
+ .label_where = due to a where-clause on `{$def_id}`...
+ .label_dup = implementation of `{$trait_def_id}` is not general enough
+
+infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signature
+ .found = found `{$found}`
+ .expected = expected `{$expected}`
+ .expected_found = expected signature `{$expected}`
+ {" "}found signature `{$found}`
+
+infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
+infer_tid_consider_borrowing = consider borrowing this type parameter in the trait
+infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+
+infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement
+infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s 'static` requirement
+infer_dtcs_has_req_note = the used `impl` has a `'static` requirement
+infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement
+
+infer_but_calling_introduces = {$has_param_name ->
+ [true] `{$param_name}`
+ *[false] `fn` parameter
+} has {$lifetime_kind ->
+ [named] lifetime `{lifetime}`
+ *[anon] an anonymous lifetime `'_`
+} but calling `{assoc_item}` introduces an implicit `'static` lifetime requirement
+ .label1 = {$has_lifetime ->
+ [named] lifetime `{lifetime}`
+ *[anon] an anonymous lifetime `'_`
+ }
+ .label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path ->
+ [named] `impl` of `{$impl_path}`
+ *[anon] inherent `impl`
+ }
+
+infer_but_needs_to_satisfy = {$has_param_name ->
+ [true] `{$param_name}`
+ *[false] `fn` parameter
+} has {$has_lifetime ->
+ [named] lifetime `{lifetime}`
+ *[anon] an anonymous lifetime `'_`
+} but it needs to satisfy a `'static` lifetime requirement
+ .influencer = this data with {$has_lifetime ->
+ [named] lifetime `{lifetime}`
+ *[anon] an anonymous lifetime `'_`
+ }...
+ .require = {$spans_empty ->
+ *[true] ...is used and required to live as long as `'static` here
+ [false] ...and is required to live as long as `'static` here
+ }
+ .used_here = ...is used here...
+ .introduced_by_bound = 'static` lifetime requirement introduced by this bound
+
+infer_more_targeted = {$has_param_name ->
+ [true] `{$param_name}`
+ *[false] `fn` parameter
+} has {$has_lifetime ->
+ [named] lifetime `{lifetime}`
+ *[anon] an anonymous lifetime `'_`
+} but calling `{$ident}` introduces an implicit `'static` lifetime requirement
+
+infer_ril_introduced_here = `'static` requirement introduced here
+infer_ril_introduced_by = requirement introduced by this return type
+infer_ril_because_of = because of this returned expression
+infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type
metadata_lib_required =
crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
+metadata_rustc_lib_required =
+ crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
+ .note = only .rmeta files are distributed for `rustc_private` crates other than `rustc_driver`
+ .help = try adding `extern crate rustc_driver;` at the top level of this crate
+
metadata_crate_dep_multiple =
cannot satisfy dependencies so `{$crate_name}` only shows up once
.help = having upstream crates all available in one format will likely make this go away
extern location for {$crate_name} is not a file: {$location}
metadata_multiple_candidates =
- multiple {$flavor} candidates for `{$crate_name}` found
-
-metadata_multiple_matching_crates =
- multiple matching crates for `{$crate_name}`
- .note = candidates:{$candidates}
+ multiple candidates for `{$flavor}` dependency `{$crate_name}` found
metadata_symbol_conflicts_current =
the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two.
parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn`
.suggestion = replace `fn` with `impl` here
+
+parse_expected_fn_path_found_fn_keyword = expected identifier, found keyword `fn`
+ .suggestion = use `Fn` to refer to the trait
.help = valid suffixes are `f32` and `f64`
session_int_literal_too_large = integer literal is too large
+ .note = value exceeds limit of `{$limit}`
session_invalid_int_literal_width = invalid width `{$width}` for integer literal
.help = valid widths are 8, 16, 32, 64 and 128
rustc_target = { path = "../rustc_target" }
rustc_hir = { path = "../rustc_hir" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
+rustc_type_ir = { path = "../rustc_type_ir" }
unicode-width = "0.1.4"
termcolor = "1.0"
annotate-snippets = "0.9"
self
}
- pub fn replace_span_with(&mut self, after: Span) -> &mut Self {
+ pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
let before = self.span.clone();
self.set_span(after);
for span_label in before.span_labels() {
if let Some(label) = span_label.label {
- if span_label.is_primary {
+ if span_label.is_primary && keep_label {
self.span.push_span_label(after, label);
} else {
self.span.push_span_label(span_label.span, label);
use crate::diagnostic::IntoDiagnosticArg;
use crate::{
Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed,
- SubdiagnosticMessage,
+ ExplicitBug, SubdiagnosticMessage,
};
use crate::{Handler, Level, MultiSpan, StashKey};
use rustc_lint_defs::Applicability;
use std::fmt::{self, Debug};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
+use std::panic;
use std::thread::panicking;
/// Trait implemented by error types. This should not be implemented manually. Instead, use
}
}
+/// Marker type which enables implementation of `create_bug` and `emit_bug` functions for
+/// bug struct diagnostics.
+#[derive(Copy, Clone)]
+pub struct Bug;
+
+impl<'a> DiagnosticBuilder<'a, Bug> {
+ /// Convenience function for internal use, clients should use one of the
+ /// `struct_*` methods on [`Handler`].
+ #[track_caller]
+ pub(crate) fn new_bug(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
+ let diagnostic = Diagnostic::new_with_code(Level::Bug, None, message);
+ Self::new_diagnostic_bug(handler, diagnostic)
+ }
+
+ /// Creates a new `DiagnosticBuilder` with an already constructed
+ /// diagnostic.
+ pub(crate) fn new_diagnostic_bug(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
+ debug!("Created new diagnostic bug");
+ Self {
+ inner: DiagnosticBuilderInner {
+ state: DiagnosticBuilderState::Emittable(handler),
+ diagnostic: Box::new(diagnostic),
+ },
+ _marker: PhantomData,
+ }
+ }
+}
+
+impl EmissionGuarantee for Bug {
+ fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
+ match db.inner.state {
+ // First `.emit()` call, the `&Handler` is still available.
+ DiagnosticBuilderState::Emittable(handler) => {
+ db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
+
+ handler.emit_diagnostic(&mut db.inner.diagnostic);
+ }
+ // `.emit()` was previously called, disallowed from repeating it.
+ DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
+ }
+ // Then panic. No need to return the marker type.
+ panic::panic_any(ExplicitBug);
+ }
+
+ fn make_diagnostic_builder(
+ handler: &Handler,
+ msg: impl Into<DiagnosticMessage>,
+ ) -> DiagnosticBuilder<'_, Self> {
+ DiagnosticBuilder::new_bug(handler, msg)
+ }
+}
+
impl<'a> DiagnosticBuilder<'a, !> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
use rustc_target::abi::TargetDataLayoutErrors;
use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
+use rustc_type_ir as type_ir;
use std::borrow::Cow;
use std::fmt;
use std::num::ParseIntError;
}
}
+impl IntoDiagnosticArg for type_ir::FloatTy {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Borrowed(self.name_str()))
+ }
+}
+
impl IntoDiagnosticArg for Level {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Borrowed(match self {
// 3 | |
// 4 | | }
// | |_^ test
- if let [ann] = &line.annotations[..] {
+ let mut buffer_ops = vec![];
+ let mut annotations = vec![];
+ let mut short_start = true;
+ for ann in &line.annotations {
if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) {
let style = if ann.is_primary {
} else {
Style::UnderlineSecondary
};
- buffer.putc(line_offset, width_offset + depth - 1, '/', style);
- return vec![(depth, style)];
+ annotations.push((depth, style));
+ buffer_ops.push((line_offset, width_offset + depth - 1, '/', style));
+ } else {
+ short_start = false;
+ break;
}
+ } else if let AnnotationType::MultilineLine(_) = ann.annotation_type {
+ } else {
+ short_start = false;
+ break;
+ }
+ }
+ if short_start {
+ for (y, x, c, s) in buffer_ops {
+ buffer.putc(y, x, c, s);
}
+ return annotations;
}
// We want to display like this:
use rustc_span::HashStableContext;
use rustc_span::{Loc, Span};
+use std::any::Any;
use std::borrow::Cow;
+use std::fmt;
use std::hash::Hash;
use std::num::NonZeroUsize;
use std::panic;
use std::path::Path;
-use std::{error, fmt};
use termcolor::{Color, ColorSpec};
/// Signifies that the compiler died with an explicit call to `.bug`
/// or `.span_bug` rather than a failed assertion, etc.
-#[derive(Copy, Clone, Debug)]
pub struct ExplicitBug;
-impl fmt::Display for ExplicitBug {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "parser internal bug")
- }
-}
-
-impl error::Error for ExplicitBug {}
+/// Signifies that the compiler died with an explicit call to `.delay_good_path_bug`
+/// rather than a failed assertion, etc.
+pub struct GoodPathBug;
pub use diagnostic::{
AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
CallAssocMethod,
}
-fn default_track_diagnostic(_: &Diagnostic) {}
+fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
+ (*f)(d)
+}
-pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&Diagnostic)> =
- AtomicRef::new(&(default_track_diagnostic as fn(&_)));
+pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&mut Diagnostic, &mut dyn FnMut(&mut Diagnostic))> =
+ AtomicRef::new(&(default_track_diagnostic as _));
#[derive(Copy, Clone, Default)]
pub struct HandlerFlags {
if !self.has_errors() {
let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new());
- self.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued");
+ self.flush_delayed(
+ bugs,
+ "no errors encountered even though `delay_span_bug` issued",
+ ExplicitBug,
+ );
}
// FIXME(eddyb) this explains what `delayed_good_path_bugs` are!
self.flush_delayed(
bugs.into_iter().map(DelayedDiagnostic::decorate),
"no warnings or errors encountered even though `delayed_good_path_bugs` issued",
+ GoodPathBug,
);
}
/// Retrieve a stashed diagnostic with `steal_diagnostic`.
pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
let mut inner = self.inner.borrow_mut();
- inner.stash((span, key), diag);
+ inner.stash((span.with_parent(None), key), diag);
}
/// Steal a previously stashed diagnostic with the given `Span` and [`StashKey`] as the key.
pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> {
let mut inner = self.inner.borrow_mut();
- inner.steal((span, key)).map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
+ inner
+ .steal((span.with_parent(None), key))
+ .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
}
pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
- self.inner.borrow().stashed_diagnostics.get(&(span, key)).is_some()
+ self.inner.borrow().stashed_diagnostics.get(&(span.with_parent(None), key)).is_some()
}
/// Emit all stashed diagnostics.
self.inner.borrow_mut().span_bug(span, msg)
}
+ /// For documentation on this, see `Session::delay_span_bug`.
#[track_caller]
pub fn delay_span_bug(
&self,
self.create_fatal(fatal).emit()
}
+ pub fn create_bug<'a>(
+ &'a self,
+ bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>,
+ ) -> DiagnosticBuilder<'a, diagnostic_builder::Bug> {
+ bug.into_diagnostic(self)
+ }
+
+ pub fn emit_bug<'a>(
+ &'a self,
+ bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>,
+ ) -> diagnostic_builder::Bug {
+ self.create_bug(bug).emit()
+ }
+
fn emit_diag_at_span(
&self,
mut diag: Diagnostic,
pub fn flush_delayed(&self) {
let mut inner = self.inner.lock();
let bugs = std::mem::replace(&mut inner.delayed_span_bugs, Vec::new());
- inner.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued");
+ inner.flush_delayed(
+ bugs,
+ "no errors encountered even though `delay_span_bug` issued",
+ ExplicitBug,
+ );
}
}
&& !diagnostic.is_force_warn()
{
if diagnostic.has_future_breakage() {
- (*TRACK_DIAGNOSTICS)(diagnostic);
+ (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
}
return None;
}
- (*TRACK_DIAGNOSTICS)(diagnostic);
-
if matches!(diagnostic.level, Level::Expect(_) | Level::Allow) {
+ (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
return None;
}
- if let Some(ref code) = diagnostic.code {
- self.emitted_diagnostic_codes.insert(code.clone());
- }
-
- let already_emitted = |this: &mut Self| {
- let mut hasher = StableHasher::new();
- diagnostic.hash(&mut hasher);
- let diagnostic_hash = hasher.finish();
- !this.emitted_diagnostics.insert(diagnostic_hash)
- };
+ let mut guaranteed = None;
+ (*TRACK_DIAGNOSTICS)(diagnostic, &mut |diagnostic| {
+ if let Some(ref code) = diagnostic.code {
+ self.emitted_diagnostic_codes.insert(code.clone());
+ }
- // Only emit the diagnostic if we've been asked to deduplicate or
- // haven't already emitted an equivalent diagnostic.
- if !(self.flags.deduplicate_diagnostics && already_emitted(self)) {
- debug!(?diagnostic);
- debug!(?self.emitted_diagnostics);
- let already_emitted_sub = |sub: &mut SubDiagnostic| {
- debug!(?sub);
- if sub.level != Level::OnceNote {
- return false;
- }
+ let already_emitted = |this: &mut Self| {
let mut hasher = StableHasher::new();
- sub.hash(&mut hasher);
+ diagnostic.hash(&mut hasher);
let diagnostic_hash = hasher.finish();
- debug!(?diagnostic_hash);
- !self.emitted_diagnostics.insert(diagnostic_hash)
+ !this.emitted_diagnostics.insert(diagnostic_hash)
};
- diagnostic.children.drain_filter(already_emitted_sub).for_each(|_| {});
-
- self.emitter.emit_diagnostic(diagnostic);
- if diagnostic.is_error() {
- self.deduplicated_err_count += 1;
- } else if let Warning(_) = diagnostic.level {
- self.deduplicated_warn_count += 1;
+ // Only emit the diagnostic if we've been asked to deduplicate or
+ // haven't already emitted an equivalent diagnostic.
+ if !(self.flags.deduplicate_diagnostics && already_emitted(self)) {
+ debug!(?diagnostic);
+ debug!(?self.emitted_diagnostics);
+ let already_emitted_sub = |sub: &mut SubDiagnostic| {
+ debug!(?sub);
+ if sub.level != Level::OnceNote {
+ return false;
+ }
+ let mut hasher = StableHasher::new();
+ sub.hash(&mut hasher);
+ let diagnostic_hash = hasher.finish();
+ debug!(?diagnostic_hash);
+ !self.emitted_diagnostics.insert(diagnostic_hash)
+ };
+
+ diagnostic.children.drain_filter(already_emitted_sub).for_each(|_| {});
+
+ self.emitter.emit_diagnostic(diagnostic);
+ if diagnostic.is_error() {
+ self.deduplicated_err_count += 1;
+ } else if let Warning(_) = diagnostic.level {
+ self.deduplicated_warn_count += 1;
+ }
}
- }
- if diagnostic.is_error() {
- if matches!(diagnostic.level, Level::Error { lint: true }) {
- self.bump_lint_err_count();
+ if diagnostic.is_error() {
+ if matches!(diagnostic.level, Level::Error { lint: true }) {
+ self.bump_lint_err_count();
+ } else {
+ self.bump_err_count();
+ }
+
+ guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
} else {
- self.bump_err_count();
+ self.bump_warn_count();
}
+ });
- Some(ErrorGuaranteed::unchecked_claim_error_was_emitted())
- } else {
- self.bump_warn_count();
-
- None
- }
+ guaranteed
}
fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
self.emit_diagnostic(diag.set_span(sp));
}
+ /// For documentation on this, see `Session::delay_span_bug`.
#[track_caller]
fn delay_span_bug(
&mut self,
&mut self,
bugs: impl IntoIterator<Item = Diagnostic>,
explanation: impl Into<DiagnosticMessage> + Copy,
+ panic_with: impl Any + Send + 'static,
) {
let mut no_bugs = true;
for mut bug in bugs {
// Panic with `ExplicitBug` to avoid "unexpected panic" messages.
if !no_bugs {
- panic::panic_any(ExplicitBug);
+ panic::panic_any(panic_with);
}
}
self.anon_const(span, ast::ExprKind::Path(None, self.path_ident(span, ident)))
}
- pub fn ty_rptr(
+ pub fn ty_ref(
&self,
span: Span,
ty: P<ast::Ty>,
lifetime: Option<ast::Lifetime>,
mutbl: ast::Mutability,
) -> P<ast::Ty> {
- self.ty(span, ast::TyKind::Rptr(lifetime, self.ty_mt(ty, mutbl)))
+ self.ty(span, ast::TyKind::Ref(lifetime, self.ty_mt(ty, mutbl)))
}
pub fn ty_ptr(&self, span: Span, ty: P<ast::Ty>, mutbl: ast::Mutability) -> P<ast::Ty> {
// Builds `#[name = val]`.
//
- // Note: `span` is used for both the identifer and the value.
+ // Note: `span` is used for both the identifier and the value.
pub fn attr_name_value_str(&self, name: Symbol, val: Symbol, span: Span) -> ast::Attribute {
let g = &self.sess.parse_sess.attr_id_generator;
attr::mk_attr_name_value_str(g, ast::AttrStyle::Outer, name, val, span)
.resolver
.visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment);
- if self.cx.sess.opts.unstable_opts.incremental_relative_spans {
+ if self.cx.sess.opts.incremental_relative_spans() {
for (invoc, _) in invocations.iter_mut() {
let expn_id = invoc.expansion_data.id;
let parent_def = self.cx.resolver.invocation_parent(expn_id);
return result;
}
- let Some((token, label, remaining_matcher)) = tracker.best_failure else {
+ let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure else {
return DummyResult::any(sp);
};
cx: &'a mut ExtCtxt<'cx>,
remaining_matcher: Option<&'matcher MatcherLoc>,
/// Which arm's failure should we report? (the one furthest along)
- best_failure: Option<(Token, &'static str, MatcherLoc)>,
+ best_failure: Option<BestFailure>,
root_span: Span,
result: Option<Box<dyn MacResult + 'cx>>,
}
+struct BestFailure {
+ token: Token,
+ position_in_tokenstream: usize,
+ msg: &'static str,
+ remaining_matcher: MatcherLoc,
+}
+
+impl BestFailure {
+ fn is_better_position(&self, position: usize) -> bool {
+ position > self.position_in_tokenstream
+ }
+}
+
impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
+ type Failure = (Token, usize, &'static str);
+
+ fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure {
+ (tok, position, msg)
+ }
+
fn before_match_loc(&mut self, parser: &TtParser, matcher: &'matcher MatcherLoc) {
if self.remaining_matcher.is_none()
|| (parser.has_no_remaining_items_for_step() && *matcher != MatcherLoc::Eof)
}
}
- fn after_arm(&mut self, result: &NamedParseResult) {
+ fn after_arm(&mut self, result: &NamedParseResult<Self::Failure>) {
match result {
Success(_) => {
// Nonterminal parser recovery might turn failed matches into successful ones,
"should not collect detailed info for successful macro match",
);
}
- Failure(token, msg) => match self.best_failure {
- Some((ref best_token, _, _)) if best_token.span.lo() >= token.span.lo() => {}
- _ => {
- self.best_failure = Some((
- token.clone(),
+ Failure((token, approx_position, msg)) => {
+ debug!(?token, ?msg, "a new failure of an arm");
+
+ if self
+ .best_failure
+ .as_ref()
+ .map_or(true, |failure| failure.is_better_position(*approx_position))
+ {
+ self.best_failure = Some(BestFailure {
+ token: token.clone(),
+ position_in_tokenstream: *approx_position,
msg,
- self.remaining_matcher
+ remaining_matcher: self
+ .remaining_matcher
.expect("must have collected matcher already")
.clone(),
- ))
+ })
}
- },
+ }
Error(err_sp, msg) => {
let span = err_sp.substitute_dummy(self.root_span);
self.cx.struct_span_err(span, msg).emit();
}
}
+/// Currently used by macro_rules! compilation to extract a little information from the `Failure` case.
+pub struct FailureForwarder;
+
+impl<'matcher> Tracker<'matcher> for FailureForwarder {
+ type Failure = (Token, usize, &'static str);
+
+ fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure {
+ (tok, position, msg)
+ }
+
+ fn description() -> &'static str {
+ "failure-forwarder"
+ }
+}
+
pub(super) fn emit_frag_parse_err(
mut e: DiagnosticBuilder<'_, rustc_errors::ErrorGuaranteed>,
parser: &Parser<'_>,
);
if !e.span.is_dummy() {
// early end of macro arm (#52866)
- e.replace_span_with(parser.token.span.shrink_to_hi());
+ e.replace_span_with(parser.token.span.shrink_to_hi(), true);
}
}
if e.span.is_dummy() {
// Get around lack of span in error (#30128)
- e.replace_span_with(site_span);
+ e.replace_span_with(site_span, true);
if !parser.sess.source_map().is_imported(arm_span) {
e.span_label(arm_span, "in this macro arm");
}
}
/// Represents the possible results of an attempted parse.
-pub(crate) enum ParseResult<T> {
+pub(crate) enum ParseResult<T, F> {
/// Parsed successfully.
Success(T),
/// Arm failed to match. If the second parameter is `token::Eof`, it indicates an unexpected
/// end of macro invocation. Otherwise, it indicates that no rules expected the given token.
- Failure(Token, &'static str),
+ /// The usize is the approximate position of the token in the input token stream.
+ Failure(F),
/// Fatal error (malformed macro?). Abort compilation.
Error(rustc_span::Span, String),
ErrorReported(ErrorGuaranteed),
/// A `ParseResult` where the `Success` variant contains a mapping of
/// `MacroRulesNormalizedIdent`s to `NamedMatch`es. This represents the mapping
/// of metavars to the token trees they bind to.
-pub(crate) type NamedParseResult = ParseResult<NamedMatches>;
+pub(crate) type NamedParseResult<F> = ParseResult<NamedMatches, F>;
/// Contains a mapping of `MacroRulesNormalizedIdent`s to `NamedMatch`es.
/// This represents the mapping of metavars to the token trees they bind to.
&mut self,
matcher: &'matcher [MatcherLoc],
token: &Token,
+ approx_position: usize,
track: &mut T,
- ) -> Option<NamedParseResult> {
+ ) -> Option<NamedParseResult<T::Failure>> {
// Matcher positions that would be valid if the macro invocation was over now. Only
// modified if `token == Eof`.
let mut eof_mps = EofMatcherPositions::None;
EofMatcherPositions::Multiple => {
Error(token.span, "ambiguity: multiple successful parses".to_string())
}
- EofMatcherPositions::None => Failure(
+ EofMatcherPositions::None => Failure(T::build_failure(
Token::new(
token::Eof,
if token.span.is_dummy() { token.span } else { token.span.shrink_to_hi() },
),
+ approx_position,
"missing tokens in macro arguments",
- ),
+ )),
})
} else {
None
parser: &mut Cow<'_, Parser<'_>>,
matcher: &'matcher [MatcherLoc],
track: &mut T,
- ) -> NamedParseResult {
+ ) -> NamedParseResult<T::Failure> {
// A queue of possible matcher positions. We initialize it with the matcher position in
// which the "dot" is before the first token of the first token tree in `matcher`.
// `parse_tt_inner` then processes all of these possible matcher positions and produces
// Process `cur_mps` until either we have finished the input or we need to get some
// parsing from the black-box parser done.
- let res = self.parse_tt_inner(matcher, &parser.token, track);
+ let res = self.parse_tt_inner(
+ matcher,
+ &parser.token,
+ parser.approx_token_stream_pos(),
+ track,
+ );
if let Some(res) = res {
return res;
}
(0, 0) => {
// There are no possible next positions AND we aren't waiting for the black-box
// parser: syntax error.
- return Failure(
+ return Failure(T::build_failure(
parser.token.clone(),
+ parser.approx_token_stream_pos(),
"no rules expected this token in macro call",
- );
+ ));
}
(_, 0) => {
}
}
- fn ambiguity_error(
+ fn ambiguity_error<F>(
&self,
matcher: &[MatcherLoc],
token_span: rustc_span::Span,
- ) -> NamedParseResult {
+ ) -> NamedParseResult<F> {
let nts = self
.bb_mps
.iter()
)
}
- fn nameize<I: Iterator<Item = NamedMatch>>(
+ fn nameize<I: Iterator<Item = NamedMatch>, F>(
&self,
matcher: &[MatcherLoc],
mut res: I,
- ) -> NamedParseResult {
+ ) -> NamedParseResult<F> {
// Make that each metavar has _exactly one_ binding. If so, insert the binding into the
// `NamedParseResult`. Otherwise, it's an error.
let mut ret_val = FxHashMap::default();
}
pub(super) trait Tracker<'matcher> {
+ /// The contents of `ParseResult::Failure`.
+ type Failure;
+
+ /// Arm failed to match. If the token is `token::Eof`, it indicates an unexpected
+ /// end of macro invocation. Otherwise, it indicates that no rules expected the given token.
+ /// The usize is the approximate position of the token in the input token stream.
+ fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure;
+
/// This is called before trying to match next MatcherLoc on the current token.
- fn before_match_loc(&mut self, parser: &TtParser, matcher: &'matcher MatcherLoc);
+ fn before_match_loc(&mut self, _parser: &TtParser, _matcher: &'matcher MatcherLoc) {}
/// This is called after an arm has been parsed, either successfully or unsuccessfully. When this is called,
/// `before_match_loc` was called at least once (with a `MatcherLoc::Eof`).
- fn after_arm(&mut self, result: &NamedParseResult);
+ fn after_arm(&mut self, _result: &NamedParseResult<Self::Failure>) {}
/// For tracing.
fn description() -> &'static str;
- fn recovery() -> Recovery;
+ fn recovery() -> Recovery {
+ Recovery::Forbidden
+ }
}
/// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to monomorphization.
pub(super) struct NoopTracker;
impl<'matcher> Tracker<'matcher> for NoopTracker {
- fn before_match_loc(&mut self, _: &TtParser, _: &'matcher MatcherLoc) {}
- fn after_arm(&mut self, _: &NamedParseResult) {}
+ type Failure = ();
+
+ fn build_failure(_tok: Token, _position: usize, _msg: &'static str) -> Self::Failure {}
+
fn description() -> &'static str {
"none"
}
- fn recovery() -> Recovery {
- Recovery::Forbidden
- }
}
/// Expands the rules based macro defined by `lhses` and `rhses` for a given
return Ok((i, named_matches));
}
- Failure(_, _) => {
+ Failure(_) => {
trace!("Failed to match arm, trying the next one");
// Try the next arm.
}
let rhs_nm = Ident::new(sym::rhs, def.span);
let tt_spec = Some(NonterminalKind::TT);
- // Parse the macro_rules! invocation
- let (macro_rules, body) = match &def.kind {
- ast::ItemKind::MacroDef(def) => (def.macro_rules, def.body.tokens.clone()),
+ let macro_def = match &def.kind {
+ ast::ItemKind::MacroDef(def) => def,
_ => unreachable!(),
};
+ let macro_rules = macro_def.macro_rules;
+
+ // Parse the macro_rules! invocation
// The pattern that macro_rules matches.
// The grammar for macro_rules! is:
// Convert it into `MatcherLoc` form.
let argument_gram = mbe::macro_parser::compute_locs(&argument_gram);
- let parser = Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS);
+ let create_parser = || {
+ let body = macro_def.body.tokens.clone();
+ Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS)
+ };
+
+ let parser = create_parser();
let mut tt_parser =
TtParser::new(Ident::with_dummy_span(if macro_rules { kw::MacroRules } else { kw::Macro }));
let argument_map =
match tt_parser.parse_tt(&mut Cow::Owned(parser), &argument_gram, &mut NoopTracker) {
Success(m) => m,
- Failure(token, msg) => {
+ Failure(()) => {
+ // The fast `NoopTracker` doesn't have any info on failure, so we need to retry it with another one
+ // that gives us the information we need.
+ // For this we need to reclone the macro body as the previous parser consumed it.
+ let retry_parser = create_parser();
+
+ let parse_result = tt_parser.parse_tt(
+ &mut Cow::Owned(retry_parser),
+ &argument_gram,
+ &mut diagnostics::FailureForwarder,
+ );
+ let Failure((token, _, msg)) = parse_result else {
+ unreachable!("matcher returned something other than Failure after retry");
+ };
+
let s = parse_failure_msg(&token);
let sp = token.span.substitute_dummy(def.span);
let mut err = sess.parse_sess.span_diagnostic.struct_span_err(sp, &s);
/// Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086).
(accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None),
/// Allows `#[instruction_set(_)]` attribute.
- (accepted, isa_attribute, "CURRENT_RUSTC_VERSION", Some(74727), None),
+ (accepted, isa_attribute, "1.67.0", Some(74727), None),
/// Allows some increased flexibility in the name resolution rules,
/// especially around globs and shadowing (RFC 1560).
(accepted, item_like_imports, "1.15.0", Some(35120), None),
/// Allows specifying the bundle link modifier
(accepted, native_link_modifiers_bundle, "1.63.0", Some(81490), None),
/// Allows specifying the verbatim link modifier
- (accepted, native_link_modifiers_verbatim, "CURRENT_RUSTC_VERSION", Some(81490), None),
+ (accepted, native_link_modifiers_verbatim, "1.67.0", Some(81490), None),
/// Allows specifying the whole-archive link modifier
(accepted, native_link_modifiers_whole_archive, "1.61.0", Some(81490), None),
/// Allows using non lexical lifetimes (RFC 2094).
/// Allows `#[doc(masked)]`.
(active, doc_masked, "1.21.0", Some(44027), None),
/// Allows `dyn* Trait` objects.
- (incomplete, dyn_star, "1.65.0", Some(91611), None),
+ (incomplete, dyn_star, "1.65.0", Some(102425), None),
/// Allows `X..Y` patterns.
(active, exclusive_range_pattern, "1.11.0", Some(37854), None),
/// Allows exhaustive pattern matching on types that contain uninhabited types.
/// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
(active, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None),
/// Allows referencing `Self` and projections in impl-trait.
- (active, impl_trait_projections, "CURRENT_RUSTC_VERSION", Some(103532), None),
+ (active, impl_trait_projections, "1.67.0", Some(103532), None),
/// Allows using imported `main` function
(active, imported_main, "1.53.0", Some(28937), None),
/// Allows associated types in inherent impls.
/// Allows lints part of the strict provenance effort.
(active, strict_provenance, "1.61.0", Some(95228), None),
/// Allows string patterns to dereference values to match them.
- (active, string_deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121), None),
+ (active, string_deref_patterns, "1.67.0", Some(87121), None),
/// Allows the use of `#[target_feature]` on safe functions.
(active, target_feature_11, "1.45.0", Some(69098), None),
/// Allows using `#[thread_local]` on `static` items.
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
Self::Gated(ref stab, name, expl, _) => {
- write!(fmt, "Gated({:?}, {}, {})", stab, name, expl)
+ write!(fmt, "Gated({stab:?}, {name}, {expl})")
}
Self::Ungated => write!(fmt, "Ungated"),
}
.find(|t| t.name == feature);
match found {
Some(found) => found.issue,
- None => panic!("feature `{}` is not declared anywhere", feature),
+ None => panic!("feature `{feature}` is not declared anywhere"),
}
}
}
match *self {
LabelStr(ref s) => format!("\"{}\"", s.escape_default()),
EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(s)),
- HtmlStr(ref s) => format!("<{}>", s),
+ HtmlStr(ref s) => format!("<{s}>"),
}
}
if let Some(fontname) = options.iter().find_map(|option| {
if let RenderOption::Fontname(fontname) = option { Some(fontname) } else { None }
}) {
- font = format!(r#"fontname="{}""#, fontname);
+ font = format!(r#"fontname="{fontname}""#);
graph_attrs.push(&font[..]);
content_attrs.push(&font[..]);
}
if !(graph_attrs.is_empty() && content_attrs.is_empty()) {
writeln!(w, r#" graph[{}];"#, graph_attrs.join(" "))?;
let content_attrs_str = content_attrs.join(" ");
- writeln!(w, r#" node[{}];"#, content_attrs_str)?;
- writeln!(w, r#" edge[{}];"#, content_attrs_str)?;
+ writeln!(w, r#" node[{content_attrs_str}];"#)?;
+ writeln!(w, r#" edge[{content_attrs_str}];"#)?;
}
let mut text = Vec::new();
write!(text, "{}", id.as_slice()).unwrap();
if !options.contains(&RenderOption::NoNodeLabels) {
- write!(text, "[label={}]", escaped).unwrap();
+ write!(text, "[label={escaped}]").unwrap();
}
let style = g.node_style(n);
write!(text, "{} -> {}", source_id.as_slice(), target_id.as_slice()).unwrap();
if !options.contains(&RenderOption::NoEdgeLabels) {
- write!(text, "[label={}]", escaped_label).unwrap();
+ write!(text, "[label={escaped_label}]").unwrap();
}
let style = g.edge_style(e);
where
Id: Debug,
{
- self.opt_def_id()
- .unwrap_or_else(|| panic!("attempted .def_id() on invalid res: {:?}", self))
+ self.opt_def_id().unwrap_or_else(|| panic!("attempted .def_id() on invalid res: {self:?}"))
}
/// Return `Some(..)` with the `DefId` of this `Res` if it has a ID, else `None`.
//
// See the documentation for DefPathHash for more information.
panic!(
- "found DefPathHash collision between {:?} and {:?}. \
- Compilation cannot continue.",
- def_path1, def_path2
+ "found DefPathHash collision between {def_path1:?} and {def_path2:?}. \
+ Compilation cannot continue."
);
}
let mut s = String::with_capacity(self.data.len() * 16);
for component in &self.data {
- write!(s, "::{}", component).unwrap();
+ write!(s, "::{component}").unwrap();
}
s
for component in &self.data {
s.extend(opt_delimiter);
opt_delimiter = Some('-');
- write!(s, "{}", component).unwrap();
+ write!(s, "{component}").unwrap();
}
s
match self.name() {
DefPathDataName::Named(name) => f.write_str(name.as_str()),
// FIXME(#70334): this will generate legacy {{closure}}, {{impl}}, etc
- DefPathDataName::Anon { namespace } => write!(f, "{{{{{}}}}}", namespace),
+ DefPathDataName::Anon { namespace } => write!(f, "{{{{{namespace}}}}}"),
}
}
}
&self
.nodes
.iter_enumerated()
- .map(|(id, parented_node)| (id, parented_node.as_ref().map(|node| node.parent)))
+ .map(|(id, parented_node)| {
+ let parented_node = parented_node.as_ref().map(|node| node.parent);
+
+ debug_fn(move |f| write!(f, "({id:?}, {parented_node:?})"))
+ })
.collect::<Vec<_>>(),
)
.field("bodies", &self.bodies)
pub fn peel_refs(&self) -> &Self {
let mut final_ty = self;
- while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind {
+ while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
final_ty = ty;
}
final_ty
/// A raw pointer (i.e., `*const T` or `*mut T`).
Ptr(MutTy<'hir>),
/// A reference (i.e., `&'a T` or `&'a mut T`).
- Rptr(&'hir Lifetime, MutTy<'hir>),
+ Ref(&'hir Lifetime, MutTy<'hir>),
/// A bare function (e.g., `fn(usize) -> bool`).
BareFn(&'hir BareFnTy<'hir>),
/// The never type (`!`).
/// ```ignore (illustrative)
/// ctor
/// .ctor_hir_id()
- /// .and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
+ /// .and_then(|ctor_id| tcx.hir().find_parent(ctor_id))
/// .and_then(|parent| parent.ident())
/// ```
pub fn ident(&self) -> Option<Ident> {
static_assert_size!(Res, 12);
static_assert_size!(Stmt<'_>, 32);
static_assert_size!(StmtKind<'_>, 16);
- // tidy-alphabetical-end
- // FIXME: move the tidy directive to the end after the next bootstrap bump
- #[cfg(bootstrap)]
- static_assert_size!(TraitItem<'_>, 88);
- #[cfg(not(bootstrap))]
static_assert_size!(TraitItem<'_>, 80);
- #[cfg(bootstrap)]
- static_assert_size!(TraitItemKind<'_>, 48);
- #[cfg(not(bootstrap))]
static_assert_size!(TraitItemKind<'_>, 40);
static_assert_size!(Ty<'_>, 48);
static_assert_size!(TyKind<'_>, 32);
+ // tidy-alphabetical-end
+}
+
+fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Debug {
+ struct DebugFn<F>(F);
+ impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Debug for DebugFn<F> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ (self.0)(fmt)
+ }
+ }
+ DebugFn(f)
}
use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_ID};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
use rustc_span::{def_id::DefPathHash, HashStableContext};
-use std::fmt;
+use std::fmt::{self, Debug};
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Encodable, Decodable)]
pub struct OwnerId {
pub def_id: LocalDefId,
}
+impl Debug for OwnerId {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Example: DefId(0:1 ~ aa[7697]::{use#0})
+ Debug::fmt(&self.def_id, f)
+ }
+}
+
impl From<OwnerId> for HirId {
fn from(owner: OwnerId) -> HirId {
HirId { owner, local_id: ItemLocalId::from_u32(0) }
/// the `local_id` part of the `HirId` changing, which is a very useful property in
/// incremental compilation where we have to persist things through changes to
/// the code base.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Encodable, Decodable, HashStable_Generic)]
#[rustc_pass_by_value]
pub struct HirId {
pub local_id: ItemLocalId,
}
+impl Debug for HirId {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Example: HirId(DefId(0:1 ~ aa[7697]::{use#0}).10)
+ // Don't use debug_tuple to always keep this on one line.
+ write!(f, "HirId({:?}.{:?})", self.owner, self.local_id)
+ }
+}
+
impl HirId {
/// Signal local id which should never be used.
pub const INVALID: HirId =
impl fmt::Display for HirId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{:?}", self)
+ write!(f, "{self:?}")
}
}
match typ.kind {
TyKind::Slice(ref ty) => visitor.visit_ty(ty),
TyKind::Ptr(ref mutable_type) => visitor.visit_ty(mutable_type.ty),
- TyKind::Rptr(ref lifetime, ref mutable_type) => {
+ TyKind::Ref(ref lifetime, ref mutable_type) => {
visitor.visit_lifetime(lifetime);
visitor.visit_ty(mutable_type.ty)
}
poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx>;
- /// Normalize an associated type coming from the user.
- ///
- /// This should only be used by astconv. Use `FnCtxt::normalize`
- /// or `ObligationCtxt::normalize` in downstream crates.
- fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
+ /// Returns `AdtDef` if `ty` is an ADT.
+ /// Note that `ty` might be a projection type that needs normalization.
+ /// This used to get the enum variants in scope of the type.
+ /// For example, `Self::A` could refer to an associated type
+ /// or to an enum variant depending on the result of this function.
+ fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>>;
/// Invoked when we encounter an error from some prior pass
/// (e.g., resolve) that is translated into a ty-error. This is
// Avoid ICE #86756 when type error recovery goes awry.
return tcx.ty_error().into();
}
- self.astconv
- .normalize_ty(
- self.span,
- tcx.at(self.span)
- .bound_type_of(param.def_id)
- .subst(tcx, substs),
- )
- .into()
+ tcx.at(self.span).bound_type_of(param.def_id).subst(tcx, substs).into()
} else if infer_args {
self.astconv.ty_infer(Some(param), self.span).into()
} else {
ty::Binder::bind_with_vars(tcx.mk_trait_ref(trait_def_id, substs), bound_vars);
debug!(?poly_trait_ref, ?assoc_bindings);
- bounds.trait_bounds.push((poly_trait_ref, span, constness));
+ bounds.push_trait_bound(tcx, poly_trait_ref, span, constness);
let mut dup_bindings = FxHashMap::default();
for binding in &assoc_bindings {
}
/// Sets `implicitly_sized` to true on `Bounds` if necessary
- pub(crate) fn add_implicitly_sized<'hir>(
+ pub(crate) fn add_implicitly_sized(
&self,
- bounds: &mut Bounds<'hir>,
- ast_bounds: &'hir [hir::GenericBound<'hir>],
- self_ty_where_predicates: Option<(LocalDefId, &'hir [hir::WherePredicate<'hir>])>,
+ bounds: &mut Bounds<'tcx>,
+ self_ty: Ty<'tcx>,
+ ast_bounds: &'tcx [hir::GenericBound<'tcx>],
+ self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
span: Span,
) {
let tcx = self.tcx();
// Try to find an unbound in bounds.
let mut unbound = None;
- let mut search_bounds = |ast_bounds: &'hir [hir::GenericBound<'hir>]| {
+ let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
for ab in ast_bounds {
if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
if unbound.is_none() {
// No lang item for `Sized`, so we can't add it as a bound.
return;
}
- bounds.implicitly_sized = Some(span);
+ bounds.push_sized(tcx, self_ty, span);
}
/// This helper takes a *converted* parameter type (`param_ty`)
}
hir::GenericBound::Outlives(lifetime) => {
let region = self.ast_region_to_region(lifetime, None);
- bounds.region_bounds.push((
- ty::Binder::bind_with_vars(region, bound_vars),
+ bounds.push_region_bound(
+ self.tcx(),
+ ty::Binder::bind_with_vars(
+ ty::OutlivesPredicate(param_ty, region),
+ bound_vars,
+ ),
lifetime.ident.span,
- ));
+ );
}
}
}
(_, _) => {
let got = if let Some(_) = term.ty() { "type" } else { "constant" };
let expected = def_kind.descr(assoc_item_def_id);
- let reported = tcx
- .sess
- .struct_span_err(
+ let mut err = tcx.sess.struct_span_err(
+ binding.span,
+ &format!("expected {expected} bound, found {got}"),
+ );
+ err.span_note(
+ tcx.def_span(assoc_item_def_id),
+ &format!("{expected} defined here"),
+ );
+
+ if let hir::def::DefKind::AssocConst = def_kind
+ && let Some(t) = term.ty() && (t.is_enum() || t.references_error())
+ && tcx.features().associated_const_equality {
+ err.span_suggestion(
binding.span,
- &format!("expected {expected} bound, found {got}"),
- )
- .span_note(
- tcx.def_span(assoc_item_def_id),
- &format!("{expected} defined here"),
- )
- .emit();
+ "if equating a const, try wrapping with braces",
+ format!("{} = {{ const }}", binding.item_name),
+ Applicability::HasPlaceholders,
+ );
+ }
+ let reported = err.emit();
term = match def_kind {
hir::def::DefKind::AssocTy => {
tcx.ty_error_with_guaranteed(reported).into()
};
}
}
- bounds.projection_bounds.push((
- projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
- projection_ty,
- term: term,
- }),
+ bounds.push_projection_bound(
+ tcx,
+ projection_ty
+ .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
binding.span,
- ));
+ );
}
ConvertedBindingKind::Constraint(ast_bounds) => {
// "Desugar" a constraint like `T: Iterator<Item: Debug>` to
item_segment: &hir::PathSegment<'_>,
) -> Ty<'tcx> {
let substs = self.ast_path_substs_for_ty(span, did, item_segment);
- self.normalize_ty(span, self.tcx().at(span).bound_type_of(did).subst(self.tcx(), substs))
+ self.tcx().at(span).bound_type_of(did).subst(self.tcx(), substs)
}
fn conv_object_ty_poly_trait_ref(
&self,
span: Span,
- trait_bounds: &[hir::PolyTraitRef<'_>],
+ hir_trait_bounds: &[hir::PolyTraitRef<'_>],
lifetime: &hir::Lifetime,
borrowed: bool,
representation: DynKind,
let mut bounds = Bounds::default();
let mut potential_assoc_types = Vec::new();
let dummy_self = self.tcx().types.trait_object_dummy_self;
- for trait_bound in trait_bounds.iter().rev() {
+ for trait_bound in hir_trait_bounds.iter().rev() {
if let GenericArgCountResult {
correct:
Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
}
}
+ let mut trait_bounds = vec![];
+ let mut projection_bounds = vec![];
+ for (pred, span) in bounds.predicates() {
+ let bound_pred = pred.kind();
+ match bound_pred.skip_binder() {
+ ty::PredicateKind::Clause(clause) => match clause {
+ ty::Clause::Trait(trait_pred) => {
+ assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive);
+ trait_bounds.push((
+ bound_pred.rebind(trait_pred.trait_ref),
+ span,
+ trait_pred.constness,
+ ));
+ }
+ ty::Clause::Projection(proj) => {
+ projection_bounds.push((bound_pred.rebind(proj), span));
+ }
+ ty::Clause::TypeOutlives(_) => {
+ // Do nothing, we deal with regions separately
+ }
+ ty::Clause::RegionOutlives(_) => bug!(),
+ },
+ ty::PredicateKind::WellFormed(_)
+ | ty::PredicateKind::ObjectSafe(_)
+ | ty::PredicateKind::ClosureKind(_, _, _)
+ | ty::PredicateKind::Subtype(_)
+ | ty::PredicateKind::Coerce(_)
+ | ty::PredicateKind::ConstEvaluatable(_)
+ | ty::PredicateKind::ConstEquate(_, _)
+ | ty::PredicateKind::TypeWellFormedFromEnv(_)
+ | ty::PredicateKind::Ambiguous => bug!(),
+ }
+ }
+
// Expand trait aliases recursively and check that only one regular (non-auto) trait
// is used and no 'maybe' bounds are used.
let expanded_traits =
- traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b)));
+ traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b, _)| (a, b)));
+
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
.filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
}
if regular_traits.is_empty() && auto_traits.is_empty() {
- let trait_alias_span = bounds
- .trait_bounds
+ let trait_alias_span = trait_bounds
.iter()
.map(|&(trait_ref, _, _)| trait_ref.def_id())
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
// Use a `BTreeSet` to keep output in a more consistent order.
let mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default();
- let regular_traits_refs_spans = bounds
- .trait_bounds
+ let regular_traits_refs_spans = trait_bounds
.into_iter()
.filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
// the discussion in #56288 for alternatives.
if !references_self {
// Include projections defined on supertraits.
- bounds.projection_bounds.push((pred, span));
+ projection_bounds.push((pred, span));
}
}
_ => (),
}
}
- for (projection_bound, _) in &bounds.projection_bounds {
+ for (projection_bound, _) in &projection_bounds {
for def_ids in associated_types.values_mut() {
def_ids.remove(&projection_bound.projection_def_id());
}
self.complain_about_missing_associated_types(
associated_types,
potential_assoc_types,
- trait_bounds,
+ hir_trait_bounds,
);
// De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
let substs = tcx.intern_substs(&substs[..]);
let span = i.bottom().1;
- let empty_generic_args = trait_bounds.iter().any(|hir_bound| {
+ let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
&& hir_bound.span.contains(span)
});
})
});
- let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
+ let existential_projections = projection_bounds.iter().map(|(bound, _)| {
bound.map_bound(|mut b| {
assert_eq!(b.projection_ty.self_ty(), dummy_self);
Ok(bound)
}
- // Create a type from a path to an associated type.
+ // Create a type from a path to an associated type or to an enum variant.
// For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C`
// and item_segment is the path segment for `D`. We return a type and a def for
// the whole path.
// Check if we have an enum variant.
let mut variant_resolution = None;
- if let ty::Adt(adt_def, adt_substs) = qself_ty.kind() {
+ if let Some(adt_def) = self.probe_adt(span, qself_ty) {
if adt_def.is_enum() {
let variant_def = adt_def
.variants()
let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, impl_) else {
continue;
};
+ let ty::Adt(_, adt_substs) = qself_ty.kind() else {
+ // FIXME(inherent_associated_types)
+ bug!("unimplemented: non-adt self of inherent assoc ty");
+ };
let item_substs = self.create_substs_for_associated_item(
span,
assoc_ty_did,
adt_substs,
);
let ty = tcx.bound_type_of(assoc_ty_did).subst(tcx, item_substs);
- let ty = self.normalize_ty(span, ty);
return Ok((ty, DefKind::AssocTy, assoc_ty_did));
}
}
};
let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound);
- let ty = self.normalize_ty(span, ty);
if let Some(variant_def_id) = variant_resolution {
tcx.struct_span_lint_hir(
debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
- self.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs))
+ tcx.mk_projection(item_def_id, item_substs)
}
pub fn prohibit_generics<'a>(
self_ty: Option<Ty<'tcx>>,
kind: DefKind,
def_id: DefId,
+ span: Span,
) -> Vec<PathSeg> {
// We need to extract the type parameters supplied by the user in
// the path `path`. Due to the current setup, this is a bit of a
// Case 2. Reference to a variant constructor.
DefKind::Ctor(CtorOf::Variant, ..) | DefKind::Variant => {
- let adt_def = self_ty.map(|t| t.ty_adt_def().unwrap());
- let (generics_def_id, index) = if let Some(adt_def) = adt_def {
+ let (generics_def_id, index) = if let Some(self_ty) = self_ty {
+ let adt_def = self.probe_adt(span, self_ty).unwrap();
debug_assert!(adt_def.is_enum());
(adt_def.did(), last)
} else if last >= 1 && segments[last - 1].args.is_some() {
err.note("`impl Trait` types can't have type parameters");
});
let substs = self.ast_path_substs_for_ty(span, did, item_segment.0);
- self.normalize_ty(span, tcx.mk_opaque(did, substs))
+ tcx.mk_opaque(did, substs)
}
Res::Def(
DefKind::Enum
assert_eq!(opt_self_ty, None);
let path_segs =
- self.def_ids_for_value_path_segments(path.segments, None, kind, def_id);
+ self.def_ids_for_value_path_segments(path.segments, None, kind, def_id, span);
let generic_segs: FxHashSet<_> =
path_segs.iter().map(|PathSeg(_, index)| index).collect();
self.prohibit_generics(
}
tcx.ty_error_with_guaranteed(err.emit())
} else {
- self.normalize_ty(span, ty)
+ ty
}
}
Res::Def(DefKind::AssocTy, def_id) => {
hir::TyKind::Ptr(ref mt) => {
tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
}
- hir::TyKind::Rptr(ref region, ref mt) => {
+ hir::TyKind::Ref(ref region, ref mt) => {
let r = self.ast_region_to_region(region, None);
debug!(?r);
let t = self.ast_ty_to_ty_inner(mt.ty, true, false);
None,
ty::BoundConstness::NotConst,
);
- EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id)))
- .subst(tcx, substs)
+ EarlyBinder(tcx.at(span).type_of(def_id)).subst(tcx, substs)
}
hir::TyKind::Array(ref ty, ref length) => {
let length = match length {
}
};
- let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length));
- self.normalize_ty(ast_ty.span, array_ty)
+ tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length))
}
hir::TyKind::Typeof(ref e) => {
let ty_erased = tcx.type_of(e.def_id);
let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) =
hir.get(fn_hir_id) else { return None };
let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) =
- hir.get(hir.get_parent_node(fn_hir_id)) else { bug!("ImplItem should have Impl parent") };
+ hir.get_parent(fn_hir_id) else { bug!("ImplItem should have Impl parent") };
let trait_ref = self.instantiate_mono_trait_ref(
i.of_trait.as_ref()?,
//! Bounds are restrictions applied to some types after they've been converted into the
//! `ty` form from the HIR.
+use rustc_hir::LangItem;
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
use rustc_span::Span;
/// ^^^^^^^^^ bounding the type parameter `T`
///
/// impl dyn Bar + Baz
-/// ^^^^^^^^^ bounding the forgotten dynamic type
+/// ^^^^^^^^^ bounding the type-erased dynamic type
/// ```
///
/// Our representation is a bit mixed here -- in some cases, we
/// include the self type (e.g., `trait_bounds`) but in others we do not
#[derive(Default, PartialEq, Eq, Clone, Debug)]
pub struct Bounds<'tcx> {
- /// A list of region bounds on the (implicit) self type. So if you
- /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but
- /// the `T` is not explicitly included).
- pub region_bounds: Vec<(ty::Binder<'tcx, ty::Region<'tcx>>, Span)>,
-
- /// A list of trait bounds. So if you had `T: Debug` this would be
- /// `T: Debug`. Note that the self-type is explicit here.
- pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, ty::BoundConstness)>,
-
- /// A list of projection equality bounds. So if you had `T:
- /// Iterator<Item = u32>` this would include `<T as
- /// Iterator>::Item => u32`. Note that the self-type is explicit
- /// here.
- pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
-
- /// `Some` if there is *no* `?Sized` predicate. The `span`
- /// is the location in the source of the `T` declaration which can
- /// be cited as the source of the `T: Sized` requirement.
- pub implicitly_sized: Option<Span>,
+ pub predicates: Vec<(ty::Predicate<'tcx>, Span)>,
}
impl<'tcx> Bounds<'tcx> {
- /// Converts a bounds list into a flat set of predicates (like
- /// where-clauses). Because some of our bounds listings (e.g.,
- /// regions) don't include the self-type, you must supply the
- /// self-type here (the `param_ty` parameter).
- pub fn predicates<'out, 's>(
- &'s self,
+ pub fn push_region_bound(
+ &mut self,
tcx: TyCtxt<'tcx>,
- param_ty: Ty<'tcx>,
- // the output must live shorter than the duration of the borrow of self and 'tcx.
- ) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + 'out
- where
- 'tcx: 'out,
- 's: 'out,
- {
- // If it could be sized, and is, add the `Sized` predicate.
- let sized_predicate = self.implicitly_sized.and_then(|span| {
- // FIXME: use tcx.at(span).mk_trait_ref(LangItem::Sized) here? This may make no-core code harder to write.
- let sized = tcx.lang_items().sized_trait()?;
- let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(sized, [param_ty]));
- Some((trait_ref.without_const().to_predicate(tcx), span))
- });
+ region: ty::PolyTypeOutlivesPredicate<'tcx>,
+ span: Span,
+ ) {
+ self.predicates.push((region.to_predicate(tcx), span));
+ }
- let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
- let pred = region_bound
- .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
- .to_predicate(tcx);
- (pred, span)
- });
- let trait_bounds =
- self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
- let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
- (predicate, span)
- });
- let projection_bounds = self
- .projection_bounds
- .iter()
- .map(move |&(projection, span)| (projection.to_predicate(tcx), span));
+ pub fn push_trait_bound(
+ &mut self,
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ span: Span,
+ constness: ty::BoundConstness,
+ ) {
+ self.predicates.push((trait_ref.with_constness(constness).to_predicate(tcx), span));
+ }
+
+ pub fn push_projection_bound(
+ &mut self,
+ tcx: TyCtxt<'tcx>,
+ projection: ty::PolyProjectionPredicate<'tcx>,
+ span: Span,
+ ) {
+ self.predicates.push((projection.to_predicate(tcx), span));
+ }
+
+ pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) {
+ let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span));
+ let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [ty]));
+ // Preferrable to put this obligation first, since we report better errors for sized ambiguity.
+ self.predicates.insert(0, (trait_ref.without_const().to_predicate(tcx), span));
+ }
- sized_predicate.into_iter().chain(region_preds).chain(trait_bounds).chain(projection_bounds)
+ pub fn predicates(&self) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + '_ {
+ self.predicates.iter().cloned()
}
}
use crate::check::intrinsicck::InlineAsmCtxt;
use crate::errors::LinkageType;
-use super::compare_method::check_type_bounds;
-use super::compare_method::{compare_impl_method, compare_ty_impl};
+use super::compare_impl_item::check_type_bounds;
+use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
use super::*;
use rustc_attr as attr;
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
// Can have different predicates to their defining use
hir::OpaqueTyOrigin::TyAlias => {
let outlives_environment = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(
+ let _ = infcx.err_ctxt().check_region_obligations_and_report_errors(
defining_use_anchor,
&outlives_environment,
);
let impl_item_full = tcx.hir().impl_item(impl_item.id);
match impl_item_full.kind {
hir::ImplItemKind::Const(..) => {
- let _ = tcx.compare_assoc_const_impl_item_with_trait_item((
+ let _ = tcx.compare_impl_const((
impl_item.id.owner_id.def_id,
ty_impl_item.trait_item_def_id.unwrap(),
));
}
hir::ImplItemKind::Type(impl_ty) => {
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
- compare_ty_impl(
+ compare_impl_ty(
tcx,
&ty_impl_item,
impl_ty.span,
if adt.variants().len() != 1 {
bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did());
- if adt.variants().is_empty() {
- // Don't bother checking the fields. No variants (and thus no fields) exist.
- return;
- }
+ // Don't bother checking the fields.
+ return;
}
// For each field, figure out if it's known to be a ZST and align(1), with "known"
--- /dev/null
+use super::potentially_plural_count;
+use crate::errors::LifetimesOrBoundsMismatchOnTrait;
+use hir::def_id::{DefId, LocalDefId};
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::intravisit;
+use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
+use rustc_infer::traits::util;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
+use rustc_middle::ty::util::ExplicitSelf;
+use rustc_middle::ty::{
+ self, DefIdTree, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
+};
+use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
+use rustc_span::Span;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
+use rustc_trait_selection::traits::{
+ self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
+};
+use std::iter;
+
+/// Checks that a method from an impl conforms to the signature of
+/// the same method as declared in the trait.
+///
+/// # Parameters
+///
+/// - `impl_m`: type of the method we are checking
+/// - `impl_m_span`: span to use for reporting errors
+/// - `trait_m`: the method in the trait
+/// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
+pub(super) fn compare_impl_method<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_m: &ty::AssocItem,
+ trait_m: &ty::AssocItem,
+ impl_trait_ref: ty::TraitRef<'tcx>,
+ trait_item_span: Option<Span>,
+) {
+ debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
+
+ let impl_m_span = tcx.def_span(impl_m.def_id);
+
+ if let Err(_) = compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref) {
+ return;
+ }
+
+ if let Err(_) = compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false) {
+ return;
+ }
+
+ if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, false) {
+ return;
+ }
+
+ if let Err(_) =
+ compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
+ {
+ return;
+ }
+
+ if let Err(_) = compare_synthetic_generics(tcx, impl_m, trait_m) {
+ return;
+ }
+
+ if let Err(_) = compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span) {
+ return;
+ }
+
+ if let Err(_) = compare_method_predicate_entailment(
+ tcx,
+ impl_m,
+ impl_m_span,
+ trait_m,
+ impl_trait_ref,
+ CheckImpliedWfMode::Check,
+ ) {
+ return;
+ }
+}
+
+/// This function is best explained by example. Consider a trait:
+///
+/// trait Trait<'t, T> {
+/// // `trait_m`
+/// fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
+/// }
+///
+/// And an impl:
+///
+/// impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
+/// // `impl_m`
+/// fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo;
+/// }
+///
+/// We wish to decide if those two method types are compatible.
+/// For this we have to show that, assuming the bounds of the impl hold, the
+/// bounds of `trait_m` imply the bounds of `impl_m`.
+///
+/// We start out with `trait_to_impl_substs`, that maps the trait
+/// type parameters to impl type parameters. This is taken from the
+/// impl trait reference:
+///
+/// trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
+///
+/// We create a mapping `dummy_substs` that maps from the impl type
+/// parameters to fresh types and regions. For type parameters,
+/// this is the identity transform, but we could as well use any
+/// placeholder types. For regions, we convert from bound to free
+/// regions (Note: but only early-bound regions, i.e., those
+/// declared on the impl or used in type parameter bounds).
+///
+/// impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
+///
+/// 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:
+///
+/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo
+///
+/// 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_placeholder_substs`, and also adding a mapping for the method
+/// type parameters. We extend the mapping to also include
+/// the method parameters.
+///
+/// trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
+///
+/// Applying this to the trait method type yields:
+///
+/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo
+///
+/// This type is also the same but the name of the bound region (`'a`
+/// vs `'b`). However, the normal subtyping rules on fn types handle
+/// this kind of equivalency just fine.
+///
+/// We now use these substitutions to ensure that all declared bounds are
+/// satisfied by the implementation's method.
+///
+/// We do this by creating a parameter environment which contains a
+/// 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 and check that
+/// they hold.
+#[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))]
+fn compare_method_predicate_entailment<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_m: &ty::AssocItem,
+ impl_m_span: Span,
+ trait_m: &ty::AssocItem,
+ impl_trait_ref: ty::TraitRef<'tcx>,
+ check_implied_wf: CheckImpliedWfMode,
+) -> Result<(), ErrorGuaranteed> {
+ let trait_to_impl_substs = impl_trait_ref.substs;
+
+ // This node-id should be used for the `body_id` field on each
+ // `ObligationCause` (and the `FnCtxt`).
+ //
+ // FIXME(@lcnr): remove that after removing `cause.body_id` from
+ // obligations.
+ let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
+ let cause = ObligationCause::new(
+ impl_m_span,
+ impl_m_hir_id,
+ ObligationCauseCode::CompareImplItemObligation {
+ impl_item_def_id: impl_m.def_id.expect_local(),
+ trait_item_def_id: trait_m.def_id,
+ kind: impl_m.kind,
+ },
+ );
+
+ // Create mapping from impl to placeholder.
+ let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
+
+ // Create mapping from trait to placeholder.
+ let trait_to_placeholder_substs =
+ impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
+ debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs);
+
+ let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
+ let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
+
+ // Check region bounds.
+ check_region_bounds_on_impl_item(tcx, impl_m, trait_m, false)?;
+
+ // Create obligations for each predicate declared by the impl
+ // definition in the context of the trait's parameter
+ // environment. We can't just use `impl_env.caller_bounds`,
+ // however, because we want to replace all late-bound regions with
+ // region variables.
+ let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
+ let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
+
+ debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
+
+ // This is the only tricky bit of the new way we check implementation methods
+ // We need to build a set of predicates where only the method-level bounds
+ // are from the trait and we assume all other bounds from the implementation
+ // to be previously satisfied.
+ //
+ // We then register the obligations from the impl_m and check to see
+ // if all constraints hold.
+ hybrid_preds
+ .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
+ // the new hybrid bounds we computed.
+ let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
+ let param_env = ty::ParamEnv::new(
+ tcx.intern_predicates(&hybrid_preds.predicates),
+ Reveal::UserFacing,
+ hir::Constness::NotConst,
+ );
+ let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
+
+ let infcx = &tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(infcx);
+
+ debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
+
+ let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
+ for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
+ let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
+ let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
+
+ let cause = ObligationCause::new(
+ span,
+ impl_m_hir_id,
+ ObligationCauseCode::CompareImplItemObligation {
+ impl_item_def_id: impl_m.def_id.expect_local(),
+ trait_item_def_id: trait_m.def_id,
+ kind: impl_m.kind,
+ },
+ );
+ ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
+ }
+
+ // We now need to check that the signature of the impl method is
+ // compatible with that of the trait method. We do this by
+ // checking that `impl_fty <: trait_fty`.
+ //
+ // FIXME. Unfortunately, this doesn't quite work right now because
+ // associated type normalization is not integrated into subtype
+ // checks. For the comparison to be valid, we need to
+ // normalize the associated types in the impl/trait methods
+ // first. However, because function types bind regions, just
+ // calling `normalize_associated_types_in` would have no effect on
+ // any associated types appearing in the fn arguments or return
+ // type.
+
+ // Compute placeholder form of impl and trait method tys.
+ let tcx = infcx.tcx;
+
+ let mut wf_tys = FxIndexSet::default();
+
+ let unnormalized_impl_sig = infcx.replace_bound_vars_with_fresh_vars(
+ impl_m_span,
+ infer::HigherRankedType,
+ tcx.fn_sig(impl_m.def_id),
+ );
+ let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig));
+
+ let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
+ let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig);
+ debug!("compare_impl_method: impl_fty={:?}", impl_sig);
+
+ let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
+ let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
+
+ // Next, add all inputs and output as well-formed tys. Importantly,
+ // we have to do this before normalization, since the normalized ty may
+ // not contain the input parameters. See issue #87748.
+ wf_tys.extend(trait_sig.inputs_and_output.iter());
+ let trait_sig = ocx.normalize(&norm_cause, param_env, trait_sig);
+ // We also have to add the normalized trait signature
+ // as we don't normalize during implied bounds computation.
+ wf_tys.extend(trait_sig.inputs_and_output.iter());
+ let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
+
+ debug!("compare_impl_method: trait_fty={:?}", trait_fty);
+
+ // FIXME: We'd want to keep more accurate spans than "the method signature" when
+ // processing the comparison between the trait and impl fn, but we sadly lose them
+ // and point at the whole signature when a trait bound or specific input or output
+ // type would be more appropriate. In other places we have a `Vec<Span>`
+ // corresponding to their `Vec<Predicate>`, but we don't have that here.
+ // Fixing this would improve the output of test `issue-83765.rs`.
+ let result = ocx.sup(&cause, param_env, trait_sig, impl_sig);
+
+ if let Err(terr) = result {
+ debug!(?impl_sig, ?trait_sig, ?terr, "sub_types failed");
+
+ let emitted = report_trait_method_mismatch(
+ &infcx,
+ cause,
+ terr,
+ (trait_m, trait_sig),
+ (impl_m, impl_sig),
+ impl_trait_ref,
+ );
+ return Err(emitted);
+ }
+
+ if check_implied_wf == CheckImpliedWfMode::Check {
+ // We need to check that the impl's args are well-formed given
+ // the hybrid param-env (impl + trait method where-clauses).
+ ocx.register_obligation(traits::Obligation::new(
+ infcx.tcx,
+ ObligationCause::dummy(),
+ param_env,
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
+ ));
+ }
+ let emit_implied_wf_lint = || {
+ infcx.tcx.struct_span_lint_hir(
+ rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
+ impl_m_hir_id,
+ infcx.tcx.def_span(impl_m.def_id),
+ "impl method assumes more implied bounds than the corresponding trait method",
+ |lint| lint,
+ );
+ };
+
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ match check_implied_wf {
+ CheckImpliedWfMode::Check => {
+ return compare_method_predicate_entailment(
+ tcx,
+ impl_m,
+ impl_m_span,
+ trait_m,
+ impl_trait_ref,
+ CheckImpliedWfMode::Skip,
+ )
+ .map(|()| {
+ // If the skip-mode was successful, emit a lint.
+ emit_implied_wf_lint();
+ });
+ }
+ CheckImpliedWfMode::Skip => {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+ return Err(reported);
+ }
+ }
+ }
+
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let outlives_env = OutlivesEnvironment::with_bounds(
+ param_env,
+ Some(infcx),
+ infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys.clone()),
+ );
+ infcx.process_registered_region_obligations(
+ outlives_env.region_bound_pairs(),
+ outlives_env.param_env,
+ );
+ let errors = infcx.resolve_regions(&outlives_env);
+ if !errors.is_empty() {
+ // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
+ // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors`
+ match check_implied_wf {
+ CheckImpliedWfMode::Check => {
+ return compare_method_predicate_entailment(
+ tcx,
+ impl_m,
+ impl_m_span,
+ trait_m,
+ impl_trait_ref,
+ CheckImpliedWfMode::Skip,
+ )
+ .map(|()| {
+ // If the skip-mode was successful, emit a lint.
+ emit_implied_wf_lint();
+ });
+ }
+ CheckImpliedWfMode::Skip => {
+ if infcx.tainted_by_errors().is_none() {
+ infcx.err_ctxt().report_region_errors(impl_m.def_id.expect_local(), &errors);
+ }
+ return Err(tcx
+ .sess
+ .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"));
+ }
+ }
+ }
+
+ Ok(())
+}
+
+#[derive(Debug, PartialEq, Eq)]
+enum CheckImpliedWfMode {
+ /// Checks implied well-formedness of the impl method. If it fails, we will
+ /// re-check with `Skip`, and emit a lint if it succeeds.
+ Check,
+ /// Skips checking implied well-formedness of the impl method, but will emit
+ /// a lint if the `compare_method_predicate_entailment` succeeded. This means that
+ /// the reason that we had failed earlier during `Check` was due to the impl
+ /// having stronger requirements than the trait.
+ Skip,
+}
+
+fn compare_asyncness<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_m: &ty::AssocItem,
+ impl_m_span: Span,
+ trait_m: &ty::AssocItem,
+ trait_item_span: Option<Span>,
+) -> Result<(), ErrorGuaranteed> {
+ if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
+ match tcx.fn_sig(impl_m.def_id).skip_binder().output().kind() {
+ ty::Alias(ty::Opaque, ..) => {
+ // allow both `async fn foo()` and `fn foo() -> impl Future`
+ }
+ ty::Error(rustc_errors::ErrorGuaranteed { .. }) => {
+ // We don't know if it's ok, but at least it's already an error.
+ }
+ _ => {
+ return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync {
+ span: impl_m_span,
+ method_name: trait_m.name,
+ trait_item_span,
+ }));
+ }
+ };
+ }
+
+ Ok(())
+}
+
+/// Given a method def-id in an impl, compare the method signature of the impl
+/// against the trait that it's implementing. In doing so, infer the hidden types
+/// that this method's signature provides to satisfy each return-position `impl Trait`
+/// in the trait signature.
+///
+/// The method is also responsible for making sure that the hidden types for each
+/// RPITIT actually satisfy the bounds of the `impl Trait`, i.e. that if we infer
+/// `impl Trait = Foo`, that `Foo: Trait` holds.
+///
+/// For example, given the sample code:
+///
+/// ```
+/// #![feature(return_position_impl_trait_in_trait)]
+///
+/// use std::ops::Deref;
+///
+/// trait Foo {
+/// fn bar() -> impl Deref<Target = impl Sized>;
+/// // ^- RPITIT #1 ^- RPITIT #2
+/// }
+///
+/// impl Foo for () {
+/// fn bar() -> Box<String> { Box::new(String::new()) }
+/// }
+/// ```
+///
+/// The hidden types for the RPITITs in `bar` would be inferred to:
+/// * `impl Deref` (RPITIT #1) = `Box<String>`
+/// * `impl Sized` (RPITIT #2) = `String`
+///
+/// The relationship between these two types is straightforward in this case, but
+/// may be more tenuously connected via other `impl`s and normalization rules for
+/// cases of more complicated nested RPITITs.
+#[instrument(skip(tcx), level = "debug", ret)]
+pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
+ let impl_m = tcx.opt_associated_item(def_id).unwrap();
+ let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
+ let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
+ let param_env = tcx.param_env(def_id);
+
+ // First, check a few of the same things as `compare_impl_method`,
+ // just so we don't ICE during substitution later.
+ compare_number_of_generics(tcx, impl_m, trait_m, tcx.hir().span_if_local(impl_m.def_id), true)?;
+ compare_generic_param_kinds(tcx, impl_m, trait_m, true)?;
+ check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?;
+
+ let trait_to_impl_substs = impl_trait_ref.substs;
+
+ let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
+ let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
+ let cause = ObligationCause::new(
+ return_span,
+ impl_m_hir_id,
+ ObligationCauseCode::CompareImplItemObligation {
+ impl_item_def_id: impl_m.def_id.expect_local(),
+ trait_item_def_id: trait_m.def_id,
+ kind: impl_m.kind,
+ },
+ );
+
+ // Create mapping from impl to placeholder.
+ let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
+
+ // Create mapping from trait to placeholder.
+ let trait_to_placeholder_substs =
+ impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
+
+ let infcx = &tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(infcx);
+
+ // Normalize the impl signature with fresh variables for lifetime inference.
+ let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
+ let impl_sig = ocx.normalize(
+ &norm_cause,
+ param_env,
+ infcx.replace_bound_vars_with_fresh_vars(
+ return_span,
+ infer::HigherRankedType,
+ tcx.fn_sig(impl_m.def_id),
+ ),
+ );
+ impl_sig.error_reported()?;
+ let impl_return_ty = impl_sig.output();
+
+ // Normalize the trait signature with liberated bound vars, passing it through
+ // the ImplTraitInTraitCollector, which gathers all of the RPITITs and replaces
+ // them with inference variables.
+ // We will use these inference variables to collect the hidden types of RPITITs.
+ let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
+ let unnormalized_trait_sig = tcx
+ .liberate_late_bound_regions(
+ impl_m.def_id,
+ tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
+ )
+ .fold_with(&mut collector);
+ let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
+ trait_sig.error_reported()?;
+ let trait_return_ty = trait_sig.output();
+
+ let wf_tys = FxIndexSet::from_iter(
+ unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()),
+ );
+
+ match ocx.eq(&cause, param_env, trait_return_ty, impl_return_ty) {
+ Ok(()) => {}
+ Err(terr) => {
+ let mut diag = struct_span_err!(
+ tcx.sess,
+ cause.span(),
+ E0053,
+ "method `{}` has an incompatible return type for trait",
+ trait_m.name
+ );
+ let hir = tcx.hir();
+ infcx.err_ctxt().note_type_err(
+ &mut diag,
+ &cause,
+ hir.get_if_local(impl_m.def_id)
+ .and_then(|node| node.fn_decl())
+ .map(|decl| (decl.output.span(), "return type in trait".to_owned())),
+ Some(infer::ValuePairs::Terms(ExpectedFound {
+ expected: trait_return_ty.into(),
+ found: impl_return_ty.into(),
+ })),
+ terr,
+ false,
+ false,
+ );
+ return Err(diag.emit());
+ }
+ }
+
+ debug!(?trait_sig, ?impl_sig, "equating function signatures");
+
+ // Unify the whole function signature. We need to do this to fully infer
+ // the lifetimes of the return type, but do this after unifying just the
+ // return types, since we want to avoid duplicating errors from
+ // `compare_method_predicate_entailment`.
+ match ocx.eq(&cause, param_env, trait_sig, impl_sig) {
+ Ok(()) => {}
+ Err(terr) => {
+ // This function gets called during `compare_method_predicate_entailment` when normalizing a
+ // signature that contains RPITIT. When the method signatures don't match, we have to
+ // emit an error now because `compare_method_predicate_entailment` will not report the error
+ // when normalization fails.
+ let emitted = report_trait_method_mismatch(
+ infcx,
+ cause,
+ terr,
+ (trait_m, trait_sig),
+ (impl_m, impl_sig),
+ impl_trait_ref,
+ );
+ return Err(emitted);
+ }
+ }
+
+ // Check that all obligations are satisfied by the implementation's
+ // RPITs.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+ return Err(reported);
+ }
+
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let outlives_environment = OutlivesEnvironment::with_bounds(
+ param_env,
+ Some(infcx),
+ infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
+ );
+ infcx.err_ctxt().check_region_obligations_and_report_errors(
+ impl_m.def_id.expect_local(),
+ &outlives_environment,
+ )?;
+
+ let mut collected_tys = FxHashMap::default();
+ for (def_id, (ty, substs)) in collector.types {
+ match infcx.fully_resolve(ty) {
+ Ok(ty) => {
+ // `ty` contains free regions that we created earlier while liberating the
+ // trait fn signature. However, projection normalization expects `ty` to
+ // contains `def_id`'s early-bound regions.
+ let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
+ debug!(?id_substs, ?substs);
+ let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> =
+ std::iter::zip(substs, id_substs).collect();
+ debug!(?map);
+
+ // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
+ // region substs that are synthesized during AST lowering. These are substs
+ // that are appended to the parent substs (trait and trait method). However,
+ // we're trying to infer the unsubstituted type value of the RPITIT inside
+ // the *impl*, so we can later use the impl's method substs to normalize
+ // an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`).
+ //
+ // Due to the design of RPITITs, during AST lowering, we have no idea that
+ // an impl method corresponds to a trait method with RPITITs in it. Therefore,
+ // we don't have a list of early-bound region substs for the RPITIT in the impl.
+ // Since early region parameters are index-based, we can't just rebase these
+ // (trait method) early-bound region substs onto the impl, and there's no
+ // guarantee that the indices from the trait substs and impl substs line up.
+ // So to fix this, we subtract the number of trait substs and add the number of
+ // impl substs to *renumber* these early-bound regions to their corresponding
+ // indices in the impl's substitutions list.
+ //
+ // Also, we only need to account for a difference in trait and impl substs,
+ // since we previously enforce that the trait method and impl method have the
+ // same generics.
+ let num_trait_substs = trait_to_impl_substs.len();
+ let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
+ let ty = tcx.fold_regions(ty, |region, _| {
+ match region.kind() {
+ // Remap all free regions, which correspond to late-bound regions in the function.
+ ty::ReFree(_) => {}
+ // Remap early-bound regions as long as they don't come from the `impl` itself.
+ ty::ReEarlyBound(ebr) if tcx.parent(ebr.def_id) != impl_m.container_id(tcx) => {}
+ _ => return region,
+ }
+ let Some(ty::ReEarlyBound(e)) = map.get(®ion.into()).map(|r| r.expect_region().kind())
+ else {
+ tcx
+ .sess
+ .delay_span_bug(
+ return_span,
+ "expected ReFree to map to ReEarlyBound"
+ );
+ return tcx.lifetimes.re_static;
+ };
+ tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+ def_id: e.def_id,
+ name: e.name,
+ index: (e.index as usize - num_trait_substs + num_impl_substs) as u32,
+ }))
+ });
+ debug!(%ty);
+ collected_tys.insert(def_id, ty);
+ }
+ Err(err) => {
+ let reported = tcx.sess.delay_span_bug(
+ return_span,
+ format!("could not fully resolve: {ty} => {err:?}"),
+ );
+ collected_tys.insert(def_id, tcx.ty_error_with_guaranteed(reported));
+ }
+ }
+ }
+
+ Ok(&*tcx.arena.alloc(collected_tys))
+}
+
+struct ImplTraitInTraitCollector<'a, 'tcx> {
+ ocx: &'a ObligationCtxt<'a, 'tcx>,
+ types: FxHashMap<DefId, (Ty<'tcx>, ty::SubstsRef<'tcx>)>,
+ span: Span,
+ param_env: ty::ParamEnv<'tcx>,
+ body_id: hir::HirId,
+}
+
+impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> {
+ fn new(
+ ocx: &'a ObligationCtxt<'a, 'tcx>,
+ span: Span,
+ param_env: ty::ParamEnv<'tcx>,
+ body_id: hir::HirId,
+ ) -> Self {
+ ImplTraitInTraitCollector { ocx, types: FxHashMap::default(), span, param_env, body_id }
+ }
+}
+
+impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
+ fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+ self.ocx.infcx.tcx
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ if let ty::Alias(ty::Projection, proj) = ty.kind()
+ && self.tcx().def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
+ {
+ if let Some((ty, _)) = self.types.get(&proj.def_id) {
+ return *ty;
+ }
+ //FIXME(RPITIT): Deny nested RPITIT in substs too
+ if proj.substs.has_escaping_bound_vars() {
+ bug!("FIXME(RPITIT): error here");
+ }
+ // Replace with infer var
+ let infer_ty = self.ocx.infcx.next_ty_var(TypeVariableOrigin {
+ span: self.span,
+ kind: TypeVariableOriginKind::MiscVariable,
+ });
+ self.types.insert(proj.def_id, (infer_ty, proj.substs));
+ // Recurse into bounds
+ for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.def_id).subst_iter_copied(self.tcx(), proj.substs) {
+ let pred = pred.fold_with(self);
+ let pred = self.ocx.normalize(
+ &ObligationCause::misc(self.span, self.body_id),
+ self.param_env,
+ pred,
+ );
+
+ self.ocx.register_obligation(traits::Obligation::new(
+ self.tcx(),
+ ObligationCause::new(
+ self.span,
+ self.body_id,
+ ObligationCauseCode::BindingObligation(proj.def_id, pred_span),
+ ),
+ self.param_env,
+ pred,
+ ));
+ }
+ infer_ty
+ } else {
+ ty.super_fold_with(self)
+ }
+ }
+}
+
+fn report_trait_method_mismatch<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ mut cause: ObligationCause<'tcx>,
+ terr: TypeError<'tcx>,
+ (trait_m, trait_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
+ (impl_m, impl_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
+ impl_trait_ref: ty::TraitRef<'tcx>,
+) -> ErrorGuaranteed {
+ let tcx = infcx.tcx;
+ let (impl_err_span, trait_err_span) =
+ extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
+
+ let mut diag = struct_span_err!(
+ tcx.sess,
+ impl_err_span,
+ E0053,
+ "method `{}` has an incompatible type for trait",
+ trait_m.name
+ );
+ match &terr {
+ TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
+ if trait_m.fn_has_self_parameter =>
+ {
+ let ty = trait_sig.inputs()[0];
+ let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
+ ExplicitSelf::ByValue => "self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
+ _ => format!("self: {ty}"),
+ };
+
+ // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
+ // span points only at the type `Box<Self`>, but we want to cover the whole
+ // argument pattern and type.
+ let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+ ImplItemKind::Fn(ref sig, body) => tcx
+ .hir()
+ .body_param_names(body)
+ .zip(sig.decl.inputs.iter())
+ .map(|(param, ty)| param.span.to(ty.span))
+ .next()
+ .unwrap_or(impl_err_span),
+ _ => bug!("{:?} is not a method", impl_m),
+ };
+
+ diag.span_suggestion(
+ span,
+ "change the self-receiver type to match the trait",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
+ if trait_sig.inputs().len() == *i {
+ // Suggestion to change output type. We do not suggest in `async` functions
+ // to avoid complex logic or incorrect output.
+ match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+ ImplItemKind::Fn(ref sig, _) if !sig.header.asyncness.is_async() => {
+ let msg = "change the output type to match the trait";
+ let ap = Applicability::MachineApplicable;
+ match sig.decl.output {
+ hir::FnRetTy::DefaultReturn(sp) => {
+ let sugg = format!("-> {} ", trait_sig.output());
+ diag.span_suggestion_verbose(sp, msg, sugg, ap);
+ }
+ hir::FnRetTy::Return(hir_ty) => {
+ let sugg = trait_sig.output();
+ diag.span_suggestion(hir_ty.span, msg, sugg, ap);
+ }
+ };
+ }
+ _ => {}
+ };
+ } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
+ diag.span_suggestion(
+ impl_err_span,
+ "change the parameter type to match the trait",
+ trait_ty,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ _ => {}
+ }
+
+ cause.span = impl_err_span;
+ infcx.err_ctxt().note_type_err(
+ &mut diag,
+ &cause,
+ trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
+ Some(infer::ValuePairs::Sigs(ExpectedFound { expected: trait_sig, found: impl_sig })),
+ terr,
+ false,
+ false,
+ );
+
+ return diag.emit();
+}
+
+fn check_region_bounds_on_impl_item<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_m: &ty::AssocItem,
+ trait_m: &ty::AssocItem,
+ delay: bool,
+) -> Result<(), ErrorGuaranteed> {
+ let impl_generics = tcx.generics_of(impl_m.def_id);
+ let impl_params = impl_generics.own_counts().lifetimes;
+
+ let trait_generics = tcx.generics_of(trait_m.def_id);
+ let trait_params = trait_generics.own_counts().lifetimes;
+
+ debug!(
+ "check_region_bounds_on_impl_item: \
+ trait_generics={:?} \
+ impl_generics={:?}",
+ trait_generics, impl_generics
+ );
+
+ // Must have same number of early-bound lifetime parameters.
+ // Unfortunately, if the user screws up the bounds, then this
+ // will change classification between early and late. E.g.,
+ // if in trait we have `<'a,'b:'a>`, and in impl we just have
+ // `<'a,'b>`, then we have 2 early-bound lifetime parameters
+ // in trait but 0 in the impl. But if we report "expected 2
+ // but found 0" it's confusing, because it looks like there
+ // are zero. Since I don't quite know how to phrase things at
+ // the moment, give a kind of vague error message.
+ if trait_params != impl_params {
+ let span = tcx
+ .hir()
+ .get_generics(impl_m.def_id.expect_local())
+ .expect("expected impl item to have generics or else we can't compare them")
+ .span;
+
+ let mut generics_span = None;
+ let mut bounds_span = vec![];
+ let mut where_span = None;
+ if let Some(trait_node) = tcx.hir().get_if_local(trait_m.def_id)
+ && let Some(trait_generics) = trait_node.generics()
+ {
+ generics_span = Some(trait_generics.span);
+ // FIXME: we could potentially look at the impl's bounds to not point at bounds that
+ // *are* present in the impl.
+ for p in trait_generics.predicates {
+ if let hir::WherePredicate::BoundPredicate(pred) = p {
+ for b in pred.bounds {
+ if let hir::GenericBound::Outlives(lt) = b {
+ bounds_span.push(lt.ident.span);
+ }
+ }
+ }
+ }
+ if let Some(impl_node) = tcx.hir().get_if_local(impl_m.def_id)
+ && let Some(impl_generics) = impl_node.generics()
+ {
+ let mut impl_bounds = 0;
+ for p in impl_generics.predicates {
+ if let hir::WherePredicate::BoundPredicate(pred) = p {
+ for b in pred.bounds {
+ if let hir::GenericBound::Outlives(_) = b {
+ impl_bounds += 1;
+ }
+ }
+ }
+ }
+ if impl_bounds == bounds_span.len() {
+ bounds_span = vec![];
+ } else if impl_generics.has_where_clause_predicates {
+ where_span = Some(impl_generics.where_clause_span);
+ }
+ }
+ }
+ let reported = tcx
+ .sess
+ .create_err(LifetimesOrBoundsMismatchOnTrait {
+ span,
+ item_kind: assoc_item_kind_str(impl_m),
+ ident: impl_m.ident(tcx),
+ generics_span,
+ bounds_span,
+ where_span,
+ })
+ .emit_unless(delay);
+ return Err(reported);
+ }
+
+ Ok(())
+}
+
+#[instrument(level = "debug", skip(infcx))]
+fn extract_spans_for_error_reporting<'tcx>(
+ infcx: &infer::InferCtxt<'tcx>,
+ terr: TypeError<'_>,
+ cause: &ObligationCause<'tcx>,
+ impl_m: &ty::AssocItem,
+ trait_m: &ty::AssocItem,
+) -> (Span, Option<Span>) {
+ let tcx = infcx.tcx;
+ let mut impl_args = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+ ImplItemKind::Fn(ref sig, _) => {
+ sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
+ }
+ _ => bug!("{:?} is not a method", impl_m),
+ };
+ let trait_args =
+ trait_m.def_id.as_local().map(|def_id| match tcx.hir().expect_trait_item(def_id).kind {
+ TraitItemKind::Fn(ref sig, _) => {
+ sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
+ }
+ _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
+ });
+
+ match terr {
+ TypeError::ArgumentMutability(i) => {
+ (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
+ }
+ TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
+ (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
+ }
+ _ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)),
+ }
+}
+
+fn compare_self_type<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_m: &ty::AssocItem,
+ impl_m_span: Span,
+ trait_m: &ty::AssocItem,
+ impl_trait_ref: ty::TraitRef<'tcx>,
+) -> Result<(), ErrorGuaranteed> {
+ // Try to give more informative error messages about self typing
+ // mismatches. Note that any mismatch will also be detected
+ // below, where we construct a canonical function type that
+ // includes the self parameter as a normal parameter. It's just
+ // that the error messages you get out of this code are a bit more
+ // inscrutable, particularly for cases where one method has no
+ // self.
+
+ let self_string = |method: &ty::AssocItem| {
+ let untransformed_self_ty = match method.container {
+ ty::ImplContainer => impl_trait_ref.self_ty(),
+ ty::TraitContainer => tcx.types.self_param,
+ };
+ let self_arg_ty = tcx.fn_sig(method.def_id).input(0);
+ let param_env = ty::ParamEnv::reveal_all();
+
+ let infcx = tcx.infer_ctxt().build();
+ let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
+ let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
+ match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
+ ExplicitSelf::ByValue => "self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
+ _ => format!("self: {self_arg_ty}"),
+ }
+ };
+
+ match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) {
+ (false, false) | (true, true) => {}
+
+ (false, true) => {
+ let self_descr = self_string(impl_m);
+ let mut err = struct_span_err!(
+ tcx.sess,
+ impl_m_span,
+ E0185,
+ "method `{}` has a `{}` declaration in the impl, but not in the trait",
+ trait_m.name,
+ self_descr
+ );
+ err.span_label(impl_m_span, format!("`{self_descr}` used in impl"));
+ if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
+ err.span_label(span, format!("trait method declared without `{self_descr}`"));
+ } else {
+ err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
+ }
+ let reported = err.emit();
+ return Err(reported);
+ }
+
+ (true, false) => {
+ let self_descr = self_string(trait_m);
+ let mut err = struct_span_err!(
+ tcx.sess,
+ impl_m_span,
+ E0186,
+ "method `{}` has a `{}` declaration in the trait, but not in the impl",
+ trait_m.name,
+ self_descr
+ );
+ err.span_label(impl_m_span, format!("expected `{self_descr}` in impl"));
+ if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
+ err.span_label(span, format!("`{self_descr}` used in trait"));
+ } else {
+ err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
+ }
+ let reported = err.emit();
+ return Err(reported);
+ }
+ }
+
+ Ok(())
+}
+
+/// Checks that the number of generics on a given assoc item in a trait impl is the same
+/// as the number of generics on the respective assoc item in the trait definition.
+///
+/// For example this code emits the errors in the following code:
+/// ```
+/// trait Trait {
+/// fn foo();
+/// type Assoc<T>;
+/// }
+///
+/// impl Trait for () {
+/// fn foo<T>() {}
+/// //~^ error
+/// type Assoc = u32;
+/// //~^ error
+/// }
+/// ```
+///
+/// Notably this does not error on `foo<T>` implemented as `foo<const N: u8>` or
+/// `foo<const N: u8>` implemented as `foo<const N: u32>`. This is handled in
+/// [`compare_generic_param_kinds`]. This function also does not handle lifetime parameters
+fn compare_number_of_generics<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_: &ty::AssocItem,
+ trait_: &ty::AssocItem,
+ trait_span: Option<Span>,
+ delay: bool,
+) -> Result<(), ErrorGuaranteed> {
+ let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
+ let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();
+
+ // This avoids us erroring on `foo<T>` implemented as `foo<const N: u8>` as this is implemented
+ // in `compare_generic_param_kinds` which will give a nicer error message than something like:
+ // "expected 1 type parameter, found 0 type parameters"
+ if (trait_own_counts.types + trait_own_counts.consts)
+ == (impl_own_counts.types + impl_own_counts.consts)
+ {
+ return Ok(());
+ }
+
+ let matchings = [
+ ("type", trait_own_counts.types, impl_own_counts.types),
+ ("const", trait_own_counts.consts, impl_own_counts.consts),
+ ];
+
+ let item_kind = assoc_item_kind_str(impl_);
+
+ let mut err_occurred = None;
+ for (kind, trait_count, impl_count) in matchings {
+ if impl_count != trait_count {
+ let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| {
+ let mut spans = generics
+ .params
+ .iter()
+ .filter(|p| match p.kind {
+ hir::GenericParamKind::Lifetime {
+ kind: hir::LifetimeParamKind::Elided,
+ } => {
+ // A fn can have an arbitrary number of extra elided lifetimes for the
+ // same signature.
+ !matches!(kind, ty::AssocKind::Fn)
+ }
+ _ => true,
+ })
+ .map(|p| p.span)
+ .collect::<Vec<Span>>();
+ if spans.is_empty() {
+ spans = vec![generics.span]
+ }
+ spans
+ };
+ let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
+ let trait_item = tcx.hir().expect_trait_item(def_id);
+ let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics);
+ let impl_trait_spans: Vec<Span> = trait_item
+ .generics
+ .params
+ .iter()
+ .filter_map(|p| match p.kind {
+ GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
+ _ => None,
+ })
+ .collect();
+ (Some(arg_spans), impl_trait_spans)
+ } else {
+ (trait_span.map(|s| vec![s]), vec![])
+ };
+
+ let impl_item = tcx.hir().expect_impl_item(impl_.def_id.expect_local());
+ let impl_item_impl_trait_spans: Vec<Span> = impl_item
+ .generics
+ .params
+ .iter()
+ .filter_map(|p| match p.kind {
+ GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
+ _ => None,
+ })
+ .collect();
+ let spans = arg_spans(impl_.kind, impl_item.generics);
+ let span = spans.first().copied();
+
+ let mut err = tcx.sess.struct_span_err_with_code(
+ spans,
+ &format!(
+ "{} `{}` has {} {kind} parameter{} but its trait \
+ declaration has {} {kind} parameter{}",
+ item_kind,
+ trait_.name,
+ impl_count,
+ pluralize!(impl_count),
+ trait_count,
+ pluralize!(trait_count),
+ kind = kind,
+ ),
+ DiagnosticId::Error("E0049".into()),
+ );
+
+ let mut suffix = None;
+
+ if let Some(spans) = trait_spans {
+ let mut spans = spans.iter();
+ if let Some(span) = spans.next() {
+ err.span_label(
+ *span,
+ format!(
+ "expected {} {} parameter{}",
+ trait_count,
+ kind,
+ pluralize!(trait_count),
+ ),
+ );
+ }
+ for span in spans {
+ err.span_label(*span, "");
+ }
+ } else {
+ suffix = Some(format!(", expected {trait_count}"));
+ }
+
+ if let Some(span) = span {
+ err.span_label(
+ span,
+ format!(
+ "found {} {} parameter{}{}",
+ impl_count,
+ kind,
+ pluralize!(impl_count),
+ suffix.unwrap_or_else(String::new),
+ ),
+ );
+ }
+
+ for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) {
+ err.span_label(*span, "`impl Trait` introduces an implicit type parameter");
+ }
+
+ let reported = err.emit_unless(delay);
+ err_occurred = Some(reported);
+ }
+ }
+
+ if let Some(reported) = err_occurred { Err(reported) } else { Ok(()) }
+}
+
+fn compare_number_of_method_arguments<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_m: &ty::AssocItem,
+ impl_m_span: Span,
+ trait_m: &ty::AssocItem,
+ trait_item_span: Option<Span>,
+) -> Result<(), ErrorGuaranteed> {
+ let impl_m_fty = tcx.fn_sig(impl_m.def_id);
+ let trait_m_fty = tcx.fn_sig(trait_m.def_id);
+ let trait_number_args = trait_m_fty.inputs().skip_binder().len();
+ let impl_number_args = impl_m_fty.inputs().skip_binder().len();
+ if trait_number_args != impl_number_args {
+ let trait_span = if let Some(def_id) = trait_m.def_id.as_local() {
+ match tcx.hir().expect_trait_item(def_id).kind {
+ TraitItemKind::Fn(ref trait_m_sig, _) => {
+ let pos = if trait_number_args > 0 { trait_number_args - 1 } else { 0 };
+ if let Some(arg) = trait_m_sig.decl.inputs.get(pos) {
+ Some(if pos == 0 {
+ arg.span
+ } else {
+ arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())
+ })
+ } else {
+ trait_item_span
+ }
+ }
+ _ => bug!("{:?} is not a method", impl_m),
+ }
+ } else {
+ trait_item_span
+ };
+ let impl_span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+ ImplItemKind::Fn(ref impl_m_sig, _) => {
+ let pos = if impl_number_args > 0 { impl_number_args - 1 } else { 0 };
+ if let Some(arg) = impl_m_sig.decl.inputs.get(pos) {
+ if pos == 0 {
+ arg.span
+ } else {
+ arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
+ }
+ } else {
+ impl_m_span
+ }
+ }
+ _ => bug!("{:?} is not a method", impl_m),
+ };
+ let mut err = struct_span_err!(
+ tcx.sess,
+ impl_span,
+ E0050,
+ "method `{}` has {} but the declaration in trait `{}` has {}",
+ trait_m.name,
+ potentially_plural_count(impl_number_args, "parameter"),
+ tcx.def_path_str(trait_m.def_id),
+ trait_number_args
+ );
+ if let Some(trait_span) = trait_span {
+ err.span_label(
+ trait_span,
+ format!(
+ "trait requires {}",
+ potentially_plural_count(trait_number_args, "parameter")
+ ),
+ );
+ } else {
+ err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
+ }
+ err.span_label(
+ impl_span,
+ format!(
+ "expected {}, found {}",
+ potentially_plural_count(trait_number_args, "parameter"),
+ impl_number_args
+ ),
+ );
+ let reported = err.emit();
+ return Err(reported);
+ }
+
+ Ok(())
+}
+
+fn compare_synthetic_generics<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_m: &ty::AssocItem,
+ trait_m: &ty::AssocItem,
+) -> Result<(), ErrorGuaranteed> {
+ // FIXME(chrisvittal) Clean up this function, list of FIXME items:
+ // 1. Better messages for the span labels
+ // 2. Explanation as to what is going on
+ // If we get here, we already have the same number of generics, so the zip will
+ // be okay.
+ let mut error_found = None;
+ let impl_m_generics = tcx.generics_of(impl_m.def_id);
+ let trait_m_generics = tcx.generics_of(trait_m.def_id);
+ let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind {
+ GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
+ GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,
+ });
+ let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| match param.kind {
+ GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
+ GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,
+ });
+ for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) in
+ iter::zip(impl_m_type_params, trait_m_type_params)
+ {
+ if impl_synthetic != trait_synthetic {
+ let impl_def_id = impl_def_id.expect_local();
+ let impl_span = tcx.def_span(impl_def_id);
+ let trait_span = tcx.def_span(trait_def_id);
+ let mut err = struct_span_err!(
+ tcx.sess,
+ impl_span,
+ E0643,
+ "method `{}` has incompatible signature for trait",
+ trait_m.name
+ );
+ err.span_label(trait_span, "declaration in trait here");
+ match (impl_synthetic, trait_synthetic) {
+ // The case where the impl method uses `impl Trait` but the trait method uses
+ // explicit generics
+ (true, false) => {
+ err.span_label(impl_span, "expected generic parameter, found `impl Trait`");
+ (|| {
+ // try taking the name from the trait impl
+ // FIXME: this is obviously suboptimal since the name can already be used
+ // as another generic argument
+ let new_name = tcx.opt_item_name(trait_def_id)?;
+ let trait_m = trait_m.def_id.as_local()?;
+ let trait_m = tcx.hir().expect_trait_item(trait_m);
+
+ let impl_m = impl_m.def_id.as_local()?;
+ let impl_m = tcx.hir().expect_impl_item(impl_m);
+
+ // in case there are no generics, take the spot between the function name
+ // and the opening paren of the argument list
+ let new_generics_span = tcx.def_ident_span(impl_def_id)?.shrink_to_hi();
+ // in case there are generics, just replace them
+ let generics_span =
+ impl_m.generics.span.substitute_dummy(new_generics_span);
+ // replace with the generics from the trait
+ let new_generics =
+ tcx.sess.source_map().span_to_snippet(trait_m.generics.span).ok()?;
+
+ err.multipart_suggestion(
+ "try changing the `impl Trait` argument to a generic parameter",
+ vec![
+ // replace `impl Trait` with `T`
+ (impl_span, new_name.to_string()),
+ // replace impl method generics with trait method generics
+ // This isn't quite right, as users might have changed the names
+ // of the generics, but it works for the common case
+ (generics_span, new_generics),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ Some(())
+ })();
+ }
+ // The case where the trait method uses `impl Trait`, but the impl method uses
+ // explicit generics.
+ (false, true) => {
+ err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
+ (|| {
+ let impl_m = impl_m.def_id.as_local()?;
+ let impl_m = tcx.hir().expect_impl_item(impl_m);
+ let input_tys = match impl_m.kind {
+ hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
+ _ => unreachable!(),
+ };
+ struct Visitor(Option<Span>, hir::def_id::LocalDefId);
+ impl<'v> intravisit::Visitor<'v> for Visitor {
+ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+ intravisit::walk_ty(self, ty);
+ if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) =
+ ty.kind
+ && let Res::Def(DefKind::TyParam, def_id) = path.res
+ && def_id == self.1.to_def_id()
+ {
+ self.0 = Some(ty.span);
+ }
+ }
+ }
+ let mut visitor = Visitor(None, impl_def_id);
+ for ty in input_tys {
+ intravisit::Visitor::visit_ty(&mut visitor, ty);
+ }
+ let span = visitor.0?;
+
+ let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds;
+ let bounds = bounds.first()?.span().to(bounds.last()?.span());
+ let bounds = tcx.sess.source_map().span_to_snippet(bounds).ok()?;
+
+ err.multipart_suggestion(
+ "try removing the generic parameter and using `impl Trait` instead",
+ vec![
+ // delete generic parameters
+ (impl_m.generics.span, String::new()),
+ // replace param usage with `impl Trait`
+ (span, format!("impl {bounds}")),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ Some(())
+ })();
+ }
+ _ => unreachable!(),
+ }
+ let reported = err.emit();
+ error_found = Some(reported);
+ }
+ }
+ if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
+}
+
+/// Checks that all parameters in the generics of a given assoc item in a trait impl have
+/// the same kind as the respective generic parameter in the trait def.
+///
+/// For example all 4 errors in the following code are emitted here:
+/// ```
+/// trait Foo {
+/// fn foo<const N: u8>();
+/// type bar<const N: u8>;
+/// fn baz<const N: u32>();
+/// type blah<T>;
+/// }
+///
+/// impl Foo for () {
+/// fn foo<const N: u64>() {}
+/// //~^ error
+/// type bar<const N: u64> {}
+/// //~^ error
+/// fn baz<T>() {}
+/// //~^ error
+/// type blah<const N: i64> = u32;
+/// //~^ error
+/// }
+/// ```
+///
+/// This function does not handle lifetime parameters
+fn compare_generic_param_kinds<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_item: &ty::AssocItem,
+ trait_item: &ty::AssocItem,
+ delay: bool,
+) -> Result<(), ErrorGuaranteed> {
+ assert_eq!(impl_item.kind, trait_item.kind);
+
+ let ty_const_params_of = |def_id| {
+ tcx.generics_of(def_id).params.iter().filter(|param| {
+ matches!(
+ param.kind,
+ GenericParamDefKind::Const { .. } | GenericParamDefKind::Type { .. }
+ )
+ })
+ };
+
+ for (param_impl, param_trait) in
+ iter::zip(ty_const_params_of(impl_item.def_id), ty_const_params_of(trait_item.def_id))
+ {
+ use GenericParamDefKind::*;
+ if match (¶m_impl.kind, ¶m_trait.kind) {
+ (Const { .. }, Const { .. })
+ if tcx.type_of(param_impl.def_id) != tcx.type_of(param_trait.def_id) =>
+ {
+ true
+ }
+ (Const { .. }, Type { .. }) | (Type { .. }, Const { .. }) => true,
+ // this is exhaustive so that anyone adding new generic param kinds knows
+ // to make sure this error is reported for them.
+ (Const { .. }, Const { .. }) | (Type { .. }, Type { .. }) => false,
+ (Lifetime { .. }, _) | (_, Lifetime { .. }) => unreachable!(),
+ } {
+ let param_impl_span = tcx.def_span(param_impl.def_id);
+ let param_trait_span = tcx.def_span(param_trait.def_id);
+
+ let mut err = struct_span_err!(
+ tcx.sess,
+ param_impl_span,
+ E0053,
+ "{} `{}` has an incompatible generic parameter for trait `{}`",
+ assoc_item_kind_str(&impl_item),
+ trait_item.name,
+ &tcx.def_path_str(tcx.parent(trait_item.def_id))
+ );
+
+ let make_param_message = |prefix: &str, param: &ty::GenericParamDef| match param.kind {
+ Const { .. } => {
+ format!("{} const parameter of type `{}`", prefix, tcx.type_of(param.def_id))
+ }
+ Type { .. } => format!("{} type parameter", prefix),
+ Lifetime { .. } => unreachable!(),
+ };
+
+ let trait_header_span = tcx.def_ident_span(tcx.parent(trait_item.def_id)).unwrap();
+ err.span_label(trait_header_span, "");
+ err.span_label(param_trait_span, make_param_message("expected", param_trait));
+
+ let impl_header_span = tcx.def_span(tcx.parent(impl_item.def_id));
+ err.span_label(impl_header_span, "");
+ err.span_label(param_impl_span, make_param_message("found", param_impl));
+
+ let reported = err.emit_unless(delay);
+ return Err(reported);
+ }
+ }
+
+ Ok(())
+}
+
+/// Use `tcx.compare_impl_const` instead
+pub(super) fn compare_impl_const_raw(
+ tcx: TyCtxt<'_>,
+ (impl_const_item_def, trait_const_item_def): (LocalDefId, DefId),
+) -> Result<(), ErrorGuaranteed> {
+ let impl_const_item = tcx.associated_item(impl_const_item_def);
+ let trait_const_item = tcx.associated_item(trait_const_item_def);
+ let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap();
+ debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
+
+ let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
+
+ let infcx = tcx.infer_ctxt().build();
+ let param_env = tcx.param_env(impl_const_item_def.to_def_id());
+ let ocx = ObligationCtxt::new(&infcx);
+
+ // The below is for the most part highly similar to the procedure
+ // for methods above. It is simpler in many respects, especially
+ // because we shouldn't really have to deal with lifetimes or
+ // predicates. In fact some of this should probably be put into
+ // shared functions because of DRY violations...
+ let trait_to_impl_substs = impl_trait_ref.substs;
+
+ // Create a parameter environment that represents the implementation's
+ // method.
+ let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_const_item_def);
+
+ // Compute placeholder form of impl and trait const tys.
+ let impl_ty = tcx.type_of(impl_const_item_def.to_def_id());
+ let trait_ty = tcx.bound_type_of(trait_const_item_def).subst(tcx, trait_to_impl_substs);
+ let mut cause = ObligationCause::new(
+ impl_c_span,
+ impl_c_hir_id,
+ ObligationCauseCode::CompareImplItemObligation {
+ impl_item_def_id: impl_const_item_def,
+ trait_item_def_id: trait_const_item_def,
+ kind: impl_const_item.kind,
+ },
+ );
+
+ // There is no "body" here, so just pass dummy id.
+ let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
+
+ debug!("compare_const_impl: impl_ty={:?}", impl_ty);
+
+ let trait_ty = ocx.normalize(&cause, param_env, trait_ty);
+
+ debug!("compare_const_impl: trait_ty={:?}", trait_ty);
+
+ let err = ocx.sup(&cause, param_env, trait_ty, impl_ty);
+
+ if let Err(terr) = err {
+ debug!(
+ "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
+ impl_ty, trait_ty
+ );
+
+ // Locate the Span containing just the type of the offending impl
+ match tcx.hir().expect_impl_item(impl_const_item_def).kind {
+ ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
+ _ => bug!("{:?} is not a impl const", impl_const_item),
+ }
+
+ let mut diag = struct_span_err!(
+ tcx.sess,
+ cause.span,
+ E0326,
+ "implemented const `{}` has an incompatible type for trait",
+ trait_const_item.name
+ );
+
+ let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| {
+ // Add a label to the Span containing just the type of the const
+ match tcx.hir().expect_trait_item(trait_c_def_id).kind {
+ TraitItemKind::Const(ref ty, _) => ty.span,
+ _ => bug!("{:?} is not a trait const", trait_const_item),
+ }
+ });
+
+ infcx.err_ctxt().note_type_err(
+ &mut diag,
+ &cause,
+ trait_c_span.map(|span| (span, "type in trait".to_owned())),
+ Some(infer::ValuePairs::Terms(ExpectedFound {
+ expected: trait_ty.into(),
+ found: impl_ty.into(),
+ })),
+ terr,
+ false,
+ false,
+ );
+ return Err(diag.emit());
+ };
+
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None));
+ }
+
+ let outlives_environment = OutlivesEnvironment::new(param_env);
+ infcx
+ .err_ctxt()
+ .check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment)?;
+ Ok(())
+}
+
+pub(super) fn compare_impl_ty<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_ty: &ty::AssocItem,
+ impl_ty_span: Span,
+ trait_ty: &ty::AssocItem,
+ impl_trait_ref: ty::TraitRef<'tcx>,
+ trait_item_span: Option<Span>,
+) {
+ debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref);
+
+ let _: Result<(), ErrorGuaranteed> = (|| {
+ compare_number_of_generics(tcx, impl_ty, trait_ty, trait_item_span, false)?;
+
+ compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
+
+ let sp = tcx.def_span(impl_ty.def_id);
+ compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
+
+ check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
+ })();
+}
+
+/// The equivalent of [compare_method_predicate_entailment], but for associated types
+/// instead of associated functions.
+fn compare_type_predicate_entailment<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_ty: &ty::AssocItem,
+ impl_ty_span: Span,
+ trait_ty: &ty::AssocItem,
+ impl_trait_ref: ty::TraitRef<'tcx>,
+) -> Result<(), ErrorGuaranteed> {
+ let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
+ let trait_to_impl_substs =
+ impl_substs.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.substs);
+
+ let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id);
+ let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
+
+ check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
+
+ let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs);
+
+ if impl_ty_own_bounds.is_empty() {
+ // Nothing to check.
+ return Ok(());
+ }
+
+ // This `HirId` should be used for the `body_id` field on each
+ // `ObligationCause` (and the `FnCtxt`). This is what
+ // `regionck_item` expects.
+ let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
+ debug!("compare_type_predicate_entailment: trait_to_impl_substs={:?}", trait_to_impl_substs);
+
+ // The predicates declared by the impl definition, the trait and the
+ // associated type in the trait are assumed.
+ let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap());
+ let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
+ hybrid_preds
+ .predicates
+ .extend(trait_ty_predicates.instantiate_own(tcx, trait_to_impl_substs).predicates);
+
+ debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
+
+ let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
+ let param_env = ty::ParamEnv::new(
+ tcx.intern_predicates(&hybrid_preds.predicates),
+ Reveal::UserFacing,
+ hir::Constness::NotConst,
+ );
+ let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
+ let infcx = tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(&infcx);
+
+ debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
+
+ assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
+ for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
+ {
+ let cause = ObligationCause::misc(span, impl_ty_hir_id);
+ let predicate = ocx.normalize(&cause, param_env, predicate);
+
+ let cause = ObligationCause::new(
+ span,
+ impl_ty_hir_id,
+ ObligationCauseCode::CompareImplItemObligation {
+ impl_item_def_id: impl_ty.def_id.expect_local(),
+ trait_item_def_id: trait_ty.def_id,
+ kind: impl_ty.kind,
+ },
+ );
+ ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
+ }
+
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+ return Err(reported);
+ }
+
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let outlives_environment = OutlivesEnvironment::new(param_env);
+ infcx.err_ctxt().check_region_obligations_and_report_errors(
+ impl_ty.def_id.expect_local(),
+ &outlives_environment,
+ )?;
+
+ Ok(())
+}
+
+/// 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.
+#[instrument(level = "debug", skip(tcx))]
+pub(super) fn check_type_bounds<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ty: &ty::AssocItem,
+ impl_ty: &ty::AssocItem,
+ impl_ty_span: Span,
+ impl_trait_ref: ty::TraitRef<'tcx>,
+) -> Result<(), ErrorGuaranteed> {
+ // Given
+ //
+ // impl<A, B> Foo<u32> for (A, B) {
+ // type Bar<C> =...
+ // }
+ //
+ // - `impl_trait_ref` would be `<(A, B) as Foo<u32>>
+ // - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
+ // - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from
+ // the *trait* with the generic associated type parameters (as bound vars).
+ //
+ // A note regarding the use of bound vars here:
+ // Imagine as an example
+ // ```
+ // trait Family {
+ // type Member<C: Eq>;
+ // }
+ //
+ // impl Family for VecFamily {
+ // type Member<C: Eq> = i32;
+ // }
+ // ```
+ // Here, we would generate
+ // ```notrust
+ // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
+ // ```
+ // when we really would like to generate
+ // ```notrust
+ // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
+ // ```
+ // But, this is probably fine, because although the first clause can be used with types C that
+ // do not implement Eq, for it to cause some kind of problem, there would have to be a
+ // VecFamily::Member<X> for some type X where !(X: Eq), that appears in the value of type
+ // Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing
+ // elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in
+ // the trait (notably, that X: Eq and T: Family).
+ let defs: &ty::Generics = tcx.generics_of(impl_ty.def_id);
+ let mut substs = smallvec::SmallVec::with_capacity(defs.count());
+ if let Some(def_id) = defs.parent {
+ let parent_defs = tcx.generics_of(def_id);
+ InternalSubsts::fill_item(&mut substs, tcx, parent_defs, &mut |param, _| {
+ tcx.mk_param_from_def(param)
+ });
+ }
+ let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
+ smallvec::SmallVec::with_capacity(defs.count());
+ InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param.kind {
+ GenericParamDefKind::Type { .. } => {
+ let kind = ty::BoundTyKind::Param(param.name);
+ let bound_var = ty::BoundVariableKind::Ty(kind);
+ bound_vars.push(bound_var);
+ tcx.mk_ty(ty::Bound(
+ ty::INNERMOST,
+ ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
+ ))
+ .into()
+ }
+ GenericParamDefKind::Lifetime => {
+ let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
+ let bound_var = ty::BoundVariableKind::Region(kind);
+ bound_vars.push(bound_var);
+ tcx.mk_region(ty::ReLateBound(
+ ty::INNERMOST,
+ ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
+ ))
+ .into()
+ }
+ GenericParamDefKind::Const { .. } => {
+ let bound_var = ty::BoundVariableKind::Const;
+ bound_vars.push(bound_var);
+ tcx.mk_const(
+ ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1)),
+ tcx.type_of(param.def_id),
+ )
+ .into()
+ }
+ });
+ let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
+ let impl_ty_substs = tcx.intern_substs(&substs);
+ let container_id = impl_ty.container_id(tcx);
+
+ let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
+ let impl_ty_value = tcx.type_of(impl_ty.def_id);
+
+ let param_env = tcx.param_env(impl_ty.def_id);
+
+ // When checking something like
+ //
+ // trait X { type Y: PartialEq<<Self as X>::Y> }
+ // impl X for T { default type Y = S; }
+ //
+ // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
+ // we want <T as X>::Y to normalize to S. This is valid because we are
+ // checking the default value specifically here. Add this equality to the
+ // ParamEnv for normalization specifically.
+ let normalize_param_env = {
+ let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
+ match impl_ty_value.kind() {
+ ty::Alias(ty::Projection, proj)
+ if proj.def_id == trait_ty.def_id && proj.substs == rebased_substs =>
+ {
+ // Don't include this predicate if the projected type is
+ // exactly the same as the projection. This can occur in
+ // (somewhat dubious) code like this:
+ //
+ // impl<T> X for T where T: X { type Y = <T as X>::Y; }
+ }
+ _ => predicates.push(
+ ty::Binder::bind_with_vars(
+ ty::ProjectionPredicate {
+ projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_substs),
+ term: impl_ty_value.into(),
+ },
+ bound_vars,
+ )
+ .to_predicate(tcx),
+ ),
+ };
+ ty::ParamEnv::new(
+ tcx.intern_predicates(&predicates),
+ Reveal::UserFacing,
+ param_env.constness(),
+ )
+ };
+ debug!(?normalize_param_env);
+
+ let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
+ let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
+ let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
+
+ let infcx = tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(&infcx);
+
+ let assumed_wf_types =
+ ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local());
+
+ let normalize_cause = ObligationCause::new(
+ impl_ty_span,
+ impl_ty_hir_id,
+ ObligationCauseCode::CheckAssociatedTypeBounds {
+ impl_item_def_id: impl_ty.def_id.expect_local(),
+ trait_item_def_id: trait_ty.def_id,
+ },
+ );
+ let mk_cause = |span: Span| {
+ let code = if span.is_dummy() {
+ traits::ItemObligation(trait_ty.def_id)
+ } else {
+ traits::BindingObligation(trait_ty.def_id, span)
+ };
+ ObligationCause::new(impl_ty_span, impl_ty_hir_id, code)
+ };
+
+ let obligations = tcx
+ .bound_explicit_item_bounds(trait_ty.def_id)
+ .subst_iter_copied(tcx, rebased_substs)
+ .map(|(concrete_ty_bound, span)| {
+ debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
+ traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
+ })
+ .collect();
+ debug!("check_type_bounds: item_bounds={:?}", obligations);
+
+ for mut obligation in util::elaborate_obligations(tcx, obligations) {
+ let normalized_predicate =
+ ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate);
+ debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
+ obligation.predicate = normalized_predicate;
+
+ ocx.register_obligation(obligation);
+ }
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+ return Err(reported);
+ }
+
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types);
+ let outlives_environment =
+ OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
+
+ infcx.err_ctxt().check_region_obligations_and_report_errors(
+ impl_ty.def_id.expect_local(),
+ &outlives_environment,
+ )?;
+
+ let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ for (key, value) in constraints {
+ infcx
+ .err_ctxt()
+ .report_mismatched_types(
+ &ObligationCause::misc(
+ value.hidden_type.span,
+ tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()),
+ ),
+ tcx.mk_opaque(key.def_id.to_def_id(), key.substs),
+ value.hidden_type.ty,
+ TypeError::Mismatch,
+ )
+ .emit();
+ }
+
+ Ok(())
+}
+
+fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
+ match impl_item.kind {
+ ty::AssocKind::Const => "const",
+ ty::AssocKind::Fn => "method",
+ ty::AssocKind::Type => "type",
+ }
+}
+++ /dev/null
-use super::potentially_plural_count;
-use crate::errors::LifetimesOrBoundsMismatchOnTrait;
-use hir::def_id::{DefId, LocalDefId};
-use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
-use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
-use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::intravisit;
-use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
-use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
-use rustc_infer::traits::util;
-use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::{
- self, DefIdTree, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
-};
-use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
-use rustc_span::Span;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
-use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
-use rustc_trait_selection::traits::{
- self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
-};
-use std::iter;
-
-/// Checks that a method from an impl conforms to the signature of
-/// the same method as declared in the trait.
-///
-/// # Parameters
-///
-/// - `impl_m`: type of the method we are checking
-/// - `impl_m_span`: span to use for reporting errors
-/// - `trait_m`: the method in the trait
-/// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
-pub(crate) fn compare_impl_method<'tcx>(
- tcx: TyCtxt<'tcx>,
- impl_m: &ty::AssocItem,
- trait_m: &ty::AssocItem,
- impl_trait_ref: ty::TraitRef<'tcx>,
- trait_item_span: Option<Span>,
-) {
- debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
-
- let impl_m_span = tcx.def_span(impl_m.def_id);
-
- if let Err(_) = compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref) {
- return;
- }
-
- if let Err(_) = compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false) {
- return;
- }
-
- if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, false) {
- return;
- }
-
- if let Err(_) =
- compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
- {
- return;
- }
-
- if let Err(_) = compare_synthetic_generics(tcx, impl_m, trait_m) {
- return;
- }
-
- if let Err(_) = compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span) {
- return;
- }
-
- if let Err(_) = compare_predicate_entailment(
- tcx,
- impl_m,
- impl_m_span,
- trait_m,
- impl_trait_ref,
- CheckImpliedWfMode::Check,
- ) {
- return;
- }
-}
-
-/// This function is best explained by example. Consider a trait:
-///
-/// trait Trait<'t, T> {
-/// // `trait_m`
-/// fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
-/// }
-///
-/// And an impl:
-///
-/// impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
-/// // `impl_m`
-/// fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo;
-/// }
-///
-/// We wish to decide if those two method types are compatible.
-/// For this we have to show that, assuming the bounds of the impl hold, the
-/// bounds of `trait_m` imply the bounds of `impl_m`.
-///
-/// We start out with `trait_to_impl_substs`, that maps the trait
-/// type parameters to impl type parameters. This is taken from the
-/// impl trait reference:
-///
-/// trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
-///
-/// We create a mapping `dummy_substs` that maps from the impl type
-/// parameters to fresh types and regions. For type parameters,
-/// this is the identity transform, but we could as well use any
-/// placeholder types. For regions, we convert from bound to free
-/// regions (Note: but only early-bound regions, i.e., those
-/// declared on the impl or used in type parameter bounds).
-///
-/// impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
-///
-/// 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:
-///
-/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo
-///
-/// 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_placeholder_substs`, and also adding a mapping for the method
-/// type parameters. We extend the mapping to also include
-/// the method parameters.
-///
-/// trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
-///
-/// Applying this to the trait method type yields:
-///
-/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo
-///
-/// This type is also the same but the name of the bound region (`'a`
-/// vs `'b`). However, the normal subtyping rules on fn types handle
-/// this kind of equivalency just fine.
-///
-/// We now use these substitutions to ensure that all declared bounds are
-/// satisfied by the implementation's method.
-///
-/// We do this by creating a parameter environment which contains a
-/// 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 and check that
-/// they hold.
-#[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))]
-fn compare_predicate_entailment<'tcx>(
- tcx: TyCtxt<'tcx>,
- impl_m: &ty::AssocItem,
- impl_m_span: Span,
- trait_m: &ty::AssocItem,
- impl_trait_ref: ty::TraitRef<'tcx>,
- check_implied_wf: CheckImpliedWfMode,
-) -> Result<(), ErrorGuaranteed> {
- let trait_to_impl_substs = impl_trait_ref.substs;
-
- // This node-id should be used for the `body_id` field on each
- // `ObligationCause` (and the `FnCtxt`).
- //
- // FIXME(@lcnr): remove that after removing `cause.body_id` from
- // obligations.
- let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- let cause = ObligationCause::new(
- impl_m_span,
- impl_m_hir_id,
- ObligationCauseCode::CompareImplItemObligation {
- impl_item_def_id: impl_m.def_id.expect_local(),
- trait_item_def_id: trait_m.def_id,
- kind: impl_m.kind,
- },
- );
-
- // Create mapping from impl to placeholder.
- let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
-
- // Create mapping from trait to placeholder.
- let trait_to_placeholder_substs =
- impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
- debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs);
-
- let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
- let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
-
- // Check region bounds.
- check_region_bounds_on_impl_item(tcx, impl_m, trait_m, false)?;
-
- // Create obligations for each predicate declared by the impl
- // definition in the context of the trait's parameter
- // environment. We can't just use `impl_env.caller_bounds`,
- // however, because we want to replace all late-bound regions with
- // region variables.
- let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
- let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
-
- debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
-
- // This is the only tricky bit of the new way we check implementation methods
- // We need to build a set of predicates where only the method-level bounds
- // are from the trait and we assume all other bounds from the implementation
- // to be previously satisfied.
- //
- // We then register the obligations from the impl_m and check to see
- // if all constraints hold.
- hybrid_preds
- .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
- // the new hybrid bounds we computed.
- let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
- let param_env = ty::ParamEnv::new(
- tcx.intern_predicates(&hybrid_preds.predicates),
- Reveal::UserFacing,
- hir::Constness::NotConst,
- );
- let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
-
- let infcx = &tcx.infer_ctxt().build();
- let ocx = ObligationCtxt::new(infcx);
-
- debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
-
- let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
- for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
- let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
- let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
-
- let cause = ObligationCause::new(
- span,
- impl_m_hir_id,
- ObligationCauseCode::CompareImplItemObligation {
- impl_item_def_id: impl_m.def_id.expect_local(),
- trait_item_def_id: trait_m.def_id,
- kind: impl_m.kind,
- },
- );
- ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
- }
-
- // We now need to check that the signature of the impl method is
- // compatible with that of the trait method. We do this by
- // checking that `impl_fty <: trait_fty`.
- //
- // FIXME. Unfortunately, this doesn't quite work right now because
- // associated type normalization is not integrated into subtype
- // checks. For the comparison to be valid, we need to
- // normalize the associated types in the impl/trait methods
- // first. However, because function types bind regions, just
- // calling `normalize_associated_types_in` would have no effect on
- // any associated types appearing in the fn arguments or return
- // type.
-
- // Compute placeholder form of impl and trait method tys.
- let tcx = infcx.tcx;
-
- let mut wf_tys = FxIndexSet::default();
-
- let unnormalized_impl_sig = infcx.replace_bound_vars_with_fresh_vars(
- impl_m_span,
- infer::HigherRankedType,
- tcx.fn_sig(impl_m.def_id),
- );
- let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig));
-
- let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
- let impl_fty = ocx.normalize(&norm_cause, param_env, unnormalized_impl_fty);
- debug!("compare_impl_method: impl_fty={:?}", impl_fty);
-
- let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
- let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
-
- // Next, add all inputs and output as well-formed tys. Importantly,
- // we have to do this before normalization, since the normalized ty may
- // not contain the input parameters. See issue #87748.
- wf_tys.extend(trait_sig.inputs_and_output.iter());
- let trait_sig = ocx.normalize(&norm_cause, param_env, trait_sig);
- // We also have to add the normalized trait signature
- // as we don't normalize during implied bounds computation.
- wf_tys.extend(trait_sig.inputs_and_output.iter());
- let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
-
- debug!("compare_impl_method: trait_fty={:?}", trait_fty);
-
- // FIXME: We'd want to keep more accurate spans than "the method signature" when
- // processing the comparison between the trait and impl fn, but we sadly lose them
- // and point at the whole signature when a trait bound or specific input or output
- // type would be more appropriate. In other places we have a `Vec<Span>`
- // corresponding to their `Vec<Predicate>`, but we don't have that here.
- // Fixing this would improve the output of test `issue-83765.rs`.
- let result = ocx.sup(&cause, param_env, trait_fty, impl_fty);
-
- if let Err(terr) = result {
- debug!(?terr, "sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
-
- let emitted = report_trait_method_mismatch(
- &infcx,
- cause,
- terr,
- (trait_m, trait_fty),
- (impl_m, impl_fty),
- trait_sig,
- impl_trait_ref,
- );
- return Err(emitted);
- }
-
- if check_implied_wf == CheckImpliedWfMode::Check {
- // We need to check that the impl's args are well-formed given
- // the hybrid param-env (impl + trait method where-clauses).
- ocx.register_obligation(traits::Obligation::new(
- infcx.tcx,
- ObligationCause::dummy(),
- param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
- ));
- }
- let emit_implied_wf_lint = || {
- infcx.tcx.struct_span_lint_hir(
- rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
- impl_m_hir_id,
- infcx.tcx.def_span(impl_m.def_id),
- "impl method assumes more implied bounds than the corresponding trait method",
- |lint| lint,
- );
- };
-
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- match check_implied_wf {
- CheckImpliedWfMode::Check => {
- return compare_predicate_entailment(
- tcx,
- impl_m,
- impl_m_span,
- trait_m,
- impl_trait_ref,
- CheckImpliedWfMode::Skip,
- )
- .map(|()| {
- // If the skip-mode was successful, emit a lint.
- emit_implied_wf_lint();
- });
- }
- CheckImpliedWfMode::Skip => {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
- return Err(reported);
- }
- }
- }
-
- // Finally, resolve all regions. This catches wily misuses of
- // lifetime parameters.
- let outlives_env = OutlivesEnvironment::with_bounds(
- param_env,
- Some(infcx),
- infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys.clone()),
- );
- infcx.process_registered_region_obligations(
- outlives_env.region_bound_pairs(),
- outlives_env.param_env,
- );
- let errors = infcx.resolve_regions(&outlives_env);
- if !errors.is_empty() {
- // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
- // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors`
- match check_implied_wf {
- CheckImpliedWfMode::Check => {
- return compare_predicate_entailment(
- tcx,
- impl_m,
- impl_m_span,
- trait_m,
- impl_trait_ref,
- CheckImpliedWfMode::Skip,
- )
- .map(|()| {
- // If the skip-mode was successful, emit a lint.
- emit_implied_wf_lint();
- });
- }
- CheckImpliedWfMode::Skip => {
- if infcx.tainted_by_errors().is_none() {
- infcx.err_ctxt().report_region_errors(impl_m.def_id.expect_local(), &errors);
- }
- return Err(tcx
- .sess
- .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"));
- }
- }
- }
-
- Ok(())
-}
-
-#[derive(Debug, PartialEq, Eq)]
-enum CheckImpliedWfMode {
- /// Checks implied well-formedness of the impl method. If it fails, we will
- /// re-check with `Skip`, and emit a lint if it succeeds.
- Check,
- /// Skips checking implied well-formedness of the impl method, but will emit
- /// a lint if the `compare_predicate_entailment` succeeded. This means that
- /// the reason that we had failed earlier during `Check` was due to the impl
- /// having stronger requirements than the trait.
- Skip,
-}
-
-fn compare_asyncness<'tcx>(
- tcx: TyCtxt<'tcx>,
- impl_m: &ty::AssocItem,
- impl_m_span: Span,
- trait_m: &ty::AssocItem,
- trait_item_span: Option<Span>,
-) -> Result<(), ErrorGuaranteed> {
- if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
- match tcx.fn_sig(impl_m.def_id).skip_binder().output().kind() {
- ty::Alias(ty::Opaque, ..) => {
- // allow both `async fn foo()` and `fn foo() -> impl Future`
- }
- ty::Error(rustc_errors::ErrorGuaranteed { .. }) => {
- // We don't know if it's ok, but at least it's already an error.
- }
- _ => {
- return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync {
- span: impl_m_span,
- method_name: trait_m.name,
- trait_item_span,
- }));
- }
- };
- }
-
- Ok(())
-}
-
-#[instrument(skip(tcx), level = "debug", ret)]
-pub fn collect_trait_impl_trait_tys<'tcx>(
- tcx: TyCtxt<'tcx>,
- def_id: DefId,
-) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
- let impl_m = tcx.opt_associated_item(def_id).unwrap();
- let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
- let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
- let param_env = tcx.param_env(def_id);
-
- // First, check a few of the same thing as `compare_impl_method`, just so we don't ICE during substitutions later.
- compare_number_of_generics(tcx, impl_m, trait_m, tcx.hir().span_if_local(impl_m.def_id), true)?;
- compare_generic_param_kinds(tcx, impl_m, trait_m, true)?;
- check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?;
-
- let trait_to_impl_substs = impl_trait_ref.substs;
-
- let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
- let cause = ObligationCause::new(
- return_span,
- impl_m_hir_id,
- ObligationCauseCode::CompareImplItemObligation {
- impl_item_def_id: impl_m.def_id.expect_local(),
- trait_item_def_id: trait_m.def_id,
- kind: impl_m.kind,
- },
- );
-
- // Create mapping from impl to placeholder.
- let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
-
- // Create mapping from trait to placeholder.
- let trait_to_placeholder_substs =
- impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
-
- let infcx = &tcx.infer_ctxt().build();
- let ocx = ObligationCtxt::new(infcx);
-
- // Normalize the impl signature with fresh variables for lifetime inference.
- let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
- let impl_sig = ocx.normalize(
- &norm_cause,
- param_env,
- infcx.replace_bound_vars_with_fresh_vars(
- return_span,
- infer::HigherRankedType,
- tcx.fn_sig(impl_m.def_id),
- ),
- );
- impl_sig.error_reported()?;
- let impl_return_ty = impl_sig.output();
-
- // Normalize the trait signature with liberated bound vars, passing it through
- // the ImplTraitInTraitCollector, which gathers all of the RPITITs and replaces
- // them with inference variables.
- // We will use these inference variables to collect the hidden types of RPITITs.
- let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
- let unnormalized_trait_sig = tcx
- .liberate_late_bound_regions(
- impl_m.def_id,
- tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
- )
- .fold_with(&mut collector);
- let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
- trait_sig.error_reported()?;
- let trait_return_ty = trait_sig.output();
-
- let wf_tys = FxIndexSet::from_iter(
- unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()),
- );
-
- match ocx.eq(&cause, param_env, trait_return_ty, impl_return_ty) {
- Ok(()) => {}
- Err(terr) => {
- let mut diag = struct_span_err!(
- tcx.sess,
- cause.span(),
- E0053,
- "method `{}` has an incompatible return type for trait",
- trait_m.name
- );
- let hir = tcx.hir();
- infcx.err_ctxt().note_type_err(
- &mut diag,
- &cause,
- hir.get_if_local(impl_m.def_id)
- .and_then(|node| node.fn_decl())
- .map(|decl| (decl.output.span(), "return type in trait".to_owned())),
- Some(infer::ValuePairs::Terms(ExpectedFound {
- expected: trait_return_ty.into(),
- found: impl_return_ty.into(),
- })),
- terr,
- false,
- false,
- );
- return Err(diag.emit());
- }
- }
-
- debug!(?trait_sig, ?impl_sig, "equating function signatures");
-
- let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
- let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
-
- // Unify the whole function signature. We need to do this to fully infer
- // the lifetimes of the return type, but do this after unifying just the
- // return types, since we want to avoid duplicating errors from
- // `compare_predicate_entailment`.
- match ocx.eq(&cause, param_env, trait_fty, impl_fty) {
- Ok(()) => {}
- Err(terr) => {
- // This function gets called during `compare_predicate_entailment` when normalizing a
- // signature that contains RPITIT. When the method signatures don't match, we have to
- // emit an error now because `compare_predicate_entailment` will not report the error
- // when normalization fails.
- let emitted = report_trait_method_mismatch(
- infcx,
- cause,
- terr,
- (trait_m, trait_fty),
- (impl_m, impl_fty),
- trait_sig,
- impl_trait_ref,
- );
- return Err(emitted);
- }
- }
-
- // Check that all obligations are satisfied by the implementation's
- // RPITs.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
- return Err(reported);
- }
-
- // Finally, resolve all regions. This catches wily misuses of
- // lifetime parameters.
- let outlives_environment = OutlivesEnvironment::with_bounds(
- param_env,
- Some(infcx),
- infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
- );
- infcx.check_region_obligations_and_report_errors(
- impl_m.def_id.expect_local(),
- &outlives_environment,
- );
-
- let mut collected_tys = FxHashMap::default();
- for (def_id, (ty, substs)) in collector.types {
- match infcx.fully_resolve(ty) {
- Ok(ty) => {
- // `ty` contains free regions that we created earlier while liberating the
- // trait fn signature. However, projection normalization expects `ty` to
- // contains `def_id`'s early-bound regions.
- let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
- debug!(?id_substs, ?substs);
- let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> =
- std::iter::zip(substs, id_substs).collect();
- debug!(?map);
-
- // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
- // region substs that are synthesized during AST lowering. These are substs
- // that are appended to the parent substs (trait and trait method). However,
- // we're trying to infer the unsubstituted type value of the RPITIT inside
- // the *impl*, so we can later use the impl's method substs to normalize
- // an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`).
- //
- // Due to the design of RPITITs, during AST lowering, we have no idea that
- // an impl method corresponds to a trait method with RPITITs in it. Therefore,
- // we don't have a list of early-bound region substs for the RPITIT in the impl.
- // Since early region parameters are index-based, we can't just rebase these
- // (trait method) early-bound region substs onto the impl, and there's no
- // guarantee that the indices from the trait substs and impl substs line up.
- // So to fix this, we subtract the number of trait substs and add the number of
- // impl substs to *renumber* these early-bound regions to their corresponding
- // indices in the impl's substitutions list.
- //
- // Also, we only need to account for a difference in trait and impl substs,
- // since we previously enforce that the trait method and impl method have the
- // same generics.
- let num_trait_substs = trait_to_impl_substs.len();
- let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
- let ty = tcx.fold_regions(ty, |region, _| {
- match region.kind() {
- // Remap all free regions, which correspond to late-bound regions in the function.
- ty::ReFree(_) => {}
- // Remap early-bound regions as long as they don't come from the `impl` itself.
- ty::ReEarlyBound(ebr) if tcx.parent(ebr.def_id) != impl_m.container_id(tcx) => {}
- _ => return region,
- }
- let Some(ty::ReEarlyBound(e)) = map.get(®ion.into()).map(|r| r.expect_region().kind())
- else {
- tcx
- .sess
- .delay_span_bug(
- return_span,
- "expected ReFree to map to ReEarlyBound"
- );
- return tcx.lifetimes.re_static;
- };
- tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
- def_id: e.def_id,
- name: e.name,
- index: (e.index as usize - num_trait_substs + num_impl_substs) as u32,
- }))
- });
- debug!(%ty);
- collected_tys.insert(def_id, ty);
- }
- Err(err) => {
- let reported = tcx.sess.delay_span_bug(
- return_span,
- format!("could not fully resolve: {ty} => {err:?}"),
- );
- collected_tys.insert(def_id, tcx.ty_error_with_guaranteed(reported));
- }
- }
- }
-
- Ok(&*tcx.arena.alloc(collected_tys))
-}
-
-struct ImplTraitInTraitCollector<'a, 'tcx> {
- ocx: &'a ObligationCtxt<'a, 'tcx>,
- types: FxHashMap<DefId, (Ty<'tcx>, ty::SubstsRef<'tcx>)>,
- span: Span,
- param_env: ty::ParamEnv<'tcx>,
- body_id: hir::HirId,
-}
-
-impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> {
- fn new(
- ocx: &'a ObligationCtxt<'a, 'tcx>,
- span: Span,
- param_env: ty::ParamEnv<'tcx>,
- body_id: hir::HirId,
- ) -> Self {
- ImplTraitInTraitCollector { ocx, types: FxHashMap::default(), span, param_env, body_id }
- }
-}
-
-impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
- fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
- self.ocx.infcx.tcx
- }
-
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- if let ty::Alias(ty::Projection, proj) = ty.kind()
- && self.tcx().def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
- {
- if let Some((ty, _)) = self.types.get(&proj.def_id) {
- return *ty;
- }
- //FIXME(RPITIT): Deny nested RPITIT in substs too
- if proj.substs.has_escaping_bound_vars() {
- bug!("FIXME(RPITIT): error here");
- }
- // Replace with infer var
- let infer_ty = self.ocx.infcx.next_ty_var(TypeVariableOrigin {
- span: self.span,
- kind: TypeVariableOriginKind::MiscVariable,
- });
- self.types.insert(proj.def_id, (infer_ty, proj.substs));
- // Recurse into bounds
- for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.def_id).subst_iter_copied(self.tcx(), proj.substs) {
- let pred = pred.fold_with(self);
- let pred = self.ocx.normalize(
- &ObligationCause::misc(self.span, self.body_id),
- self.param_env,
- pred,
- );
-
- self.ocx.register_obligation(traits::Obligation::new(
- self.tcx(),
- ObligationCause::new(
- self.span,
- self.body_id,
- ObligationCauseCode::BindingObligation(proj.def_id, pred_span),
- ),
- self.param_env,
- pred,
- ));
- }
- infer_ty
- } else {
- ty.super_fold_with(self)
- }
- }
-}
-
-fn report_trait_method_mismatch<'tcx>(
- infcx: &InferCtxt<'tcx>,
- mut cause: ObligationCause<'tcx>,
- terr: TypeError<'tcx>,
- (trait_m, trait_fty): (&ty::AssocItem, Ty<'tcx>),
- (impl_m, impl_fty): (&ty::AssocItem, Ty<'tcx>),
- trait_sig: ty::FnSig<'tcx>,
- impl_trait_ref: ty::TraitRef<'tcx>,
-) -> ErrorGuaranteed {
- let tcx = infcx.tcx;
- let (impl_err_span, trait_err_span) =
- extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
-
- let mut diag = struct_span_err!(
- tcx.sess,
- impl_err_span,
- E0053,
- "method `{}` has an incompatible type for trait",
- trait_m.name
- );
- match &terr {
- TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
- if trait_m.fn_has_self_parameter =>
- {
- let ty = trait_sig.inputs()[0];
- let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
- ExplicitSelf::ByValue => "self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
- _ => format!("self: {ty}"),
- };
-
- // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
- // span points only at the type `Box<Self`>, but we want to cover the whole
- // argument pattern and type.
- let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref sig, body) => tcx
- .hir()
- .body_param_names(body)
- .zip(sig.decl.inputs.iter())
- .map(|(param, ty)| param.span.to(ty.span))
- .next()
- .unwrap_or(impl_err_span),
- _ => bug!("{:?} is not a method", impl_m),
- };
-
- diag.span_suggestion(
- span,
- "change the self-receiver type to match the trait",
- sugg,
- Applicability::MachineApplicable,
- );
- }
- TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
- if trait_sig.inputs().len() == *i {
- // Suggestion to change output type. We do not suggest in `async` functions
- // to avoid complex logic or incorrect output.
- match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref sig, _) if !sig.header.asyncness.is_async() => {
- let msg = "change the output type to match the trait";
- let ap = Applicability::MachineApplicable;
- match sig.decl.output {
- hir::FnRetTy::DefaultReturn(sp) => {
- let sugg = format!("-> {} ", trait_sig.output());
- diag.span_suggestion_verbose(sp, msg, sugg, ap);
- }
- hir::FnRetTy::Return(hir_ty) => {
- let sugg = trait_sig.output();
- diag.span_suggestion(hir_ty.span, msg, sugg, ap);
- }
- };
- }
- _ => {}
- };
- } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
- diag.span_suggestion(
- impl_err_span,
- "change the parameter type to match the trait",
- trait_ty,
- Applicability::MachineApplicable,
- );
- }
- }
- _ => {}
- }
-
- cause.span = impl_err_span;
- infcx.err_ctxt().note_type_err(
- &mut diag,
- &cause,
- trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
- Some(infer::ValuePairs::Terms(ExpectedFound {
- expected: trait_fty.into(),
- found: impl_fty.into(),
- })),
- terr,
- false,
- false,
- );
-
- return diag.emit();
-}
-
-fn check_region_bounds_on_impl_item<'tcx>(
- tcx: TyCtxt<'tcx>,
- impl_m: &ty::AssocItem,
- trait_m: &ty::AssocItem,
- delay: bool,
-) -> Result<(), ErrorGuaranteed> {
- let impl_generics = tcx.generics_of(impl_m.def_id);
- let impl_params = impl_generics.own_counts().lifetimes;
-
- let trait_generics = tcx.generics_of(trait_m.def_id);
- let trait_params = trait_generics.own_counts().lifetimes;
-
- debug!(
- "check_region_bounds_on_impl_item: \
- trait_generics={:?} \
- impl_generics={:?}",
- trait_generics, impl_generics
- );
-
- // Must have same number of early-bound lifetime parameters.
- // Unfortunately, if the user screws up the bounds, then this
- // will change classification between early and late. E.g.,
- // if in trait we have `<'a,'b:'a>`, and in impl we just have
- // `<'a,'b>`, then we have 2 early-bound lifetime parameters
- // in trait but 0 in the impl. But if we report "expected 2
- // but found 0" it's confusing, because it looks like there
- // are zero. Since I don't quite know how to phrase things at
- // the moment, give a kind of vague error message.
- if trait_params != impl_params {
- let span = tcx
- .hir()
- .get_generics(impl_m.def_id.expect_local())
- .expect("expected impl item to have generics or else we can't compare them")
- .span;
-
- let mut generics_span = None;
- let mut bounds_span = vec![];
- let mut where_span = None;
- if let Some(trait_node) = tcx.hir().get_if_local(trait_m.def_id)
- && let Some(trait_generics) = trait_node.generics()
- {
- generics_span = Some(trait_generics.span);
- // FIXME: we could potentially look at the impl's bounds to not point at bounds that
- // *are* present in the impl.
- for p in trait_generics.predicates {
- if let hir::WherePredicate::BoundPredicate(pred) = p {
- for b in pred.bounds {
- if let hir::GenericBound::Outlives(lt) = b {
- bounds_span.push(lt.ident.span);
- }
- }
- }
- }
- if let Some(impl_node) = tcx.hir().get_if_local(impl_m.def_id)
- && let Some(impl_generics) = impl_node.generics()
- {
- let mut impl_bounds = 0;
- for p in impl_generics.predicates {
- if let hir::WherePredicate::BoundPredicate(pred) = p {
- for b in pred.bounds {
- if let hir::GenericBound::Outlives(_) = b {
- impl_bounds += 1;
- }
- }
- }
- }
- if impl_bounds == bounds_span.len() {
- bounds_span = vec![];
- } else if impl_generics.has_where_clause_predicates {
- where_span = Some(impl_generics.where_clause_span);
- }
- }
- }
- let reported = tcx
- .sess
- .create_err(LifetimesOrBoundsMismatchOnTrait {
- span,
- item_kind: assoc_item_kind_str(impl_m),
- ident: impl_m.ident(tcx),
- generics_span,
- bounds_span,
- where_span,
- })
- .emit_unless(delay);
- return Err(reported);
- }
-
- Ok(())
-}
-
-#[instrument(level = "debug", skip(infcx))]
-fn extract_spans_for_error_reporting<'tcx>(
- infcx: &infer::InferCtxt<'tcx>,
- terr: TypeError<'_>,
- cause: &ObligationCause<'tcx>,
- impl_m: &ty::AssocItem,
- trait_m: &ty::AssocItem,
-) -> (Span, Option<Span>) {
- let tcx = infcx.tcx;
- let mut impl_args = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref sig, _) => {
- sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
- }
- _ => bug!("{:?} is not a method", impl_m),
- };
- let trait_args =
- trait_m.def_id.as_local().map(|def_id| match tcx.hir().expect_trait_item(def_id).kind {
- TraitItemKind::Fn(ref sig, _) => {
- sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
- }
- _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
- });
-
- match terr {
- TypeError::ArgumentMutability(i) => {
- (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
- }
- TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
- (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
- }
- _ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)),
- }
-}
-
-fn compare_self_type<'tcx>(
- tcx: TyCtxt<'tcx>,
- impl_m: &ty::AssocItem,
- impl_m_span: Span,
- trait_m: &ty::AssocItem,
- impl_trait_ref: ty::TraitRef<'tcx>,
-) -> Result<(), ErrorGuaranteed> {
- // Try to give more informative error messages about self typing
- // mismatches. Note that any mismatch will also be detected
- // below, where we construct a canonical function type that
- // includes the self parameter as a normal parameter. It's just
- // that the error messages you get out of this code are a bit more
- // inscrutable, particularly for cases where one method has no
- // self.
-
- let self_string = |method: &ty::AssocItem| {
- let untransformed_self_ty = match method.container {
- ty::ImplContainer => impl_trait_ref.self_ty(),
- ty::TraitContainer => tcx.types.self_param,
- };
- let self_arg_ty = tcx.fn_sig(method.def_id).input(0);
- let param_env = ty::ParamEnv::reveal_all();
-
- let infcx = tcx.infer_ctxt().build();
- let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
- let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
- match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
- ExplicitSelf::ByValue => "self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
- _ => format!("self: {self_arg_ty}"),
- }
- };
-
- match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) {
- (false, false) | (true, true) => {}
-
- (false, true) => {
- let self_descr = self_string(impl_m);
- let mut err = struct_span_err!(
- tcx.sess,
- impl_m_span,
- E0185,
- "method `{}` has a `{}` declaration in the impl, but not in the trait",
- trait_m.name,
- self_descr
- );
- err.span_label(impl_m_span, format!("`{self_descr}` used in impl"));
- if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
- err.span_label(span, format!("trait method declared without `{self_descr}`"));
- } else {
- err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
- }
- let reported = err.emit();
- return Err(reported);
- }
-
- (true, false) => {
- let self_descr = self_string(trait_m);
- let mut err = struct_span_err!(
- tcx.sess,
- impl_m_span,
- E0186,
- "method `{}` has a `{}` declaration in the trait, but not in the impl",
- trait_m.name,
- self_descr
- );
- err.span_label(impl_m_span, format!("expected `{self_descr}` in impl"));
- if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
- err.span_label(span, format!("`{self_descr}` used in trait"));
- } else {
- err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
- }
- let reported = err.emit();
- return Err(reported);
- }
- }
-
- Ok(())
-}
-
-/// Checks that the number of generics on a given assoc item in a trait impl is the same
-/// as the number of generics on the respective assoc item in the trait definition.
-///
-/// For example this code emits the errors in the following code:
-/// ```
-/// trait Trait {
-/// fn foo();
-/// type Assoc<T>;
-/// }
-///
-/// impl Trait for () {
-/// fn foo<T>() {}
-/// //~^ error
-/// type Assoc = u32;
-/// //~^ error
-/// }
-/// ```
-///
-/// Notably this does not error on `foo<T>` implemented as `foo<const N: u8>` or
-/// `foo<const N: u8>` implemented as `foo<const N: u32>`. This is handled in
-/// [`compare_generic_param_kinds`]. This function also does not handle lifetime parameters
-fn compare_number_of_generics<'tcx>(
- tcx: TyCtxt<'tcx>,
- impl_: &ty::AssocItem,
- trait_: &ty::AssocItem,
- trait_span: Option<Span>,
- delay: bool,
-) -> Result<(), ErrorGuaranteed> {
- let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
- let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();
-
- // This avoids us erroring on `foo<T>` implemented as `foo<const N: u8>` as this is implemented
- // in `compare_generic_param_kinds` which will give a nicer error message than something like:
- // "expected 1 type parameter, found 0 type parameters"
- if (trait_own_counts.types + trait_own_counts.consts)
- == (impl_own_counts.types + impl_own_counts.consts)
- {
- return Ok(());
- }
-
- let matchings = [
- ("type", trait_own_counts.types, impl_own_counts.types),
- ("const", trait_own_counts.consts, impl_own_counts.consts),
- ];
-
- let item_kind = assoc_item_kind_str(impl_);
-
- let mut err_occurred = None;
- for (kind, trait_count, impl_count) in matchings {
- if impl_count != trait_count {
- let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| {
- let mut spans = generics
- .params
- .iter()
- .filter(|p| match p.kind {
- hir::GenericParamKind::Lifetime {
- kind: hir::LifetimeParamKind::Elided,
- } => {
- // A fn can have an arbitrary number of extra elided lifetimes for the
- // same signature.
- !matches!(kind, ty::AssocKind::Fn)
- }
- _ => true,
- })
- .map(|p| p.span)
- .collect::<Vec<Span>>();
- if spans.is_empty() {
- spans = vec![generics.span]
- }
- spans
- };
- let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
- let trait_item = tcx.hir().expect_trait_item(def_id);
- let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics);
- let impl_trait_spans: Vec<Span> = trait_item
- .generics
- .params
- .iter()
- .filter_map(|p| match p.kind {
- GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
- _ => None,
- })
- .collect();
- (Some(arg_spans), impl_trait_spans)
- } else {
- (trait_span.map(|s| vec![s]), vec![])
- };
-
- let impl_item = tcx.hir().expect_impl_item(impl_.def_id.expect_local());
- let impl_item_impl_trait_spans: Vec<Span> = impl_item
- .generics
- .params
- .iter()
- .filter_map(|p| match p.kind {
- GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
- _ => None,
- })
- .collect();
- let spans = arg_spans(impl_.kind, impl_item.generics);
- let span = spans.first().copied();
-
- let mut err = tcx.sess.struct_span_err_with_code(
- spans,
- &format!(
- "{} `{}` has {} {kind} parameter{} but its trait \
- declaration has {} {kind} parameter{}",
- item_kind,
- trait_.name,
- impl_count,
- pluralize!(impl_count),
- trait_count,
- pluralize!(trait_count),
- kind = kind,
- ),
- DiagnosticId::Error("E0049".into()),
- );
-
- let mut suffix = None;
-
- if let Some(spans) = trait_spans {
- let mut spans = spans.iter();
- if let Some(span) = spans.next() {
- err.span_label(
- *span,
- format!(
- "expected {} {} parameter{}",
- trait_count,
- kind,
- pluralize!(trait_count),
- ),
- );
- }
- for span in spans {
- err.span_label(*span, "");
- }
- } else {
- suffix = Some(format!(", expected {trait_count}"));
- }
-
- if let Some(span) = span {
- err.span_label(
- span,
- format!(
- "found {} {} parameter{}{}",
- impl_count,
- kind,
- pluralize!(impl_count),
- suffix.unwrap_or_else(String::new),
- ),
- );
- }
-
- for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) {
- err.span_label(*span, "`impl Trait` introduces an implicit type parameter");
- }
-
- let reported = err.emit_unless(delay);
- err_occurred = Some(reported);
- }
- }
-
- if let Some(reported) = err_occurred { Err(reported) } else { Ok(()) }
-}
-
-fn compare_number_of_method_arguments<'tcx>(
- tcx: TyCtxt<'tcx>,
- impl_m: &ty::AssocItem,
- impl_m_span: Span,
- trait_m: &ty::AssocItem,
- trait_item_span: Option<Span>,
-) -> Result<(), ErrorGuaranteed> {
- let impl_m_fty = tcx.fn_sig(impl_m.def_id);
- let trait_m_fty = tcx.fn_sig(trait_m.def_id);
- let trait_number_args = trait_m_fty.inputs().skip_binder().len();
- let impl_number_args = impl_m_fty.inputs().skip_binder().len();
- if trait_number_args != impl_number_args {
- let trait_span = if let Some(def_id) = trait_m.def_id.as_local() {
- match tcx.hir().expect_trait_item(def_id).kind {
- TraitItemKind::Fn(ref trait_m_sig, _) => {
- let pos = if trait_number_args > 0 { trait_number_args - 1 } else { 0 };
- if let Some(arg) = trait_m_sig.decl.inputs.get(pos) {
- Some(if pos == 0 {
- arg.span
- } else {
- arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())
- })
- } else {
- trait_item_span
- }
- }
- _ => bug!("{:?} is not a method", impl_m),
- }
- } else {
- trait_item_span
- };
- let impl_span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref impl_m_sig, _) => {
- let pos = if impl_number_args > 0 { impl_number_args - 1 } else { 0 };
- if let Some(arg) = impl_m_sig.decl.inputs.get(pos) {
- if pos == 0 {
- arg.span
- } else {
- arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
- }
- } else {
- impl_m_span
- }
- }
- _ => bug!("{:?} is not a method", impl_m),
- };
- let mut err = struct_span_err!(
- tcx.sess,
- impl_span,
- E0050,
- "method `{}` has {} but the declaration in trait `{}` has {}",
- trait_m.name,
- potentially_plural_count(impl_number_args, "parameter"),
- tcx.def_path_str(trait_m.def_id),
- trait_number_args
- );
- if let Some(trait_span) = trait_span {
- err.span_label(
- trait_span,
- format!(
- "trait requires {}",
- potentially_plural_count(trait_number_args, "parameter")
- ),
- );
- } else {
- err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
- }
- err.span_label(
- impl_span,
- format!(
- "expected {}, found {}",
- potentially_plural_count(trait_number_args, "parameter"),
- impl_number_args
- ),
- );
- let reported = err.emit();
- return Err(reported);
- }
-
- Ok(())
-}
-
-fn compare_synthetic_generics<'tcx>(
- tcx: TyCtxt<'tcx>,
- impl_m: &ty::AssocItem,
- trait_m: &ty::AssocItem,
-) -> Result<(), ErrorGuaranteed> {
- // FIXME(chrisvittal) Clean up this function, list of FIXME items:
- // 1. Better messages for the span labels
- // 2. Explanation as to what is going on
- // If we get here, we already have the same number of generics, so the zip will
- // be okay.
- let mut error_found = None;
- let impl_m_generics = tcx.generics_of(impl_m.def_id);
- let trait_m_generics = tcx.generics_of(trait_m.def_id);
- let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind {
- GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
- GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,
- });
- let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| match param.kind {
- GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
- GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,
- });
- for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) in
- iter::zip(impl_m_type_params, trait_m_type_params)
- {
- if impl_synthetic != trait_synthetic {
- let impl_def_id = impl_def_id.expect_local();
- let impl_span = tcx.def_span(impl_def_id);
- let trait_span = tcx.def_span(trait_def_id);
- let mut err = struct_span_err!(
- tcx.sess,
- impl_span,
- E0643,
- "method `{}` has incompatible signature for trait",
- trait_m.name
- );
- err.span_label(trait_span, "declaration in trait here");
- match (impl_synthetic, trait_synthetic) {
- // The case where the impl method uses `impl Trait` but the trait method uses
- // explicit generics
- (true, false) => {
- err.span_label(impl_span, "expected generic parameter, found `impl Trait`");
- (|| {
- // try taking the name from the trait impl
- // FIXME: this is obviously suboptimal since the name can already be used
- // as another generic argument
- let new_name = tcx.opt_item_name(trait_def_id)?;
- let trait_m = trait_m.def_id.as_local()?;
- let trait_m = tcx.hir().expect_trait_item(trait_m);
-
- let impl_m = impl_m.def_id.as_local()?;
- let impl_m = tcx.hir().expect_impl_item(impl_m);
-
- // in case there are no generics, take the spot between the function name
- // and the opening paren of the argument list
- let new_generics_span = tcx.def_ident_span(impl_def_id)?.shrink_to_hi();
- // in case there are generics, just replace them
- let generics_span =
- impl_m.generics.span.substitute_dummy(new_generics_span);
- // replace with the generics from the trait
- let new_generics =
- tcx.sess.source_map().span_to_snippet(trait_m.generics.span).ok()?;
-
- err.multipart_suggestion(
- "try changing the `impl Trait` argument to a generic parameter",
- vec![
- // replace `impl Trait` with `T`
- (impl_span, new_name.to_string()),
- // replace impl method generics with trait method generics
- // This isn't quite right, as users might have changed the names
- // of the generics, but it works for the common case
- (generics_span, new_generics),
- ],
- Applicability::MaybeIncorrect,
- );
- Some(())
- })();
- }
- // The case where the trait method uses `impl Trait`, but the impl method uses
- // explicit generics.
- (false, true) => {
- err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
- (|| {
- let impl_m = impl_m.def_id.as_local()?;
- let impl_m = tcx.hir().expect_impl_item(impl_m);
- let input_tys = match impl_m.kind {
- hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
- _ => unreachable!(),
- };
- struct Visitor(Option<Span>, hir::def_id::LocalDefId);
- impl<'v> intravisit::Visitor<'v> for Visitor {
- fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
- intravisit::walk_ty(self, ty);
- if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) =
- ty.kind
- && let Res::Def(DefKind::TyParam, def_id) = path.res
- && def_id == self.1.to_def_id()
- {
- self.0 = Some(ty.span);
- }
- }
- }
- let mut visitor = Visitor(None, impl_def_id);
- for ty in input_tys {
- intravisit::Visitor::visit_ty(&mut visitor, ty);
- }
- let span = visitor.0?;
-
- let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds;
- let bounds = bounds.first()?.span().to(bounds.last()?.span());
- let bounds = tcx.sess.source_map().span_to_snippet(bounds).ok()?;
-
- err.multipart_suggestion(
- "try removing the generic parameter and using `impl Trait` instead",
- vec![
- // delete generic parameters
- (impl_m.generics.span, String::new()),
- // replace param usage with `impl Trait`
- (span, format!("impl {bounds}")),
- ],
- Applicability::MaybeIncorrect,
- );
- Some(())
- })();
- }
- _ => unreachable!(),
- }
- let reported = err.emit();
- error_found = Some(reported);
- }
- }
- if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
-}
-
-/// Checks that all parameters in the generics of a given assoc item in a trait impl have
-/// the same kind as the respective generic parameter in the trait def.
-///
-/// For example all 4 errors in the following code are emitted here:
-/// ```
-/// trait Foo {
-/// fn foo<const N: u8>();
-/// type bar<const N: u8>;
-/// fn baz<const N: u32>();
-/// type blah<T>;
-/// }
-///
-/// impl Foo for () {
-/// fn foo<const N: u64>() {}
-/// //~^ error
-/// type bar<const N: u64> {}
-/// //~^ error
-/// fn baz<T>() {}
-/// //~^ error
-/// type blah<const N: i64> = u32;
-/// //~^ error
-/// }
-/// ```
-///
-/// This function does not handle lifetime parameters
-fn compare_generic_param_kinds<'tcx>(
- tcx: TyCtxt<'tcx>,
- impl_item: &ty::AssocItem,
- trait_item: &ty::AssocItem,
- delay: bool,
-) -> Result<(), ErrorGuaranteed> {
- assert_eq!(impl_item.kind, trait_item.kind);
-
- let ty_const_params_of = |def_id| {
- tcx.generics_of(def_id).params.iter().filter(|param| {
- matches!(
- param.kind,
- GenericParamDefKind::Const { .. } | GenericParamDefKind::Type { .. }
- )
- })
- };
-
- for (param_impl, param_trait) in
- iter::zip(ty_const_params_of(impl_item.def_id), ty_const_params_of(trait_item.def_id))
- {
- use GenericParamDefKind::*;
- if match (¶m_impl.kind, ¶m_trait.kind) {
- (Const { .. }, Const { .. })
- if tcx.type_of(param_impl.def_id) != tcx.type_of(param_trait.def_id) =>
- {
- true
- }
- (Const { .. }, Type { .. }) | (Type { .. }, Const { .. }) => true,
- // this is exhaustive so that anyone adding new generic param kinds knows
- // to make sure this error is reported for them.
- (Const { .. }, Const { .. }) | (Type { .. }, Type { .. }) => false,
- (Lifetime { .. }, _) | (_, Lifetime { .. }) => unreachable!(),
- } {
- let param_impl_span = tcx.def_span(param_impl.def_id);
- let param_trait_span = tcx.def_span(param_trait.def_id);
-
- let mut err = struct_span_err!(
- tcx.sess,
- param_impl_span,
- E0053,
- "{} `{}` has an incompatible generic parameter for trait `{}`",
- assoc_item_kind_str(&impl_item),
- trait_item.name,
- &tcx.def_path_str(tcx.parent(trait_item.def_id))
- );
-
- let make_param_message = |prefix: &str, param: &ty::GenericParamDef| match param.kind {
- Const { .. } => {
- format!("{} const parameter of type `{}`", prefix, tcx.type_of(param.def_id))
- }
- Type { .. } => format!("{} type parameter", prefix),
- Lifetime { .. } => unreachable!(),
- };
-
- let trait_header_span = tcx.def_ident_span(tcx.parent(trait_item.def_id)).unwrap();
- err.span_label(trait_header_span, "");
- err.span_label(param_trait_span, make_param_message("expected", param_trait));
-
- let impl_header_span = tcx.def_span(tcx.parent(impl_item.def_id));
- err.span_label(impl_header_span, "");
- err.span_label(param_impl_span, make_param_message("found", param_impl));
-
- let reported = err.emit_unless(delay);
- return Err(reported);
- }
- }
-
- Ok(())
-}
-
-/// Use `tcx.compare_assoc_const_impl_item_with_trait_item` instead
-pub(crate) fn raw_compare_const_impl(
- tcx: TyCtxt<'_>,
- (impl_const_item_def, trait_const_item_def): (LocalDefId, DefId),
-) -> Result<(), ErrorGuaranteed> {
- let impl_const_item = tcx.associated_item(impl_const_item_def);
- let trait_const_item = tcx.associated_item(trait_const_item_def);
- let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap();
- debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
-
- let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
-
- let infcx = tcx.infer_ctxt().build();
- let param_env = tcx.param_env(impl_const_item_def.to_def_id());
- let ocx = ObligationCtxt::new(&infcx);
-
- // The below is for the most part highly similar to the procedure
- // for methods above. It is simpler in many respects, especially
- // because we shouldn't really have to deal with lifetimes or
- // predicates. In fact some of this should probably be put into
- // shared functions because of DRY violations...
- let trait_to_impl_substs = impl_trait_ref.substs;
-
- // Create a parameter environment that represents the implementation's
- // method.
- let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_const_item_def);
-
- // Compute placeholder form of impl and trait const tys.
- let impl_ty = tcx.type_of(impl_const_item_def.to_def_id());
- let trait_ty = tcx.bound_type_of(trait_const_item_def).subst(tcx, trait_to_impl_substs);
- let mut cause = ObligationCause::new(
- impl_c_span,
- impl_c_hir_id,
- ObligationCauseCode::CompareImplItemObligation {
- impl_item_def_id: impl_const_item_def,
- trait_item_def_id: trait_const_item_def,
- kind: impl_const_item.kind,
- },
- );
-
- // There is no "body" here, so just pass dummy id.
- let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
-
- debug!("compare_const_impl: impl_ty={:?}", impl_ty);
-
- let trait_ty = ocx.normalize(&cause, param_env, trait_ty);
-
- debug!("compare_const_impl: trait_ty={:?}", trait_ty);
-
- let err = ocx.sup(&cause, param_env, trait_ty, impl_ty);
-
- if let Err(terr) = err {
- debug!(
- "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
- impl_ty, trait_ty
- );
-
- // Locate the Span containing just the type of the offending impl
- match tcx.hir().expect_impl_item(impl_const_item_def).kind {
- ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
- _ => bug!("{:?} is not a impl const", impl_const_item),
- }
-
- let mut diag = struct_span_err!(
- tcx.sess,
- cause.span,
- E0326,
- "implemented const `{}` has an incompatible type for trait",
- trait_const_item.name
- );
-
- let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| {
- // Add a label to the Span containing just the type of the const
- match tcx.hir().expect_trait_item(trait_c_def_id).kind {
- TraitItemKind::Const(ref ty, _) => ty.span,
- _ => bug!("{:?} is not a trait const", trait_const_item),
- }
- });
-
- infcx.err_ctxt().note_type_err(
- &mut diag,
- &cause,
- trait_c_span.map(|span| (span, "type in trait".to_owned())),
- Some(infer::ValuePairs::Terms(ExpectedFound {
- expected: trait_ty.into(),
- found: impl_ty.into(),
- })),
- terr,
- false,
- false,
- );
- return Err(diag.emit());
- };
-
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None));
- }
-
- // FIXME return `ErrorReported` if region obligations error?
- let outlives_environment = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment);
- Ok(())
-}
-
-pub(crate) fn compare_ty_impl<'tcx>(
- tcx: TyCtxt<'tcx>,
- impl_ty: &ty::AssocItem,
- impl_ty_span: Span,
- trait_ty: &ty::AssocItem,
- impl_trait_ref: ty::TraitRef<'tcx>,
- trait_item_span: Option<Span>,
-) {
- debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref);
-
- let _: Result<(), ErrorGuaranteed> = (|| {
- compare_number_of_generics(tcx, impl_ty, trait_ty, trait_item_span, false)?;
-
- compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
-
- let sp = tcx.def_span(impl_ty.def_id);
- compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
-
- check_type_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<'tcx>(
- tcx: TyCtxt<'tcx>,
- impl_ty: &ty::AssocItem,
- impl_ty_span: Span,
- trait_ty: &ty::AssocItem,
- impl_trait_ref: ty::TraitRef<'tcx>,
-) -> Result<(), ErrorGuaranteed> {
- let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
- let trait_to_impl_substs =
- impl_substs.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.substs);
-
- let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id);
- let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
-
- check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
-
- let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs);
-
- if impl_ty_own_bounds.is_empty() {
- // Nothing to check.
- return Ok(());
- }
-
- // This `HirId` should be used for the `body_id` field on each
- // `ObligationCause` (and the `FnCtxt`). This is what
- // `regionck_item` expects.
- let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
- debug!("compare_type_predicate_entailment: trait_to_impl_substs={:?}", trait_to_impl_substs);
-
- // The predicates declared by the impl definition, the trait and the
- // associated type in the trait are assumed.
- let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap());
- let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
- hybrid_preds
- .predicates
- .extend(trait_ty_predicates.instantiate_own(tcx, trait_to_impl_substs).predicates);
-
- debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
-
- let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
- let param_env = ty::ParamEnv::new(
- tcx.intern_predicates(&hybrid_preds.predicates),
- Reveal::UserFacing,
- hir::Constness::NotConst,
- );
- let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
- let infcx = tcx.infer_ctxt().build();
- let ocx = ObligationCtxt::new(&infcx);
-
- debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
-
- assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
- for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
- {
- let cause = ObligationCause::misc(span, impl_ty_hir_id);
- let predicate = ocx.normalize(&cause, param_env, predicate);
-
- let cause = ObligationCause::new(
- span,
- impl_ty_hir_id,
- ObligationCauseCode::CompareImplItemObligation {
- impl_item_def_id: impl_ty.def_id.expect_local(),
- trait_item_def_id: trait_ty.def_id,
- kind: impl_ty.kind,
- },
- );
- ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
- }
-
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
- return Err(reported);
- }
-
- // Finally, resolve all regions. This catches wily misuses of
- // lifetime parameters.
- let outlives_environment = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(
- impl_ty.def_id.expect_local(),
- &outlives_environment,
- );
-
- Ok(())
-}
-
-/// 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.
-#[instrument(level = "debug", skip(tcx))]
-pub fn check_type_bounds<'tcx>(
- tcx: TyCtxt<'tcx>,
- trait_ty: &ty::AssocItem,
- impl_ty: &ty::AssocItem,
- impl_ty_span: Span,
- impl_trait_ref: ty::TraitRef<'tcx>,
-) -> Result<(), ErrorGuaranteed> {
- // Given
- //
- // impl<A, B> Foo<u32> for (A, B) {
- // type Bar<C> =...
- // }
- //
- // - `impl_trait_ref` would be `<(A, B) as Foo<u32>>
- // - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
- // - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from
- // the *trait* with the generic associated type parameters (as bound vars).
- //
- // A note regarding the use of bound vars here:
- // Imagine as an example
- // ```
- // trait Family {
- // type Member<C: Eq>;
- // }
- //
- // impl Family for VecFamily {
- // type Member<C: Eq> = i32;
- // }
- // ```
- // Here, we would generate
- // ```notrust
- // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
- // ```
- // when we really would like to generate
- // ```notrust
- // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
- // ```
- // But, this is probably fine, because although the first clause can be used with types C that
- // do not implement Eq, for it to cause some kind of problem, there would have to be a
- // VecFamily::Member<X> for some type X where !(X: Eq), that appears in the value of type
- // Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing
- // elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in
- // the trait (notably, that X: Eq and T: Family).
- let defs: &ty::Generics = tcx.generics_of(impl_ty.def_id);
- let mut substs = smallvec::SmallVec::with_capacity(defs.count());
- if let Some(def_id) = defs.parent {
- let parent_defs = tcx.generics_of(def_id);
- InternalSubsts::fill_item(&mut substs, tcx, parent_defs, &mut |param, _| {
- tcx.mk_param_from_def(param)
- });
- }
- let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
- smallvec::SmallVec::with_capacity(defs.count());
- InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param.kind {
- GenericParamDefKind::Type { .. } => {
- let kind = ty::BoundTyKind::Param(param.name);
- let bound_var = ty::BoundVariableKind::Ty(kind);
- bound_vars.push(bound_var);
- tcx.mk_ty(ty::Bound(
- ty::INNERMOST,
- ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
- ))
- .into()
- }
- GenericParamDefKind::Lifetime => {
- let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
- let bound_var = ty::BoundVariableKind::Region(kind);
- bound_vars.push(bound_var);
- tcx.mk_region(ty::ReLateBound(
- ty::INNERMOST,
- ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
- ))
- .into()
- }
- GenericParamDefKind::Const { .. } => {
- let bound_var = ty::BoundVariableKind::Const;
- bound_vars.push(bound_var);
- tcx.mk_const(
- ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1)),
- tcx.type_of(param.def_id),
- )
- .into()
- }
- });
- let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
- let impl_ty_substs = tcx.intern_substs(&substs);
- let container_id = impl_ty.container_id(tcx);
-
- let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
- let impl_ty_value = tcx.type_of(impl_ty.def_id);
-
- let param_env = tcx.param_env(impl_ty.def_id);
-
- // When checking something like
- //
- // trait X { type Y: PartialEq<<Self as X>::Y> }
- // impl X for T { default type Y = S; }
- //
- // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
- // we want <T as X>::Y to normalize to S. This is valid because we are
- // checking the default value specifically here. Add this equality to the
- // ParamEnv for normalization specifically.
- let normalize_param_env = {
- let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
- match impl_ty_value.kind() {
- ty::Alias(ty::Projection, proj)
- if proj.def_id == trait_ty.def_id && proj.substs == rebased_substs =>
- {
- // Don't include this predicate if the projected type is
- // exactly the same as the projection. This can occur in
- // (somewhat dubious) code like this:
- //
- // impl<T> X for T where T: X { type Y = <T as X>::Y; }
- }
- _ => predicates.push(
- ty::Binder::bind_with_vars(
- ty::ProjectionPredicate {
- projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_substs),
- term: impl_ty_value.into(),
- },
- bound_vars,
- )
- .to_predicate(tcx),
- ),
- };
- ty::ParamEnv::new(
- tcx.intern_predicates(&predicates),
- Reveal::UserFacing,
- param_env.constness(),
- )
- };
- debug!(?normalize_param_env);
-
- let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
- let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
- let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
-
- let infcx = tcx.infer_ctxt().build();
- let ocx = ObligationCtxt::new(&infcx);
-
- let assumed_wf_types =
- ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local());
-
- let normalize_cause = ObligationCause::new(
- impl_ty_span,
- impl_ty_hir_id,
- ObligationCauseCode::CheckAssociatedTypeBounds {
- impl_item_def_id: impl_ty.def_id.expect_local(),
- trait_item_def_id: trait_ty.def_id,
- },
- );
- let mk_cause = |span: Span| {
- let code = if span.is_dummy() {
- traits::ItemObligation(trait_ty.def_id)
- } else {
- traits::BindingObligation(trait_ty.def_id, span)
- };
- ObligationCause::new(impl_ty_span, impl_ty_hir_id, code)
- };
-
- let obligations = tcx
- .bound_explicit_item_bounds(trait_ty.def_id)
- .subst_iter_copied(tcx, rebased_substs)
- .map(|(concrete_ty_bound, span)| {
- debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
- traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
- })
- .collect();
- debug!("check_type_bounds: item_bounds={:?}", obligations);
-
- for mut obligation in util::elaborate_obligations(tcx, obligations) {
- let normalized_predicate =
- ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate);
- debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
- obligation.predicate = normalized_predicate;
-
- ocx.register_obligation(obligation);
- }
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
- return Err(reported);
- }
-
- // Finally, resolve all regions. This catches wily misuses of
- // lifetime parameters.
- let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types);
- let outlives_environment =
- OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
-
- infcx.check_region_obligations_and_report_errors(
- impl_ty.def_id.expect_local(),
- &outlives_environment,
- );
-
- let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
- for (key, value) in constraints {
- infcx
- .err_ctxt()
- .report_mismatched_types(
- &ObligationCause::misc(
- value.hidden_type.span,
- tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()),
- ),
- tcx.mk_opaque(key.def_id.to_def_id(), key.substs),
- value.hidden_type.ty,
- TypeError::Mismatch,
- )
- .emit();
- }
-
- Ok(())
-}
-
-fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
- match impl_item.kind {
- ty::AssocKind::Const => "const",
- ty::AssocKind::Fn => "method",
- ty::AssocKind::Type => "type",
- }
-}
*/
mod check;
-mod compare_method;
+mod compare_impl_item;
pub mod dropck;
pub mod intrinsic;
pub mod intrinsicck;
use crate::require_c_abi_if_c_variadic;
use crate::util::common::indenter;
-use self::compare_method::collect_trait_impl_trait_tys;
+use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys;
use self::region::region_scope_tree;
pub fn provide(providers: &mut Providers) {
adt_destructor,
check_mod_item_types,
region_scope_tree,
- collect_trait_impl_trait_tys,
- compare_assoc_const_impl_item_with_trait_item: compare_method::raw_compare_const_impl,
+ collect_return_position_impl_trait_in_trait_tys,
+ compare_impl_const: compare_impl_item::compare_impl_const_raw,
..*providers
};
}
let infcx = &tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(infcx);
- let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id);
-
let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env };
if !tcx.features().trivial_bounds {
wfcx.check_false_global_bounds()
}
f(&mut wfcx);
+
+ let assumed_wf_types = wfcx.ocx.assumed_wf_types(param_env, span, body_def_id);
+ let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
+
let errors = wfcx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return;
}
- let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
let outlives_environment =
OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
- infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
+ let _ = infcx
+ .err_ctxt()
+ .check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
}
fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
// Do some rudimentary sanity checking to avoid an ICE later (issue #83471).
if let Some(hir::FnSig { decl, span, .. }) = method_sig {
if let [self_ty, _] = decl.inputs {
- if !matches!(self_ty.kind, hir::TyKind::Rptr(_, _)) {
+ if !matches!(self_ty.kind, hir::TyKind::Ref(_, _)) {
tcx.sess
.struct_span_err(
self_ty.span,
def_id: LocalDefId,
) {
let tcx = wfcx.tcx();
- let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
+ let mut sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
// Normalize the input and output types one at a time, using a different
// `WellFormedLoc` for each. We cannot call `normalize_associated_types`
// on the entire `FnSig`, since this would use the same `WellFormedLoc`
// for each type, preventing the HIR wf check from generating
// a nice error message.
- let ty::FnSig { mut inputs_and_output, c_variadic, unsafety, abi } = sig;
- inputs_and_output = tcx.mk_type_list(inputs_and_output.iter().enumerate().map(|(i, ty)| {
- wfcx.normalize(
- span,
- Some(WellFormedLoc::Param {
- function: def_id,
- // Note that the `param_idx` of the output type is
- // one greater than the index of the last input type.
- param_idx: i.try_into().unwrap(),
- }),
- ty,
- )
- }));
- // Manually call `normalize_associated_types_in` on the other types
- // in `FnSig`. This ensures that if the types of these fields
- // ever change to include projections, we will start normalizing
- // them automatically.
- let sig = ty::FnSig {
- inputs_and_output,
- c_variadic: wfcx.normalize(span, None, c_variadic),
- unsafety: wfcx.normalize(span, None, unsafety),
- abi: wfcx.normalize(span, None, abi),
- };
+ let arg_span =
+ |idx| hir_decl.inputs.get(idx).map_or(hir_decl.output.span(), |arg: &hir::Ty<'_>| arg.span);
+
+ sig.inputs_and_output =
+ tcx.mk_type_list(sig.inputs_and_output.iter().enumerate().map(|(idx, ty)| {
+ wfcx.normalize(
+ arg_span(idx),
+ Some(WellFormedLoc::Param {
+ function: def_id,
+ // Note that the `param_idx` of the output type is
+ // one greater than the index of the last input type.
+ param_idx: idx.try_into().unwrap(),
+ }),
+ ty,
+ )
+ }));
- for (i, (&input_ty, ty)) in iter::zip(sig.inputs(), hir_decl.inputs).enumerate() {
+ for (idx, ty) in sig.inputs_and_output.iter().enumerate() {
wfcx.register_wf_obligation(
- ty.span,
- Some(WellFormedLoc::Param { function: def_id, param_idx: i.try_into().unwrap() }),
- input_ty.into(),
+ arg_span(idx),
+ Some(WellFormedLoc::Param { function: def_id, param_idx: idx.try_into().unwrap() }),
+ ty.into(),
);
}
- wfcx.register_wf_obligation(
- hir_decl.output.span(),
- Some(WellFormedLoc::Param {
- function: def_id,
- param_idx: sig.inputs().len().try_into().unwrap(),
- }),
- sig.output().into(),
- );
-
check_where_clauses(wfcx, span, def_id);
check_return_position_impl_trait_in_trait_bounds(
}
let pred = obligation.predicate;
// Match the existing behavior.
- if pred.is_global() && !pred.has_late_bound_regions() {
+ if pred.is_global() && !pred.has_late_bound_vars() {
let pred = self.normalize(span, None, pred);
let hir_node = tcx.hir().find(self.body_id);
// Finally, resolve all regions.
let outlives_env = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
+ let _ = infcx
+ .err_ctxt()
+ .check_region_obligations_and_report_errors(impl_did, &outlives_env);
}
}
_ => {
// Finally, resolve all regions.
let outlives_env = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
+ let _ = infcx.err_ctxt().check_region_obligations_and_report_errors(impl_did, &outlives_env);
CoerceUnsizedInfo { custom_kind: kind }
}
sp,
item.span,
tr.path.span,
- trait_ref.self_ty(),
+ trait_ref,
impl_.self_ty.span,
&impl_.generics,
err,
sp: Span,
full_impl_span: Span,
trait_span: Span,
- self_ty: Ty<'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
self_ty_span: Span,
generics: &hir::Generics<'tcx>,
err: traits::OrphanCheckErr<'tcx>,
) -> Result<!, ErrorGuaranteed> {
+ let self_ty = trait_ref.self_ty();
Err(match err {
traits::OrphanCheckErr::NonLocalInputType(tys) => {
let msg = match self_ty.kind() {
let msg = |ty: &str, postfix: &str| {
format!("{ty} is not defined in the current crate{postfix}")
};
- let this = |name: &str| msg("this", &format!(" because {name} are always foreign"));
+
+ let this = |name: &str| {
+ if !trait_ref.def_id.is_local() && !is_target_ty {
+ msg("this", &format!(" because this is a foreign trait"))
+ } else {
+ msg("this", &format!(" because {name} are always foreign"))
+ }
+ };
let msg = match &ty.kind() {
ty::Slice(_) => this("slices"),
ty::Array(..) => this("arrays"),
(Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
struct_span_err!(
tcx.sess,
- item.span,
+ tcx.def_span(def_id),
E0199,
"implementing the trait `{}` is not unsafe",
trait_ref.print_only_trait_path()
(Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
struct_span_err!(
tcx.sess,
- item.span,
+ tcx.def_span(def_id),
E0200,
"the trait `{}` requires an `unsafe impl` declaration",
trait_ref.print_only_trait_path()
(Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
struct_span_err!(
tcx.sess,
- item.span,
+ tcx.def_span(def_id),
E0569,
"requires an `unsafe impl` declaration due to `#[{}]` attribute",
attr_name
use crate::astconv::AstConv;
use crate::check::intrinsic::intrinsic_operation_unsafety;
use crate::errors;
+use hir::def::DefKind;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericParamKind, Node};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::ObligationCause;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::util::{Discr, IntTypeExt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use rustc_target::spec::abi;
+use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
+use rustc_trait_selection::traits::ObligationCtxt;
use std::iter;
mod generics_of;
is_fn = true;
// Check if parent is const or static
- let parent_id = tcx.hir().get_parent_node(hir_ty.hir_id);
+ let parent_id = tcx.hir().parent_id(hir_ty.hir_id);
let parent_node = tcx.hir().get(parent_id);
is_const_or_static = matches!(
}
}
- fn normalize_ty(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
- // Types in item signatures are not normalized to avoid undue dependencies.
- ty
+ fn probe_adt(&self, _span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
+ // FIXME(#103640): Should we handle the case where `ty` is a projection?
+ ty.ty_adt_def()
}
fn set_tainted_by_errors(&self, _: ErrorGuaranteed) {
is_suggestable_infer_ty(ty) || matches!(length, hir::ArrayLen::Infer(_, _))
}
Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
- Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
+ Ptr(mut_ty) | Ref(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args),
Path(hir::QPath::TypeRelative(ty, segment)) => {
is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.args().args)
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
// Do not try to infer the return type for a impl method coming from a trait
if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
- tcx.hir().get(tcx.hir().get_parent_node(hir_id))
+ tcx.hir().get_parent(hir_id)
&& i.of_trait.is_some()
{
<dyn AstConv<'_>>::ty_of_fn(
ty::ReErased => tcx.lifetimes.re_static,
_ => r,
});
- let fn_sig = ty::Binder::dummy(fn_sig);
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_ty(ty);
let mut diag = bad_placeholder(tcx, visitor.0, "return type");
- let ret_ty = fn_sig.skip_binder().output();
+ let ret_ty = fn_sig.output();
if ret_ty.is_suggestable(tcx, false) {
diag.span_suggestion(
ty.span,
Applicability::MachineApplicable,
);
}
+ } else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, hir_id, def_id) {
+ diag.span_suggestion(
+ ty.span,
+ "replace with an appropriate return type",
+ sugg,
+ Applicability::MachineApplicable,
+ );
} else if ret_ty.is_closure() {
- // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds
- // to prevent the user from getting a papercut while trying to use the unique closure
- // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
- diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
+ }
+ // Also note how `Fn` traits work just in case!
+ if ret_ty.is_closure() {
+ diag.note(
+ "for more information on `Fn` traits and closure types, see \
+ https://doc.rust-lang.org/book/ch13-01-closures.html",
+ );
}
diag.emit();
- fn_sig
+ ty::Binder::dummy(fn_sig)
}
None => <dyn AstConv<'_>>::ty_of_fn(
icx,
}
}
+fn suggest_impl_trait<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ret_ty: Ty<'tcx>,
+ span: Span,
+ hir_id: hir::HirId,
+ def_id: LocalDefId,
+) -> Option<String> {
+ let format_as_assoc: fn(_, _, _, _, _) -> _ =
+ |tcx: TyCtxt<'tcx>,
+ _: ty::SubstsRef<'tcx>,
+ trait_def_id: DefId,
+ assoc_item_def_id: DefId,
+ item_ty: Ty<'tcx>| {
+ let trait_name = tcx.item_name(trait_def_id);
+ let assoc_name = tcx.item_name(assoc_item_def_id);
+ Some(format!("impl {trait_name}<{assoc_name} = {item_ty}>"))
+ };
+ let format_as_parenthesized: fn(_, _, _, _, _) -> _ =
+ |tcx: TyCtxt<'tcx>,
+ substs: ty::SubstsRef<'tcx>,
+ trait_def_id: DefId,
+ _: DefId,
+ item_ty: Ty<'tcx>| {
+ let trait_name = tcx.item_name(trait_def_id);
+ let args_tuple = substs.type_at(1);
+ let ty::Tuple(types) = *args_tuple.kind() else { return None; };
+ if !types.is_suggestable(tcx, false) {
+ return None;
+ }
+ let maybe_ret =
+ if item_ty.is_unit() { String::new() } else { format!(" -> {item_ty}") };
+ Some(format!(
+ "impl {trait_name}({}){maybe_ret}",
+ types.iter().map(|ty| ty.to_string()).collect::<Vec<_>>().join(", ")
+ ))
+ };
+
+ for (trait_def_id, assoc_item_def_id, formatter) in [
+ (
+ tcx.get_diagnostic_item(sym::Iterator),
+ tcx.get_diagnostic_item(sym::IteratorItem),
+ format_as_assoc,
+ ),
+ (
+ tcx.lang_items().future_trait(),
+ tcx.get_diagnostic_item(sym::FutureOutput),
+ format_as_assoc,
+ ),
+ (tcx.lang_items().fn_trait(), tcx.lang_items().fn_once_output(), format_as_parenthesized),
+ (
+ tcx.lang_items().fn_mut_trait(),
+ tcx.lang_items().fn_once_output(),
+ format_as_parenthesized,
+ ),
+ (
+ tcx.lang_items().fn_once_trait(),
+ tcx.lang_items().fn_once_output(),
+ format_as_parenthesized,
+ ),
+ ] {
+ let Some(trait_def_id) = trait_def_id else { continue; };
+ let Some(assoc_item_def_id) = assoc_item_def_id else { continue; };
+ if tcx.def_kind(assoc_item_def_id) != DefKind::AssocTy {
+ continue;
+ }
+ let param_env = tcx.param_env(def_id);
+ let infcx = tcx.infer_ctxt().build();
+ let substs = ty::InternalSubsts::for_item(tcx, trait_def_id, |param, _| {
+ if param.index == 0 { ret_ty.into() } else { infcx.var_for_def(span, param) }
+ });
+ if !infcx.type_implements_trait(trait_def_id, substs, param_env).must_apply_modulo_regions()
+ {
+ continue;
+ }
+ let ocx = ObligationCtxt::new_in_snapshot(&infcx);
+ let item_ty = ocx.normalize(
+ &ObligationCause::misc(span, hir_id),
+ param_env,
+ tcx.mk_projection(assoc_item_def_id, substs),
+ );
+ // FIXME(compiler-errors): We may benefit from resolving regions here.
+ if ocx.select_where_possible().is_empty()
+ && let item_ty = infcx.resolve_vars_if_possible(item_ty)
+ && item_ty.is_suggestable(tcx, false)
+ && let Some(sugg) = formatter(tcx, infcx.resolve_vars_if_possible(substs), trait_def_id, assoc_item_def_id, item_ty)
+ {
+ return Some(sugg);
+ }
+ }
+ None
+}
+
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
let icx = ItemCtxt::new(tcx, def_id);
let item = tcx.hir().expect_item(def_id.expect_local());
// `min_const_generics`.
Some(parent_def_id.to_def_id())
} else {
- let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+ let parent_node = tcx.hir().get_parent(hir_id);
match parent_node {
// HACK(eddyb) this provides the correct generics for repeat
// expressions' count (i.e. `N` in `[x; N]`), and explicit
// provide junk type parameter defs for const blocks.
if let Node::AnonConst(_) = node {
- let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+ let parent_node = tcx.hir().get_parent(hir_id);
if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
params.push(ty::GenericParamDef {
index: next_index(),
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
// Associated types are implicitly sized unless a `?Sized` bound is found
- <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
+ <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, item_ty, ast_bounds, None, span);
let trait_def_id = tcx.parent(assoc_item_def_id);
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
}
});
- let all_bounds = tcx
- .arena
- .alloc_from_iter(bounds.predicates(tcx, item_ty).into_iter().chain(bounds_from_parent));
+ let all_bounds = tcx.arena.alloc_from_iter(bounds.predicates().chain(bounds_from_parent));
debug!("associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id), all_bounds);
all_bounds
}
let icx = ItemCtxt::new(tcx, opaque_def_id);
let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
// Opaque types are implicitly sized unless a `?Sized` bound is found
- <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
+ <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, item_ty, ast_bounds, None, span);
debug!(?bounds);
- tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
+ tcx.arena.alloc_from_iter(bounds.predicates())
})
}
LifetimeName::Error => {}
}
}
- hir::TyKind::Rptr(ref lifetime_ref, ref mt) => {
+ hir::TyKind::Ref(ref lifetime_ref, ref mt) => {
self.visit_lifetime(lifetime_ref);
let scope = Scope::ObjectLifetimeDefault {
lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(),
};
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
// Ensure that the parent of the def is an item, not HRTB
- let parent_id = self.tcx.hir().get_parent_node(hir_id);
+ let parent_id = self.tcx.hir().parent_id(hir_id);
if !parent_id.is_owner() {
struct_span_err!(
self.tcx.sess,
// Fresh lifetimes in APIT used to be allowed in async fns and forbidden in
// regular fns.
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
- && let hir::LifetimeName::Param(_) = lifetime_ref.res
- && lifetime_ref.is_anonymous()
+ && let hir::LifetimeName::Param(param_id) = lifetime_ref.res
+ && let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id))
+ && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
+ && param.is_elided_lifetime()
&& let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id)
&& !self.tcx.features().anonymous_lifetime_in_impl_trait
{
<dyn AstConv<'_>>::add_implicitly_sized(
&icx,
&mut bounds,
+ param_ty,
&[],
Some((param.def_id, ast_generics.predicates)),
param.span,
);
trace!(?bounds);
- predicates.extend(bounds.predicates(tcx, param_ty));
+ predicates.extend(bounds.predicates());
trace!(?predicates);
}
GenericParamKind::Const { .. } => {
&mut bounds,
bound_vars,
);
- predicates.extend(bounds.predicates(tcx, ty));
+ predicates.extend(bounds.predicates());
}
hir::WherePredicate::RegionPredicate(region_pred) => {
// We create bi-directional Outlives predicates between the original
// and the duplicated parameter, to ensure that they do not get out of sync.
if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
- let opaque_ty_id = tcx.hir().get_parent_node(hir_id);
+ let opaque_ty_id = tcx.hir().parent_id(hir_id);
let opaque_ty_node = tcx.hir().get(opaque_ty_id);
let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else {
bug!("unexpected {opaque_ty_node:?}")
<dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, bounds)
};
- let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
+ let superbounds1 = superbounds1.predicates();
// Convert any explicit superbounds in the where-clause,
// e.g., `trait Foo where Self: Bar`.
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let mut bounds = Bounds::default();
astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
- bounds.predicates(astconv.tcx(), param_ty).collect()
+ bounds.predicates().collect()
}
use rustc_hir::intravisit::Visitor;
use rustc_hir::{HirId, Node};
use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
_ => return None,
};
- let parent_node_id = tcx.hir().get_parent_node(hir_id);
+ let parent_node_id = tcx.hir().parent_id(hir_id);
let parent_node = tcx.hir().get(parent_node_id);
let (generics, arg_idx) = match parent_node {
}
Node::AnonConst(_) => {
- let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+ let parent_node = tcx.hir().get_parent(hir_id);
match parent_node {
Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
..
},
) if let Node::TraitRef(trait_ref) =
- tcx.hir().get(tcx.hir().get_parent_node(binding_id))
+ tcx.hir().get_parent(binding_id)
&& e.hir_id == hir_id =>
{
let Some(trait_def_id) = trait_ref.trait_def_id() else {
Node::TypeBinding(
binding @ &TypeBinding { hir_id: binding_id, gen_args, ref kind, .. },
) if let Node::TraitRef(trait_ref) =
- tcx.hir().get(tcx.hir().get_parent_node(binding_id))
+ tcx.hir().get_parent(binding_id)
&& let Some((idx, _)) =
gen_args.args.iter().enumerate().find(|(_, arg)| {
if let GenericArg::Const(ct) = arg {
Applicability::MachineApplicable,
);
} else {
- err.span_note(
+ with_forced_trimmed_paths!(err.span_note(
tcx.hir().body(body_id).value.span,
- &format!("however, the inferred type `{}` cannot be named", ty),
- );
+ &format!("however, the inferred type `{ty}` cannot be named"),
+ ));
}
}
Applicability::MaybeIncorrect,
);
} else {
- diag.span_note(
+ with_forced_trimmed_paths!(diag.span_note(
tcx.hir().body(body_id).value.span,
- &format!("however, the inferred type `{}` cannot be named", ty),
- );
+ &format!("however, the inferred type `{ty}` cannot be named"),
+ ));
}
}
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt};
-use tracing::instrument;
pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
if let Some(node) = parent_specialization_node(tcx, impl_def_id) {
let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types);
let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
- infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
+ let _ =
+ infcx.err_ctxt().check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
let span = tcx.def_span(impl1_def_id);
tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
let span = self.path_segment.ident.span;
// insert a suggestion of the form "Y<'a, 'b>"
- let ident = self.path_segment.ident.name.to_ident_string();
- let sugg = format!("{}<{}>", ident, suggested_args);
+ let sugg = format!("<{}>", suggested_args);
debug!("sugg: {:?}", sugg);
- err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
+ err.span_suggestion_verbose(
+ span.shrink_to_hi(),
+ &msg,
+ sugg,
+ Applicability::HasPlaceholders,
+ );
}
AngleBrackets::Available => {
let span = self.path_segment.ident.span;
// insert a suggestion of the form "Y<T, U>"
- let ident = self.path_segment.ident.name.to_ident_string();
- let sugg = format!("{}<{}>", ident, suggested_args);
+ let sugg = format!("<{}>", suggested_args);
debug!("sugg: {:?}", sugg);
- err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
+ err.span_suggestion_verbose(
+ span.shrink_to_hi(),
+ &msg,
+ sugg,
+ Applicability::HasPlaceholders,
+ );
}
AngleBrackets::Available => {
let gen_args_span = self.gen_args.span().unwrap();
num = num_trait_generics_except_self,
);
- if let Some(parent_node) = self.tcx.hir().find_parent_node(self.path_segment.hir_id)
+ if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id)
&& let Some(parent_node) = self.tcx.hir().find(parent_node)
&& let hir::Node::Expr(expr) = parent_node {
match expr.kind {
self.word("*");
self.print_mt(mt, true);
}
- hir::TyKind::Rptr(ref lifetime, ref mt) => {
+ hir::TyKind::Ref(ref lifetime, ref mt) => {
self.word("&");
self.print_opt_lifetime(lifetime);
self.print_mt(mt, false);
hir::InlineAsmOperand::In { reg, ref expr } => {
s.word("in");
s.popen();
- s.word(format!("{}", reg));
+ s.word(format!("{reg}"));
s.pclose();
s.space();
s.print_expr(expr);
hir::InlineAsmOperand::Out { reg, late, ref expr } => {
s.word(if late { "lateout" } else { "out" });
s.popen();
- s.word(format!("{}", reg));
+ s.word(format!("{reg}"));
s.pclose();
s.space();
match expr {
hir::InlineAsmOperand::InOut { reg, late, ref expr } => {
s.word(if late { "inlateout" } else { "inout" });
s.popen();
- s.word(format!("{}", reg));
+ s.word(format!("{reg}"));
s.pclose();
s.space();
s.print_expr(expr);
hir::InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
s.word(if late { "inlateout" } else { "inout" });
s.popen();
- s.word(format!("{}", reg));
+ s.word(format!("{reg}"));
s.pclose();
s.space();
s.print_expr(in_expr);
let mut ret_span: MultiSpan = semi_span.into();
ret_span.push_span_label(
expr.span,
- "this could be implicitly returned but it is a statement, not a \
- tail expression",
+ "this could be implicitly returned but it is a statement, not a tail expression",
);
ret_span.push_span_label(ret, "the `match` arms can conform to this return type");
ret_span.push_span_label(
semi_span,
- "the `match` is a statement because of this semicolon, consider \
- removing it",
+ "the `match` is a statement because of this semicolon, consider removing it",
);
diag.span_note(ret_span, "you might have meant to return the `match` expression");
diag.tool_only_span_suggestion(
fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, sp: Span) -> Option<(Span, String)> {
let node = {
- let rslt = self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(hir_id));
+ let rslt = self.tcx.hir().parent_id(self.tcx.hir().parent_id(hir_id));
self.tcx.hir().get(rslt)
};
if let hir::Node::Block(block) = node {
// check that the body's parent is an fn
- let parent = self
- .tcx
- .hir()
- .get(self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(block.hir_id)));
+ let parent = self.tcx.hir().get_parent(self.tcx.hir().parent_id(block.hir_id));
if let (Some(expr), hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })) =
(&block.expr, parent)
{
None
}
})?;
- let opaque_ty = self.tcx.mk_opaque(rpit_def_id, substs);
if !self.can_coerce(first_ty, expected) || !self.can_coerce(second_ty, expected) {
return None;
{
let pred = pred.kind().rebind(match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => {
- assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty);
+ // FIXME(rpitit): This will need to be fixed when we move to associated types
+ assert!(matches!(
+ *trait_pred.trait_ref.self_ty().kind(),
+ ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+ if def_id == rpit_def_id && substs == substs
+ ));
ty::PredicateKind::Clause(ty::Clause::Trait(
trait_pred.with_self_ty(self.tcx, ty),
))
}
ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => {
- assert_eq!(proj_pred.projection_ty.self_ty(), opaque_ty);
+ assert!(matches!(
+ *proj_pred.projection_ty.self_ty().kind(),
+ ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+ if def_id == rpit_def_id && substs == substs
+ ));
proj_pred = proj_pred.with_self_ty(self.tcx, ty);
ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred))
}
});
if let Some(ok) = self.lookup_method_in_trait(
- call_expr.span,
+ self.misc(call_expr.span),
method_name,
trait_def_id,
adjusted_ty,
callee_span: Span,
) {
let hir = self.tcx.hir();
- let parent_hir_id = hir.get_parent_node(hir_id);
+ let parent_hir_id = hir.parent_id(hir_id);
let parent_node = hir.get(parent_hir_id);
if let (
hir::Node::Expr(hir::Expr {
{
// Actually need to unwrap a few more layers of HIR to get to
// the _real_ closure...
- let async_closure = hir.get_parent_node(hir.get_parent_node(parent_hir_id));
+ let async_closure = hir.parent_id(hir.parent_id(parent_hir_id));
if let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
..
call_expr: &'tcx hir::Expr<'tcx>,
callee_expr: &'tcx hir::Expr<'tcx>,
) -> bool {
- let hir_id = self.tcx.hir().get_parent_node(call_expr.hir_id);
+ let hir_id = self.tcx.hir().parent_id(call_expr.hir_id);
let parent_node = self.tcx.hir().get(hir_id);
if let (
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Array(_), .. }),
use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TypeSuperVisitable, TypeVisitor};
use rustc_span::source_map::Span;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use std::cmp;
use std::iter;
+use std::ops::ControlFlow;
/// What signature do we *expect* the closure to have from context?
#[derive(Debug, Clone, TypeFoldable, TypeVisitable)]
// closure sooner rather than later, so first examine the expected
// type, and see if can glean a closure kind from there.
let (expected_sig, expected_kind) = match expected.to_option(self) {
- Some(ty) => self.deduce_expectations_from_expected_type(ty),
+ Some(ty) => self.deduce_closure_signature(ty),
None => (None, None),
};
let body = self.tcx.hir().body(closure.body);
/// Given the expected type, figures out what it can about this closure we
/// are about to type check:
#[instrument(skip(self), level = "debug")]
- fn deduce_expectations_from_expected_type(
+ fn deduce_closure_signature(
&self,
expected_ty: Ty<'tcx>,
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
match *expected_ty.kind() {
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
- .deduce_signature_from_predicates(
+ .deduce_closure_signature_from_predicates(
+ expected_ty,
self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
),
ty::Dynamic(ref object_type, ..) => {
.and_then(|did| self.tcx.fn_trait_kind_from_def_id(did));
(sig, kind)
}
- ty::Infer(ty::TyVar(vid)) => self.deduce_signature_from_predicates(
+ ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates(
+ self.tcx.mk_ty_var(self.root_var(vid)),
self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)),
),
ty::FnPtr(sig) => {
}
}
- fn deduce_signature_from_predicates(
+ fn deduce_closure_signature_from_predicates(
&self,
+ expected_ty: Ty<'tcx>,
predicates: impl DoubleEndedIterator<Item = (ty::Predicate<'tcx>, Span)>,
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
let mut expected_sig = None;
if expected_sig.is_none()
&& let ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) = bound_predicate.skip_binder()
{
- expected_sig = self.normalize(
+ let inferred_sig = self.normalize(
obligation.cause.span,
self.deduce_sig_from_projection(
Some(obligation.cause.span),
bound_predicate.rebind(proj_predicate),
),
);
+ // Make sure that we didn't infer a signature that mentions itself.
+ // This can happen when we elaborate certain supertrait bounds that
+ // mention projections containing the `Self` type. See #105401.
+ struct MentionsTy<'tcx> {
+ expected_ty: Ty<'tcx>,
+ }
+ impl<'tcx> TypeVisitor<'tcx> for MentionsTy<'tcx> {
+ type BreakTy = ();
+
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if t == self.expected_ty {
+ ControlFlow::BREAK
+ } else {
+ t.super_visit_with(self)
+ }
+ }
+ }
+ if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() {
+ expected_sig = inferred_sig;
+ }
}
// Even if we can't infer the full signature, we may be able to
),
bound_vars,
);
- // Astconv can't normalize inputs or outputs with escaping bound vars,
- // so normalize them here, after we've wrapped them in a binder.
- let result = self.normalize(self.tcx.hir().span(hir_id), result);
let c_result = self.inh.infcx.canonicalize_response(result);
self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
- result
+ // Normalize only after registering in `user_provided_sigs`.
+ self.normalize(self.tcx.hir().span(hir_id), result)
}
/// Invoked when we are translating the generator that results
// Just ignore error types.
if a.references_error() || b.references_error() {
+ // Best-effort try to unify these types -- we're already on the error path,
+ // so this will have the side-effect of making sure we have no ambiguities
+ // due to `[type error]` and `_` not coercing together.
+ let _ = self.commit_if_ok(|_| self.at(&self.cause, self.param_env).eq(a, b));
return success(vec![], self.fcx.tcx.ty_error(), vec![]);
}
err.span_label(cause.span, "return type is not `()`");
}
ObligationCauseCode::BlockTailExpression(blk_id) => {
- let parent_id = fcx.tcx.hir().get_parent_node(blk_id);
+ let parent_id = fcx.tcx.hir().parent_id(blk_id);
err = self.report_return_mismatched_types(
cause,
expected,
None,
);
if !fcx.tcx.features().unsized_locals {
- let id = fcx.tcx.hir().get_parent_node(id);
+ let id = fcx.tcx.hir().parent_id(id);
unsized_return = self.is_return_ty_unsized(fcx, id);
}
}
let mut pointing_at_return_type = false;
let mut fn_output = None;
- let parent_id = fcx.tcx.hir().get_parent_node(id);
+ let parent_id = fcx.tcx.hir().parent_id(id);
let parent = fcx.tcx.hir().get(parent_id);
if let Some(expr) = expression
&& let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), .. }) = parent
use crate::FnCtxt;
use rustc_ast::util::parser::PREC_POSTFIX;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::MultiSpan;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def::CtorKind;
+use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node};
use rustc_infer::infer::InferOk;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut};
+use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder};
+use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
+use rustc_middle::ty::relate::TypeRelation;
+use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeVisitable};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{BytePos, Span};
use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::method_chain::CollectAllMismatches;
use rustc_trait_selection::traits::ObligationCause;
use super::method::probe;
expr_ty: Ty<'tcx>,
expected: Ty<'tcx>,
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
- _error: Option<TypeError<'tcx>>,
+ error: Option<TypeError<'tcx>>,
) {
if expr_ty == expected {
return;
}
+ self.annotate_alternative_method_deref(err, expr, error);
+
// Use `||` to give these suggestions a precedence
- let _ = self.suggest_missing_parentheses(err, expr)
+ let suggested = self.suggest_missing_parentheses(err, expr)
|| self.suggest_remove_last_method_call(err, expr, expected)
|| self.suggest_associated_const(err, expr, expected)
|| self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr)
|| self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
|| self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
|| self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
+ || self.suggest_clone_for_ref(err, expr, expr_ty, expected)
|| self.suggest_into(err, expr, expr_ty, expected)
|| self.suggest_floating_point_literal(err, expr, expected);
+ if !suggested {
+ self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected);
+ }
}
pub fn emit_coerce_suggestions(
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
+ self.check_for_range_as_method_call(err, expr, expr_ty, expected);
+ self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
}
/// Requires that the two types unify, and prints an error message if
(expected, Some(err))
}
+ pub fn point_at_expr_source_of_inferred_type(
+ &self,
+ err: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ found: Ty<'tcx>,
+ expected: Ty<'tcx>,
+ ) -> bool {
+ let map = self.tcx.hir();
+
+ let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else { return false; };
+ let [hir::PathSegment { ident, args: None, .. }] = p.segments else { return false; };
+ let hir::def::Res::Local(hir_id) = p.res else { return false; };
+ let Some(hir::Node::Pat(pat)) = map.find(hir_id) else { return false; };
+ let Some(hir::Node::Local(hir::Local {
+ ty: None,
+ init: Some(init),
+ ..
+ })) = map.find_parent(pat.hir_id) else { return false; };
+ let Some(ty) = self.node_ty_opt(init.hir_id) else { return false; };
+ if ty.is_closure() || init.span.overlaps(expr.span) || pat.span.from_expansion() {
+ return false;
+ }
+
+ // Locate all the usages of the relevant binding.
+ struct FindExprs<'hir> {
+ hir_id: hir::HirId,
+ uses: Vec<&'hir hir::Expr<'hir>>,
+ }
+ impl<'v> Visitor<'v> for FindExprs<'v> {
+ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+ if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = ex.kind
+ && let hir::def::Res::Local(hir_id) = path.res
+ && hir_id == self.hir_id
+ {
+ self.uses.push(ex);
+ }
+ hir::intravisit::walk_expr(self, ex);
+ }
+ }
+
+ let mut expr_finder = FindExprs { hir_id, uses: vec![] };
+ let id = map.get_parent_item(hir_id);
+ let hir_id: hir::HirId = id.into();
+
+ let Some(node) = map.find(hir_id) else { return false; };
+ let Some(body_id) = node.body_id() else { return false; };
+ let body = map.body(body_id);
+ expr_finder.visit_expr(body.value);
+ // Hack to make equality checks on types with inference variables and regions useful.
+ let mut eraser = BottomUpFolder {
+ tcx: self.tcx,
+ lt_op: |_| self.tcx.lifetimes.re_erased,
+ ct_op: |c| c,
+ ty_op: |t| match *t.kind() {
+ ty::Infer(ty::TyVar(vid)) => self.tcx.mk_ty_infer(ty::TyVar(self.root_var(vid))),
+ ty::Infer(ty::IntVar(_)) => {
+ self.tcx.mk_ty_infer(ty::IntVar(ty::IntVid { index: 0 }))
+ }
+ ty::Infer(ty::FloatVar(_)) => {
+ self.tcx.mk_ty_infer(ty::FloatVar(ty::FloatVid { index: 0 }))
+ }
+ _ => t,
+ },
+ };
+ let mut prev = eraser.fold_ty(ty);
+ let mut prev_span = None;
+
+ for binding in expr_finder.uses {
+ // In every expression where the binding is referenced, we will look at that
+ // expression's type and see if it is where the incorrect found type was fully
+ // "materialized" and point at it. We will also try to provide a suggestion there.
+ if let Some(hir::Node::Expr(expr)
+ | hir::Node::Stmt(hir::Stmt {
+ kind: hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr),
+ ..
+ })) = &map.find_parent(binding.hir_id)
+ && let hir::ExprKind::MethodCall(segment, rcvr, args, _span) = expr.kind
+ && rcvr.hir_id == binding.hir_id
+ && let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(expr.hir_id)
+ {
+ // We special case methods, because they can influence inference through the
+ // call's arguments and we can provide a more explicit span.
+ let sig = self.tcx.fn_sig(def_id);
+ let def_self_ty = sig.input(0).skip_binder();
+ let rcvr_ty = self.node_ty(rcvr.hir_id);
+ // Get the evaluated type *after* calling the method call, so that the influence
+ // of the arguments can be reflected in the receiver type. The receiver
+ // expression has the type *before* theis analysis is done.
+ let ty = match self.lookup_probe(
+ segment.ident,
+ rcvr_ty,
+ expr,
+ probe::ProbeScope::TraitsInScope,
+ ) {
+ Ok(pick) => pick.self_ty,
+ Err(_) => rcvr_ty,
+ };
+ // Remove one layer of references to account for `&mut self` and
+ // `&self`, so that we can compare it against the binding.
+ let (ty, def_self_ty) = match (ty.kind(), def_self_ty.kind()) {
+ (ty::Ref(_, ty, a), ty::Ref(_, self_ty, b)) if a == b => (*ty, *self_ty),
+ _ => (ty, def_self_ty),
+ };
+ let mut param_args = FxHashMap::default();
+ let mut param_expected = FxHashMap::default();
+ let mut param_found = FxHashMap::default();
+ if self.can_eq(self.param_env, ty, found).is_ok() {
+ // We only point at the first place where the found type was inferred.
+ for (i, param_ty) in sig.inputs().skip_binder().iter().skip(1).enumerate() {
+ if def_self_ty.contains(*param_ty) && let ty::Param(_) = param_ty.kind() {
+ // We found an argument that references a type parameter in `Self`,
+ // so we assume that this is the argument that caused the found
+ // type, which we know already because of `can_eq` above was first
+ // inferred in this method call.
+ let arg = &args[i];
+ let arg_ty = self.node_ty(arg.hir_id);
+ err.span_label(
+ arg.span,
+ &format!(
+ "this is of type `{arg_ty}`, which causes `{ident}` to be \
+ inferred as `{ty}`",
+ ),
+ );
+ param_args.insert(param_ty, (arg, arg_ty));
+ }
+ }
+ }
+
+ // Here we find, for a type param `T`, the type that `T` is in the current
+ // method call *and* in the original expected type. That way, we can see if we
+ // can give any structured suggestion for the function argument.
+ let mut c = CollectAllMismatches {
+ infcx: &self.infcx,
+ param_env: self.param_env,
+ errors: vec![],
+ };
+ let _ = c.relate(def_self_ty, ty);
+ for error in c.errors {
+ if let TypeError::Sorts(error) = error {
+ param_found.insert(error.expected, error.found);
+ }
+ }
+ c.errors = vec![];
+ let _ = c.relate(def_self_ty, expected);
+ for error in c.errors {
+ if let TypeError::Sorts(error) = error {
+ param_expected.insert(error.expected, error.found);
+ }
+ }
+ for (param, (arg, arg_ty)) in param_args.iter() {
+ let Some(expected) = param_expected.get(param) else { continue; };
+ let Some(found) = param_found.get(param) else { continue; };
+ if self.can_eq(self.param_env, *arg_ty, *found).is_err() { continue; }
+ self.emit_coerce_suggestions(err, arg, *found, *expected, None, None);
+ }
+
+ let ty = eraser.fold_ty(ty);
+ if ty.references_error() {
+ break;
+ }
+ if ty != prev
+ && param_args.is_empty()
+ && self.can_eq(self.param_env, ty, found).is_ok()
+ {
+ // We only point at the first place where the found type was inferred.
+ err.span_label(
+ segment.ident.span,
+ with_forced_trimmed_paths!(format!(
+ "here the type of `{ident}` is inferred to be `{ty}`",
+ )),
+ );
+ break;
+ } else if !param_args.is_empty() {
+ break;
+ }
+ prev = ty;
+ } else {
+ let ty = eraser.fold_ty(self.node_ty(binding.hir_id));
+ if ty.references_error() {
+ break;
+ }
+ if ty != prev
+ && let Some(span) = prev_span
+ && self.can_eq(self.param_env, ty, found).is_ok()
+ {
+ // We only point at the first place where the found type was inferred.
+ // We use the *previous* span because if the type is known *here* it means
+ // it was *evaluated earlier*. We don't do this for method calls because we
+ // evaluate the method's self type eagerly, but not in any other case.
+ err.span_label(
+ span,
+ with_forced_trimmed_paths!(format!(
+ "here the type of `{ident}` is inferred to be `{ty}`",
+ )),
+ );
+ break;
+ }
+ prev = ty;
+ }
+ if binding.hir_id == expr.hir_id {
+ // Do not look at expressions that come after the expression we were originally
+ // evaluating and had a type error.
+ break;
+ }
+ prev_span = Some(binding.span);
+ }
+ true
+ }
+
fn annotate_expected_due_to_let_ty(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
error: Option<TypeError<'tcx>>,
) {
- let parent = self.tcx.hir().get_parent_node(expr.hir_id);
+ let parent = self.tcx.hir().parent_id(expr.hir_id);
match (self.tcx.hir().find(parent), error) {
(Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })), _)
if init.hir_id == expr.hir_id =>
hir::Path { res: hir::def::Res::Local(hir_id), .. },
)) => {
if let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(*hir_id) {
- let parent = self.tcx.hir().get_parent_node(pat.hir_id);
primary_span = pat.span;
secondary_span = pat.span;
- match self.tcx.hir().find(parent) {
+ match self.tcx.hir().find_parent(pat.hir_id) {
Some(hir::Node::Local(hir::Local { ty: Some(ty), .. })) => {
primary_span = ty.span;
post_message = " type";
}
}
+ fn annotate_alternative_method_deref(
+ &self,
+ err: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ error: Option<TypeError<'tcx>>,
+ ) {
+ let parent = self.tcx.hir().parent_id(expr.hir_id);
+ let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {return;};
+ let Some(hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Assign(lhs, rhs, _), ..
+ })) = self.tcx.hir().find(parent) else {return; };
+ if rhs.hir_id != expr.hir_id || expected.is_closure() {
+ return;
+ }
+ let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else { return; };
+ let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else { return; };
+ let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else { return; };
+
+ let Ok(pick) = self
+ .probe_for_name(
+ probe::Mode::MethodCall,
+ path.ident,
+ probe::IsSuggestion(true),
+ self_ty,
+ deref.hir_id,
+ probe::ProbeScope::TraitsInScope,
+ ) else {
+ return;
+ };
+ let in_scope_methods = self.probe_for_name_many(
+ probe::Mode::MethodCall,
+ path.ident,
+ probe::IsSuggestion(true),
+ self_ty,
+ deref.hir_id,
+ probe::ProbeScope::TraitsInScope,
+ );
+ let other_methods_in_scope: Vec<_> =
+ in_scope_methods.iter().filter(|c| c.item.def_id != pick.item.def_id).collect();
+
+ let all_methods = self.probe_for_name_many(
+ probe::Mode::MethodCall,
+ path.ident,
+ probe::IsSuggestion(true),
+ self_ty,
+ deref.hir_id,
+ probe::ProbeScope::AllTraits,
+ );
+ let suggestions: Vec<_> = all_methods
+ .into_iter()
+ .filter(|c| c.item.def_id != pick.item.def_id)
+ .map(|c| {
+ let m = c.item;
+ let substs = ty::InternalSubsts::for_item(self.tcx, m.def_id, |param, _| {
+ self.var_for_def(deref.span, param)
+ });
+ vec![
+ (
+ deref.span.until(base.span),
+ format!(
+ "{}({}",
+ with_no_trimmed_paths!(
+ self.tcx.def_path_str_with_substs(m.def_id, substs,)
+ ),
+ match self.tcx.fn_sig(m.def_id).input(0).skip_binder().kind() {
+ ty::Ref(_, _, hir::Mutability::Mut) => "&mut ",
+ ty::Ref(_, _, _) => "&",
+ _ => "",
+ },
+ ),
+ ),
+ match &args[..] {
+ [] => (base.span.shrink_to_hi().with_hi(deref.span.hi()), ")".to_string()),
+ [first, ..] => (base.span.between(first.span), ", ".to_string()),
+ },
+ ]
+ })
+ .collect();
+ if suggestions.is_empty() {
+ return;
+ }
+ let mut path_span: MultiSpan = path.ident.span.into();
+ path_span.push_span_label(
+ path.ident.span,
+ with_no_trimmed_paths!(format!(
+ "refers to `{}`",
+ self.tcx.def_path_str(pick.item.def_id),
+ )),
+ );
+ let container_id = pick.item.container_id(self.tcx);
+ let container = with_no_trimmed_paths!(self.tcx.def_path_str(container_id));
+ for def_id in pick.import_ids {
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+ path_span.push_span_label(
+ self.tcx.hir().span(hir_id),
+ format!("`{container}` imported here"),
+ );
+ }
+ let tail = with_no_trimmed_paths!(match &other_methods_in_scope[..] {
+ [] => return,
+ [candidate] => format!(
+ "the method of the same name on {} `{}`",
+ match candidate.kind {
+ probe::CandidateKind::InherentImplCandidate(..) => "the inherent impl for",
+ _ => "trait",
+ },
+ self.tcx.def_path_str(candidate.item.container_id(self.tcx))
+ ),
+ [.., last] if other_methods_in_scope.len() < 5 => {
+ format!(
+ "the methods of the same name on {} and `{}`",
+ other_methods_in_scope[..other_methods_in_scope.len() - 1]
+ .iter()
+ .map(|c| format!(
+ "`{}`",
+ self.tcx.def_path_str(c.item.container_id(self.tcx))
+ ))
+ .collect::<Vec<String>>()
+ .join(", "),
+ self.tcx.def_path_str(last.item.container_id(self.tcx))
+ )
+ }
+ _ => format!(
+ "the methods of the same name on {} other traits",
+ other_methods_in_scope.len()
+ ),
+ });
+ err.span_note(
+ path_span,
+ &format!(
+ "the `{}` call is resolved to the method in `{container}`, shadowing {tail}",
+ path.ident,
+ ),
+ );
+ if suggestions.len() > other_methods_in_scope.len() {
+ err.note(&format!(
+ "additionally, there are {} other available methods that aren't in scope",
+ suggestions.len() - other_methods_in_scope.len()
+ ));
+ }
+ err.multipart_suggestions(
+ &format!(
+ "you might have meant to call {}; you can use the fully-qualified path to call {} \
+ explicitly",
+ if suggestions.len() == 1 {
+ "the other method"
+ } else {
+ "one of the other methods"
+ },
+ if suggestions.len() == 1 { "it" } else { "one of them" },
+ ),
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ }
+
/// If the expected type is an enum (Issue #55250) with any variants whose
/// sole field is of the found type, suggest such variants. (Issue #42764)
fn suggest_compatible_variants(
// Unroll desugaring, to make sure this works for `for` loops etc.
loop {
- parent = self.tcx.hir().get_parent_node(id);
+ parent = self.tcx.hir().parent_id(id);
if let Some(parent_span) = self.tcx.hir().opt_span(parent) {
if parent_span.find_ancestor_inside(expr.span).is_some() {
// The parent node is part of the same span, so is the result of the
return None;
};
- let local_parent = self.tcx.hir().get_parent_node(local_id);
+ let local_parent = self.tcx.hir().parent_id(local_id);
let Some(Node::Param(hir::Param { hir_id: param_hir_id, .. })) = self.tcx.hir().find(local_parent) else {
return None;
};
- let param_parent = self.tcx.hir().get_parent_node(*param_hir_id);
+ let param_parent = self.tcx.hir().parent_id(*param_hir_id);
let Some(Node::Expr(hir::Expr {
hir_id: expr_hir_id,
kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }),
return None;
};
- let expr_parent = self.tcx.hir().get_parent_node(*expr_hir_id);
+ let expr_parent = self.tcx.hir().parent_id(*expr_hir_id);
let hir = self.tcx.hir().find(expr_parent);
let closure_params_len = closure_fn_decl.inputs.len();
let (
_ => None,
}?;
- match hir.find(hir.get_parent_node(expr.hir_id))? {
+ match hir.find_parent(expr.hir_id)? {
Node::ExprField(field) => {
if field.ident.name == local.name && field.is_shorthand {
return Some(local.name);
/// Returns whether the given expression is an `else if`.
pub(crate) fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
if let hir::ExprKind::If(..) = expr.kind {
- let parent_id = self.tcx.hir().get_parent_node(expr.hir_id);
+ let parent_id = self.tcx.hir().parent_id(expr.hir_id);
if let Some(Node::Expr(hir::Expr {
kind: hir::ExprKind::If(_, _, Some(else_expr)),
..
if let Some(hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Assign(..),
..
- })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
+ })) = self.tcx.hir().find_parent(expr.hir_id)
{
if mutability.is_mut() {
// Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
}
}
// If we've reached our target type with just removing `&`, then just print now.
- if steps == 0 {
+ if steps == 0 && !remove.trim().is_empty() {
return Some((
prefix_span,
format!("consider removing the `{}`", remove.trim()),
} else {
(prefix_span, format!("{}{}", prefix, "*".repeat(steps)))
};
+ if suggestion.trim().is_empty() {
+ return None;
+ }
return Some((
span,
let mut sugg = vec![];
- if let Some(hir::Node::ExprField(field)) =
- self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
- {
+ if let Some(hir::Node::ExprField(field)) = self.tcx.hir().find_parent(expr.hir_id) {
// `expr` is a literal field for a struct, only suggest if appropriate
if field.is_shorthand {
// This is a field literal
_ => false,
}
}
+
+ /// Identify when the user has written `foo..bar()` instead of `foo.bar()`.
+ pub fn check_for_range_as_method_call(
+ &self,
+ err: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ checked_ty: Ty<'tcx>,
+ expected_ty: Ty<'tcx>,
+ ) {
+ if !hir::is_range_literal(expr) {
+ return;
+ }
+ let hir::ExprKind::Struct(
+ hir::QPath::LangItem(LangItem::Range, ..),
+ [start, end],
+ _,
+ ) = expr.kind else { return; };
+ let parent = self.tcx.hir().parent_id(expr.hir_id);
+ if let Some(hir::Node::ExprField(_)) = self.tcx.hir().find(parent) {
+ // Ignore `Foo { field: a..Default::default() }`
+ return;
+ }
+ let mut expr = end.expr;
+ while let hir::ExprKind::MethodCall(_, rcvr, ..) = expr.kind {
+ // Getting to the root receiver and asserting it is a fn call let's us ignore cases in
+ // `src/test/ui/methods/issues/issue-90315.stderr`.
+ expr = rcvr;
+ }
+ let hir::ExprKind::Call(method_name, _) = expr.kind else { return; };
+ let ty::Adt(adt, _) = checked_ty.kind() else { return; };
+ if self.tcx.lang_items().range_struct() != Some(adt.did()) {
+ return;
+ }
+ if let ty::Adt(adt, _) = expected_ty.kind()
+ && self.tcx.lang_items().range_struct() == Some(adt.did())
+ {
+ return;
+ }
+ // Check if start has method named end.
+ let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = method_name.kind else { return; };
+ let [hir::PathSegment { ident, .. }] = p.segments else { return; };
+ let self_ty = self.typeck_results.borrow().expr_ty(start.expr);
+ let Ok(_pick) = self.probe_for_name(
+ probe::Mode::MethodCall,
+ *ident,
+ probe::IsSuggestion(true),
+ self_ty,
+ expr.hir_id,
+ probe::ProbeScope::AllTraits,
+ ) else { return; };
+ let mut sugg = ".";
+ let mut span = start.expr.span.between(end.expr.span);
+ if span.lo() + BytePos(2) == span.hi() {
+ // There's no space between the start, the range op and the end, suggest removal which
+ // will be more noticeable than the replacement of `..` with `.`.
+ span = span.with_lo(span.lo() + BytePos(1));
+ sugg = "";
+ }
+ err.span_suggestion_verbose(
+ span,
+ "you likely meant to write a method call instead of a range",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+
+ /// Identify when the type error is because `()` is found in a binding that was assigned a
+ /// block without a tail expression.
+ fn check_for_binding_assigned_block_without_tail_expression(
+ &self,
+ err: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ checked_ty: Ty<'tcx>,
+ expected_ty: Ty<'tcx>,
+ ) {
+ if !checked_ty.is_unit() {
+ return;
+ }
+ let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; };
+ let hir::def::Res::Local(hir_id) = path.res else { return; };
+ let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else {
+ return;
+ };
+ let Some(hir::Node::Local(hir::Local {
+ ty: None,
+ init: Some(init),
+ ..
+ })) = self.tcx.hir().find_parent(pat.hir_id) else { return; };
+ let hir::ExprKind::Block(block, None) = init.kind else { return; };
+ if block.expr.is_some() {
+ return;
+ }
+ let [.., stmt] = block.stmts else {
+ err.span_label(block.span, "this empty block is missing a tail expression");
+ return;
+ };
+ let hir::StmtKind::Semi(tail_expr) = stmt.kind else { return; };
+ let Some(ty) = self.node_ty_opt(tail_expr.hir_id) else { return; };
+ if self.can_eq(self.param_env, expected_ty, ty).is_ok() {
+ err.span_suggestion_short(
+ stmt.span.with_lo(tail_expr.span.hi()),
+ "remove this semicolon",
+ "",
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.span_label(block.span, "this block is missing a tail expression");
+ }
+ }
}
) => self.check_expr_path(qpath, expr, args),
_ => self.check_expr_kind(expr, expected),
});
+ let ty = self.resolve_vars_if_possible(ty);
// Warn for non-block expressions with diverging children.
match expr.kind {
E0614,
"type `{oprnd_t}` cannot be dereferenced",
);
- let sp = tcx.sess.source_map().start_point(expr.span);
+ let sp = tcx.sess.source_map().start_point(expr.span).with_parent(None);
if let Some(sp) =
tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
{
original_expr_id: HirId,
then: impl FnOnce(&hir::Expr<'_>),
) {
- let mut parent = self.tcx.hir().get_parent_node(original_expr_id);
+ let mut parent = self.tcx.hir().parent_id(original_expr_id);
while let Some(node) = self.tcx.hir().find(parent) {
match node {
hir::Node::Expr(hir::Expr {
}) => {
// Check if our original expression is a child of the condition of a while loop
let expr_is_ancestor = std::iter::successors(Some(original_expr_id), |id| {
- self.tcx.hir().find_parent_node(*id)
+ self.tcx.hir().opt_parent_id(*id)
})
.take_while(|id| *id != parent)
.any(|id| id == expr.hir_id);
| hir::Node::TraitItem(_)
| hir::Node::Crate(_) => break,
_ => {
- parent = self.tcx.hir().get_parent_node(parent);
+ parent = self.tcx.hir().parent_id(parent);
}
}
}
// Do not suggest `if let x = y` as `==` is way more likely to be the intention.
let hir = self.tcx.hir();
if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
- hir.get(hir.get_parent_node(hir.get_parent_node(expr.hir_id)))
+ hir.get_parent(hir.parent_id(expr.hir_id))
{
err.span_suggestion_verbose(
expr.span.shrink_to_lo(),
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
return field_ty;
}
- private_candidate = Some((adjustments, base_def.did(), field_ty));
+ private_candidate = Some((adjustments, base_def.did()));
}
}
ty::Tuple(tys) => {
}
self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
- if let Some((adjustments, did, field_ty)) = private_candidate {
+ if let Some((adjustments, did)) = private_candidate {
// (#90483) apply adjustments to avoid ExprUseVisitor from
// creating erroneous projection.
self.apply_adjustments(base, adjustments);
self.ban_private_field_access(expr, base_ty, field, did);
- return field_ty;
+ return self.tcx().ty_error();
}
if field.name == kw::Empty {
err.span_label(field.span, "method, not a field");
let expr_is_call =
if let hir::Node::Expr(hir::Expr { kind: ExprKind::Call(callee, _args), .. }) =
- self.tcx.hir().get(self.tcx.hir().get_parent_node(expr.hir_id))
+ self.tcx.hir().get_parent(expr.hir_id)
{
expr.hir_id == callee.hir_id
} else {
use crate::callee::{self, DeferredCallResolution};
use crate::method::{self, MethodCallee, SelfSource};
use crate::rvalue_scopes;
-use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
+use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
use rustc_middle::ty::{
self, AdtKind, CanonicalUserType, DefIdTree, GenericParamDefKind, Ty, UserType,
};
-use rustc_middle::ty::{GenericArgKind, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts};
+use rustc_middle::ty::{GenericArgKind, SubstsRef, UserSelfTy, UserSubsts};
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) {
self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id)));
self.write_substs(hir_id, method.substs);
-
- // When the method is confirmed, the `method.substs` includes
- // parameters from not just the method, but also the impl of
- // the method -- in particular, the `Self` type will be fully
- // resolved. However, those are not something that the "user
- // specified" -- i.e., those types come from the inferred type
- // of the receiver, not something the user wrote. So when we
- // create the user-substs, we want to replace those earlier
- // types with just the types that the user actually wrote --
- // that is, those that appear on the *method itself*.
- //
- // As an example, if the user wrote something like
- // `foo.bar::<u32>(...)` -- the `Self` type here will be the
- // type of `foo` (possibly adjusted), but we don't want to
- // include that. We want just the `[_, u32]` part.
- if !method.substs.is_empty() {
- let method_generics = self.tcx.generics_of(method.def_id);
- if !method_generics.params.is_empty() {
- let user_type_annotation = self.probe(|_| {
- let user_substs = UserSubsts {
- substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| {
- let i = param.index as usize;
- if i < method_generics.parent_count {
- self.var_for_def(DUMMY_SP, param)
- } else {
- method.substs[i]
- }
- }),
- user_self_ty: None, // not relevant here
- };
-
- self.canonicalize_user_type_annotation(UserType::TypeOf(
- method.def_id,
- user_substs,
- ))
- });
-
- debug!("write_method_call: user_type_annotation={:?}", user_type_annotation);
- self.write_user_type_annotation(hir_id, user_type_annotation);
- }
- }
}
pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) {
}
}
- pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> {
+ pub fn handle_raw_ty(&self, span: Span, ty: Ty<'tcx>) -> RawTy<'tcx> {
+ RawTy { raw: ty, normalized: self.normalize(span, ty) }
+ }
+
+ pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> RawTy<'tcx> {
let t = <dyn AstConv<'_>>::ast_ty_to_ty(self, ast_t);
self.register_wf_obligation(t.into(), ast_t.span, traits::WellFormed(None));
- t
+ self.handle_raw_ty(ast_t.span, t)
}
pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
let ty = self.to_ty(ast_ty);
debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
- if Self::can_contain_user_lifetime_bounds(ty) {
- let c_ty = self.canonicalize_response(UserType::Ty(ty));
+ if Self::can_contain_user_lifetime_bounds(ty.raw) {
+ let c_ty = self.canonicalize_response(UserType::Ty(ty.raw));
debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
}
- ty
+ ty.normalized
+ }
+
+ pub(super) fn user_substs_for_adt(ty: RawTy<'tcx>) -> UserSubsts<'tcx> {
+ match (ty.raw.kind(), ty.normalized.kind()) {
+ (ty::Adt(_, substs), _) => UserSubsts { substs, user_self_ty: None },
+ (_, ty::Adt(adt, substs)) => UserSubsts {
+ substs,
+ user_self_ty: Some(UserSelfTy { impl_def_id: adt.did(), self_ty: ty.raw }),
+ },
+ _ => bug!("non-adt type {:?}", ty),
+ }
}
pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
qpath: &'tcx QPath<'tcx>,
hir_id: hir::HirId,
span: Span,
- ) -> (Res, Option<Ty<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) {
+ ) -> (Res, Option<RawTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) {
debug!(
"resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}",
qpath, hir_id, span
// to be object-safe.
// We manually call `register_wf_obligation` in the success path
// below.
- (<dyn AstConv<'_>>::ast_ty_to_ty_in_path(self, qself), qself, segment)
+ let ty = <dyn AstConv<'_>>::ast_ty_to_ty_in_path(self, qself);
+ (self.handle_raw_ty(span, ty), qself, segment)
}
QPath::LangItem(..) => {
bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`")
};
if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
{
- self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
+ self.register_wf_obligation(ty.raw.into(), qself.span, traits::WellFormed(None));
// Return directly on cache hit. This is useful to avoid doubly reporting
// errors with default match binding modes. See #44614.
let def = cached_result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id));
}
let item_name = item_segment.ident;
let result = self
- .resolve_fully_qualified_call(span, item_name, ty, qself.span, hir_id)
+ .resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id)
.or_else(|error| {
let result = match error {
method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
// a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise,
// register a WF obligation so that we can detect any additional
// errors in the self type.
- if !(matches!(error, method::MethodError::NoMatch(_)) && ty.is_trait()) {
- self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
+ if !(matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait()) {
+ self.register_wf_obligation(
+ ty.raw.into(),
+ qself.span,
+ traits::WellFormed(None),
+ );
}
if item_name.name != kw::Empty {
if let Some(mut e) = self.report_method_error(
span,
- ty,
+ ty.normalized,
item_name,
SelfSource::QPath(qself),
error,
});
if result.is_ok() {
- self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
+ self.register_wf_obligation(ty.raw.into(), qself.span, traits::WellFormed(None));
}
// Write back the new resolution.
pub fn instantiate_value_path(
&self,
segments: &[hir::PathSegment<'_>],
- self_ty: Option<Ty<'tcx>>,
+ self_ty: Option<RawTy<'tcx>>,
res: Res,
span: Span,
hir_id: hir::HirId,
let path_segs = match res {
Res::Local(_) | Res::SelfCtor(_) => vec![],
Res::Def(kind, def_id) => <dyn AstConv<'_>>::def_ids_for_value_path_segments(
- self, segments, self_ty, kind, def_id,
+ self,
+ segments,
+ self_ty.map(|ty| ty.raw),
+ kind,
+ def_id,
+ span,
),
_ => bug!("instantiate_value_path on {:?}", res),
};
Res::Def(DefKind::Ctor(CtorOf::Variant, _), _)
if let Some(self_ty) = self_ty =>
{
- let adt_def = self_ty.ty_adt_def().unwrap();
- user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty });
+ let adt_def = self_ty.normalized.ty_adt_def().unwrap();
+ user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty: self_ty.raw });
is_alias_variant_ctor = true;
}
Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
// inherent impl, we need to record the
// `T` for posterity (see `UserSelfTy` for
// details).
- let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
+ let self_ty = self_ty.expect("UFCS sugared assoc missing Self").raw;
user_self_ty = Some(UserSelfTy { impl_def_id: container_id, self_ty });
}
}
.unwrap_or(false);
let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
- let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id));
- match *ty.kind() {
- ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
- let variant = adt_def.non_enum_variant();
- let (ctor_kind, ctor_def_id) = variant.ctor.unwrap();
- (Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id), Some(substs))
+ let ty = self.handle_raw_ty(span, tcx.at(span).type_of(impl_def_id));
+ match ty.normalized.ty_adt_def() {
+ Some(adt_def) if adt_def.has_ctor() => {
+ let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap();
+ let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
+ let user_substs = Self::user_substs_for_adt(ty);
+ user_self_ty = user_substs.user_self_ty;
+ (new_res, Some(user_substs.substs))
}
_ => {
let mut err = tcx.sess.struct_span_err(
span,
"the `Self` constructor can only be used with tuple or unit structs",
);
- if let Some(adt_def) = ty.ty_adt_def() {
+ if let Some(adt_def) = ty.normalized.ty_adt_def() {
match adt_def.adt_kind() {
AdtKind::Enum => {
err.help("did you mean to use one of the enum's variants?");
<dyn AstConv<'_>>::ast_region_to_region(self.fcx, lt, Some(param)).into()
}
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
- self.fcx.to_ty(ty).into()
+ self.fcx.to_ty(ty).raw.into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
self.fcx.const_arg_to_const(&ct.value, param.def_id).into()
// If we have a default, then we it doesn't matter that we're not
// inferring the type arguments: we provide the default where any
// is missing.
- let default = tcx.bound_type_of(param.def_id);
- self.fcx
- .normalize_ty(self.span, default.subst(tcx, substs.unwrap()))
- .into()
+ tcx.bound_type_of(param.def_id).subst(tcx, substs.unwrap()).into()
} else {
// If no type arguments were provided, we have to infer them.
// This case also occurs as a result of some malformed input, e.g.
}
}
- let substs = self_ctor_substs.unwrap_or_else(|| {
+ let substs_raw = self_ctor_substs.unwrap_or_else(|| {
<dyn AstConv<'_>>::create_substs_for_generic_args(
tcx,
def_id,
&[],
has_self,
- self_ty,
+ self_ty.map(|s| s.raw),
&arg_count,
&mut CreateCtorSubstsContext {
fcx: self,
});
// First, store the "user substs" for later.
- self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty);
+ self.write_user_type_annotation_from_substs(hir_id, def_id, substs_raw, user_self_ty);
+
+ // Normalize only after registering type annotations.
+ let substs = self.normalize(span, substs_raw);
self.add_required_obligations_for_hir(span, def_id, &substs, hir_id);
// with the substituted impl type.
// This also occurs for an enum variant on a type alias.
let impl_ty = self.normalize(span, tcx.bound_type_of(impl_def_id).subst(tcx, substs));
+ let self_ty = self.normalize(span, self_ty);
match self.at(&self.misc(span), self.param_env).eq(impl_ty, self_ty) {
Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => {
pub(in super::super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool {
let mut contained_in_place = false;
- while let hir::Node::Expr(parent_expr) =
- self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id))
- {
+ while let hir::Node::Expr(parent_expr) = self.tcx.hir().get_parent(expr_id) {
match &parent_expr.kind {
hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => {
if lhs.hir_id == expr_id {
use crate::Expectation::*;
use crate::TupleArgumentsFlag::*;
use crate::{
- struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs,
+ struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs, RawTy,
TupleArgumentsFlag,
};
use rustc_ast as ast;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
call_expr: &hir::Expr<'tcx>,
) {
// Next, let's construct the error
- let (error_span, full_call_span, ctor_of, is_method) = match &call_expr.kind {
+ let (error_span, full_call_span, call_name, is_method) = match &call_expr.kind {
hir::ExprKind::Call(
hir::Expr { hir_id, span, kind: hir::ExprKind::Path(qpath), .. },
_,
if let Res::Def(DefKind::Ctor(of, _), _) =
self.typeck_results.borrow().qpath_res(qpath, *hir_id)
{
- (call_span, *span, Some(of), false)
+ let name = match of {
+ CtorOf::Struct => "struct",
+ CtorOf::Variant => "enum variant",
+ };
+ (call_span, *span, name, false)
} else {
- (call_span, *span, None, false)
+ (call_span, *span, "function", false)
}
}
- hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None, false),
+ hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, "function", false),
hir::ExprKind::MethodCall(path_segment, _, _, span) => {
let ident_span = path_segment.ident.span;
let ident_span = if let Some(args) = path_segment.args {
} else {
ident_span
};
- // methods are never ctors
- (*span, ident_span, None, true)
+ (*span, ident_span, "method", true)
}
k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
};
let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span);
- let call_name = match ctor_of {
- Some(CtorOf::Struct) => "struct",
- Some(CtorOf::Variant) => "enum variant",
- None => "function",
- };
// Don't print if it has error types or is just plain `_`
fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
err = tcx.sess.struct_span_err_with_code(
full_call_span,
&format!(
- "this {} takes {}{} but {} {} supplied",
- call_name,
+ "{call_name} takes {}{} but {} {} supplied",
if c_variadic { "at least " } else { "" },
potentially_plural_count(
formal_and_expected_inputs.len(),
full_call_span,
format!("arguments to this {} are incorrect", call_name),
);
+ if let (Some(callee_ty), hir::ExprKind::MethodCall(_, rcvr, _, _)) =
+ (callee_ty, &call_expr.kind)
+ {
+ // Type that would have accepted this argument if it hadn't been inferred earlier.
+ // FIXME: We leave an inference variable for now, but it'd be nice to get a more
+ // specific type to increase the accuracy of the diagnostic.
+ let expected = self.infcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::MiscVariable,
+ span: full_call_span,
+ });
+ self.point_at_expr_source_of_inferred_type(&mut err, rcvr, expected, callee_ty);
+ }
// Call out where the function is defined
self.label_fn_like(
&mut err,
);
return None;
}
- Res::Def(DefKind::Variant, _) => match ty.kind() {
- ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did(), substs)),
- _ => bug!("unexpected type: {:?}", ty),
+ Res::Def(DefKind::Variant, _) => match ty.normalized.ty_adt_def() {
+ Some(adt) => {
+ Some((adt.variant_of_res(def), adt.did(), Self::user_substs_for_adt(ty)))
+ }
+ _ => bug!("unexpected type: {:?}", ty.normalized),
},
Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
| Res::SelfTyParam { .. }
- | Res::SelfTyAlias { .. } => match ty.kind() {
- ty::Adt(adt, substs) if !adt.is_enum() => {
- Some((adt.non_enum_variant(), adt.did(), substs))
+ | Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() {
+ Some(adt) if !adt.is_enum() => {
+ Some((adt.non_enum_variant(), adt.did(), Self::user_substs_for_adt(ty)))
}
_ => None,
},
_ => bug!("unexpected definition: {:?}", def),
};
- if let Some((variant, did, substs)) = variant {
+ if let Some((variant, did, ty::UserSubsts { substs, user_self_ty })) = variant {
debug!("check_struct_path: did={:?} substs={:?}", did, substs);
- self.write_user_type_annotation_from_substs(hir_id, did, substs, None);
+
+ // Register type annotation.
+ self.write_user_type_annotation_from_substs(hir_id, did, substs, user_self_ty);
// Check bounds on type arguments used in the path.
self.add_required_obligations_for_hir(path_span, did, substs, hir_id);
- Some((variant, ty))
+ Some((variant, ty.normalized))
} else {
- match ty.kind() {
+ match ty.normalized.kind() {
ty::Error(_) => {
// E0071 might be caused by a spelling error, which will have
// already caused an error message and probably a suggestion
path_span,
E0071,
"expected struct, variant or union type, found {}",
- ty.sort_string(self.tcx)
+ ty.normalized.sort_string(self.tcx)
)
.span_label(path_span, "not a struct")
.emit();
// Type check the initializer.
if let Some(ref init) = decl.init {
let init_ty = self.check_decl_initializer(decl.hir_id, decl.pat, &init);
- self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, init_ty);
+ self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, init_ty);
}
// Does the expected pattern type originate from an expression and what is the span?
// Type check the pattern. Override if necessary to avoid knock-on errors.
self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr);
let pat_ty = self.node_ty(decl.pat.hir_id);
- self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty);
+ self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty);
if let Some(blk) = decl.els {
let previous_diverges = self.diverges.get();
&self,
hir_id: hir::HirId,
pat: &'tcx hir::Pat<'tcx>,
- decl_ty: Ty<'tcx>,
ty: Ty<'tcx>,
) {
if ty.references_error() {
// Override the types everywhere with `err()` to avoid knock on errors.
- self.write_ty(hir_id, ty);
- self.write_ty(pat.hir_id, ty);
- let local_ty = LocalTy { decl_ty, revealed_ty: ty };
+ let err = self.tcx.ty_error();
+ self.write_ty(hir_id, err);
+ self.write_ty(pat.hir_id, err);
+ let local_ty = LocalTy { decl_ty: err, revealed_ty: err };
self.locals.borrow_mut().insert(hir_id, local_ty);
self.locals.borrow_mut().insert(pat.hir_id, local_ty);
}
qpath: &QPath<'_>,
path_span: Span,
hir_id: hir::HirId,
- ) -> (Res, Ty<'tcx>) {
+ ) -> (Res, RawTy<'tcx>) {
match *qpath {
QPath::Resolved(ref maybe_qself, ref path) => {
- let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
+ let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself).raw);
let ty = <dyn AstConv<'_>>::res_to_ty(self, self_ty, path, true);
- (path.res, ty)
+ (path.res, self.handle_raw_ty(path_span, ty))
}
QPath::TypeRelative(ref qself, ref segment) => {
let ty = self.to_ty(qself);
let result = <dyn AstConv<'_>>::associated_path_to_ty(
- self, hir_id, path_span, ty, qself, segment, true,
+ self, hir_id, path_span, ty.raw, qself, segment, true,
);
let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
+ let ty = self.handle_raw_ty(path_span, ty);
let result = result.map(|(_, kind, def_id)| (kind, def_id));
// Write back the new resolution.
(result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty)
}
QPath::LangItem(lang_item, span, id) => {
- self.resolve_lang_item_path(lang_item, span, hir_id, id)
+ let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id, id);
+ (res, self.handle_raw_ty(path_span, ty))
}
}
}
// even if their `ObligationCauseCode` isn't an `Expr*Obligation` kind.
// This is important since if we adjust one span but not the other, then
// we will have "duplicated" the error on the UI side.
- let mut remap_cause = FxHashSet::default();
+ let mut remap_cause = FxIndexSet::default();
let mut not_adjusted = vec![];
for error in errors {
}
}
+ // Adjust any other errors that come from other cause codes, when these
+ // errors are of the same predicate as one we successfully adjusted, and
+ // when their spans overlap (suggesting they're due to the same root cause).
+ //
+ // This is because due to normalization, we often register duplicate
+ // obligations with misc obligations that are basically impossible to
+ // line back up with a useful ExprBindingObligation.
for error in not_adjusted {
for (span, predicate, cause) in &remap_cause {
if *predicate == error.obligation.predicate
hir_id: call_hir_id,
span: call_span,
..
- }) = hir.get(hir.get_parent_node(expr.hir_id))
+ }) = hir.get_parent(expr.hir_id)
&& callee.hir_id == expr.hir_id
{
if self.closure_span_overlaps_error(error, *call_span) {
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, Const, Ty, TyCtxt};
+use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitable};
use rustc_session::Session;
use rustc_span::symbol::Ident;
use rustc_span::{self, Span};
self.tcx().mk_projection(item_def_id, item_substs)
}
- fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
- if ty.has_escaping_bound_vars() {
- ty // FIXME: normalization and escaping regions
- } else {
- self.normalize(span, ty)
+ fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
+ match ty.kind() {
+ ty::Adt(adt_def, _) => Some(*adt_def),
+ // FIXME(#104767): Should we handle bound regions here?
+ ty::Alias(ty::Projection, _) if !ty.has_escaping_bound_vars() => {
+ self.normalize(span, ty).ty_adt_def()
+ }
+ _ => None,
}
}
self.infcx.set_tainted_by_errors(e)
}
- fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) {
+ fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
+ // FIXME: normalization and escaping regions
+ let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty };
self.write_ty(hir_id, ty)
}
}
+
+/// Represents a user-provided type in the raw form (never normalized).
+///
+/// This is a bridge between the interface of `AstConv`, which outputs a raw `Ty`,
+/// and the API in this module, which expect `Ty` to be fully normalized.
+#[derive(Clone, Copy, Debug)]
+pub struct RawTy<'tcx> {
+ pub raw: Ty<'tcx>,
+
+ /// The normalized form of `raw`, stored here for efficiency.
+ pub normalized: Ty<'tcx>,
+}
TypeVisitable,
};
use rustc_session::errors::ExprParenthesesNeeded;
+use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
self.typeck_results
.borrow()
.liberated_fn_sigs()
- .get(self.tcx.hir().get_parent_node(self.body_id))
+ .get(self.tcx.hir().parent_id(self.body_id))
.copied()
}
// Check if the parent expression is a call to Pin::new. If it
// is and we were expecting a Box, ergo Pin<Box<expected>>, we
// can suggest Box::pin.
- let parent = self.tcx.hir().get_parent_node(expr.hir_id);
+ let parent = self.tcx.hir().parent_id(expr.hir_id);
let Some(Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. })) = self.tcx.hir().find(parent) else {
return false;
};
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
) -> bool {
- let sp = self.tcx.sess.source_map().start_point(expr.span);
+ let sp = self.tcx.sess.source_map().start_point(expr.span).with_parent(None);
if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
}
}
+ pub(crate) fn suggest_clone_for_ref(
+ &self,
+ diag: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ expr_ty: Ty<'tcx>,
+ expected_ty: Ty<'tcx>,
+ ) -> bool {
+ if let ty::Ref(_, inner_ty, hir::Mutability::Not) = expr_ty.kind()
+ && let Some(clone_trait_def) = self.tcx.lang_items().clone_trait()
+ && expected_ty == *inner_ty
+ && self
+ .infcx
+ .type_implements_trait(
+ clone_trait_def,
+ [self.tcx.erase_regions(expected_ty)],
+ self.param_env
+ )
+ .must_apply_modulo_regions()
+ {
+ diag.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ "consider using clone here",
+ ".clone()",
+ Applicability::MachineApplicable,
+ );
+ return true;
+ }
+ false
+ }
+
pub(crate) fn suggest_copied_or_cloned(
&self,
diag: &mut Diagnostic,
);
true
}
+ ExprKind::Lit(Spanned {
+ node: rustc_ast::LitKind::Int(lit, rustc_ast::LitIntType::Unsuffixed),
+ span,
+ }) => {
+ let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) else { return false; };
+ if !(snippet.starts_with("0x") || snippet.starts_with("0X")) {
+ return false;
+ }
+ if snippet.len() <= 5 || !snippet.is_char_boundary(snippet.len() - 3) {
+ return false;
+ }
+ let (_, suffix) = snippet.split_at(snippet.len() - 3);
+ let value = match suffix {
+ "f32" => (lit - 0xf32) / (16 * 16 * 16),
+ "f64" => (lit - 0xf64) / (16 * 16 * 16),
+ _ => return false,
+ };
+ err.span_suggestions(
+ expr.span,
+ "rewrite this as a decimal floating point literal, or use `as` to turn a hex literal into a float",
+ [format!("0x{value:X} as {suffix}"), format!("{value}_{suffix}")],
+ Applicability::MaybeIncorrect,
+ );
+ true
+ }
_ => false,
}
}
Some(ref ty) => {
let o_ty = self.fcx.to_ty(&ty);
- let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty));
+ let c_ty =
+ self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty.raw));
debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty);
self.fcx
.typeck_results
.user_provided_types_mut()
.insert(ty.hir_id, c_ty);
- Some(LocalTy { decl_ty: o_ty, revealed_ty: o_ty })
+ Some(LocalTy { decl_ty: o_ty.normalized, revealed_ty: o_ty.normalized })
}
None => None,
};
diag_expr_id: HirId,
) {
let hir = self.tcx.hir();
- let parent = match hir.find_parent_node(place_with_id.hir_id) {
+ let parent = match hir.opt_parent_id(place_with_id.hir_id) {
Some(parent) => parent,
None => place_with_id.hir_id,
};
_ => None,
})
.unwrap_or_else(|| match tcx.hir().get(id) {
- Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
+ Node::AnonConst(_) => match tcx.hir().get(tcx.hir().parent_id(id)) {
Node::Expr(&hir::Expr {
kind: hir::ExprKind::ConstBlock(ref anon_const),
..
}),
Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
| Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
- let operand_ty = asm
- .operands
- .iter()
- .filter_map(|(op, _op_sp)| match op {
+ let operand_ty =
+ asm.operands.iter().find_map(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const }
if anon_const.hir_id == id =>
{
}))
}
_ => None,
- })
- .next();
+ });
operand_ty.unwrap_or_else(fallback)
}
_ => fallback(),
fcx.resolve_generator_interiors(def_id.to_def_id());
for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
- let ty = fcx.normalize_ty(span, ty);
+ let ty = fcx.normalize(span, ty);
fcx.require_type_is_sized(ty, span, code);
}
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{self, SubstsRef};
use rustc_middle::ty::{self, GenericParamDefKind, Ty};
-use rustc_span::Span;
+use rustc_middle::ty::{InternalSubsts, UserSubsts, UserType};
+use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::traits;
use std::iter;
.into()
}
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
- self.cfcx.to_ty(ty).into()
+ self.cfcx.to_ty(ty).raw.into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
self.cfcx.const_arg_to_const(&ct.value, param.def_id).into()
self.cfcx.var_for_def(self.cfcx.span, param)
}
}
- <dyn AstConv<'_>>::create_substs_for_generic_args(
+
+ let substs = <dyn AstConv<'_>>::create_substs_for_generic_args(
self.tcx,
pick.item.def_id,
parent_substs,
None,
&arg_count_correct,
&mut MethodSubstsCtxt { cfcx: self, pick, seg },
- )
+ );
+
+ // When the method is confirmed, the `substs` includes
+ // parameters from not just the method, but also the impl of
+ // the method -- in particular, the `Self` type will be fully
+ // resolved. However, those are not something that the "user
+ // specified" -- i.e., those types come from the inferred type
+ // of the receiver, not something the user wrote. So when we
+ // create the user-substs, we want to replace those earlier
+ // types with just the types that the user actually wrote --
+ // that is, those that appear on the *method itself*.
+ //
+ // As an example, if the user wrote something like
+ // `foo.bar::<u32>(...)` -- the `Self` type here will be the
+ // type of `foo` (possibly adjusted), but we don't want to
+ // include that. We want just the `[_, u32]` part.
+ if !substs.is_empty() && !generics.params.is_empty() {
+ let user_type_annotation = self.probe(|_| {
+ let user_substs = UserSubsts {
+ substs: InternalSubsts::for_item(self.tcx, pick.item.def_id, |param, _| {
+ let i = param.index as usize;
+ if i < generics.parent_count {
+ self.fcx.var_for_def(DUMMY_SP, param)
+ } else {
+ substs[i]
+ }
+ }),
+ user_self_ty: None, // not relevant here
+ };
+
+ self.fcx.canonicalize_user_type_annotation(UserType::TypeOf(
+ pick.item.def_id,
+ user_substs,
+ ))
+ });
+
+ debug!("instantiate_method_substs: user_type_annotation={:?}", user_type_annotation);
+ self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation);
+ }
+
+ self.normalize(self.span, substs)
}
fn unify_receivers(
pub use self::MethodError::*;
use crate::errors::OpMethodGenericParams;
-use crate::{Expectation, FnCtxt};
+use crate::FnCtxt;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
PrivateMatch(DefKind, DefId, Vec<DefId>),
// Found a `Self: Sized` bound where `Self` is a trait object.
- IllegalSizedBound(Vec<DefId>, bool, Span),
+ IllegalSizedBound {
+ candidates: Vec<DefId>,
+ needs_mut: bool,
+ bound_span: Span,
+ self_expr: &'tcx hir::Expr<'tcx>,
+ },
// Found a match, but the return type is wrong
BadReturnType,
Err(NoMatch(..)) => false,
Err(Ambiguity(..)) => true,
Err(PrivateMatch(..)) => allow_private,
- Err(IllegalSizedBound(..)) => true,
+ Err(IllegalSizedBound { .. }) => true,
Err(BadReturnType) => bug!("no return type expectations but got BadReturnType"),
}
}
_ => Vec::new(),
};
- return Err(IllegalSizedBound(candidates, needs_mut, span));
+ return Err(IllegalSizedBound { candidates, needs_mut, bound_span: span, self_expr });
}
Ok(result.callee)
pub(super) fn obligation_for_method(
&self,
- span: Span,
+ cause: ObligationCause<'tcx>,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
}
}
}
- self.var_for_def(span, param)
+ self.var_for_def(cause.span, param)
});
let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
- (
- traits::Obligation::misc(
- self.tcx,
- span,
- self.body_id,
- self.param_env,
- poly_trait_ref.without_const(),
- ),
- substs,
- )
- }
-
- pub(super) fn obligation_for_op_method(
- &self,
- span: Span,
- trait_def_id: DefId,
- self_ty: Ty<'tcx>,
- opt_input_type: Option<Ty<'tcx>>,
- opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
- expected: Expectation<'tcx>,
- ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>)
- {
- // Construct a trait-reference `self_ty : Trait<input_tys>`
- let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
- match param.kind {
- GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {}
- GenericParamDefKind::Type { .. } => {
- if param.index == 0 {
- return self_ty.into();
- } else if let Some(input_type) = opt_input_type {
- return input_type.into();
- }
- }
- }
- self.var_for_def(span, param)
- });
-
- let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
-
- // Construct an obligation
- let poly_trait_ref = ty::Binder::dummy(trait_ref);
- let output_ty = expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty));
-
(
traits::Obligation::new(
self.tcx,
- traits::ObligationCause::new(
- span,
- self.body_id,
- traits::BinOp {
- rhs_span: opt_input_expr.map(|expr| expr.span),
- is_lit: opt_input_expr
- .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
- output_ty,
- },
- ),
+ cause,
self.param_env,
- poly_trait_ref,
+ poly_trait_ref.without_const(),
),
substs,
)
/// In particular, it doesn't really do any probing: it simply constructs
/// an obligation for a particular trait with the given self type and checks
/// whether that trait is implemented.
- #[instrument(level = "debug", skip(self, span))]
+ #[instrument(level = "debug", skip(self))]
pub(super) fn lookup_method_in_trait(
&self,
- span: Span,
+ cause: ObligationCause<'tcx>,
m_name: Ident,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
let (obligation, substs) =
- self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types);
- self.construct_obligation_for_trait(
- span,
- m_name,
- trait_def_id,
- obligation,
- substs,
- None,
- false,
- )
- }
-
- pub(super) fn lookup_op_method_in_trait(
- &self,
- span: Span,
- m_name: Ident,
- trait_def_id: DefId,
- self_ty: Ty<'tcx>,
- opt_input_type: Option<Ty<'tcx>>,
- opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
- expected: Expectation<'tcx>,
- ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
- let (obligation, substs) = self.obligation_for_op_method(
- span,
- trait_def_id,
- self_ty,
- opt_input_type,
- opt_input_expr,
- expected,
- );
- self.construct_obligation_for_trait(
- span,
- m_name,
- trait_def_id,
- obligation,
- substs,
- opt_input_expr,
- true,
- )
+ self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types);
+ self.construct_obligation_for_trait(m_name, trait_def_id, obligation, substs)
}
// FIXME(#18741): it seems likely that we can consolidate some of this
// of this method is basically the same as confirmation.
fn construct_obligation_for_trait(
&self,
- span: Span,
m_name: Ident,
trait_def_id: DefId,
obligation: traits::PredicateObligation<'tcx>,
substs: &'tcx ty::List<ty::subst::GenericArg<'tcx>>,
- opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
- is_op: bool,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!(?obligation);
let tcx = self.tcx;
let Some(method_item) = self.associated_value(trait_def_id, m_name) else {
tcx.sess.delay_span_bug(
- span,
+ obligation.cause.span,
"operator trait does not have corresponding operator method",
);
return None;
// with bound regions.
let fn_sig = tcx.bound_fn_sig(def_id);
let fn_sig = fn_sig.subst(self.tcx, substs);
- let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig);
-
- let cause = if is_op {
- ObligationCause::new(
- span,
- self.body_id,
- traits::BinOp {
- rhs_span: opt_input_expr.map(|expr| expr.span),
- is_lit: opt_input_expr
- .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
- output_ty: None,
- },
- )
- } else {
- traits::ObligationCause::misc(span, self.body_id)
- };
+ let fn_sig =
+ self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);
- let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(fn_sig);
+ let InferOk { value, obligations: o } =
+ self.at(&obligation.cause, self.param_env).normalize(fn_sig);
let fn_sig = {
obligations.extend(o);
value
// any late-bound regions appearing in its bounds.
let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs);
- let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(bounds);
+ let InferOk { value, obligations: o } =
+ self.at(&obligation.cause, self.param_env).normalize(bounds);
let bounds = {
obligations.extend(o);
value
assert!(!bounds.has_escaping_bound_vars());
- let predicates_cause = cause.clone();
+ let predicates_cause = obligation.cause.clone();
obligations.extend(traits::predicates_for_generics(
move |_, _| predicates_cause.clone(),
self.param_env,
);
obligations.push(traits::Obligation::new(
tcx,
- cause,
+ obligation.cause,
self.param_env,
ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())),
));
// Find an identifier with which this trait was imported (note that `_` doesn't count).
let any_id = import_items
.iter()
- .filter_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None })
- .next();
+ .find_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None });
if let Some(any_id) = any_id {
if any_id.name == Empty {
// Glob import, so just use its name.
}
#[derive(Debug, Clone)]
-struct Candidate<'tcx> {
+pub(crate) struct Candidate<'tcx> {
// Candidates are (I'm not quite sure, but they are mostly) basically
// some metadata on top of a `ty::AssocItem` (without substs).
//
// if `T: Sized`.
xform_self_ty: Ty<'tcx>,
xform_ret_ty: Option<Ty<'tcx>>,
- item: ty::AssocItem,
- kind: CandidateKind<'tcx>,
- import_ids: SmallVec<[LocalDefId; 1]>,
+ pub(crate) item: ty::AssocItem,
+ pub(crate) kind: CandidateKind<'tcx>,
+ pub(crate) import_ids: SmallVec<[LocalDefId; 1]>,
}
#[derive(Debug, Clone)]
-enum CandidateKind<'tcx> {
+pub(crate) enum CandidateKind<'tcx> {
InherentImplCandidate(
SubstsRef<'tcx>,
// Normalize obligations
)
}
+ #[instrument(level = "debug", skip(self))]
+ pub(crate) fn probe_for_name_many(
+ &self,
+ mode: Mode,
+ item_name: Ident,
+ is_suggestion: IsSuggestion,
+ self_ty: Ty<'tcx>,
+ scope_expr_id: hir::HirId,
+ scope: ProbeScope,
+ ) -> Vec<Candidate<'tcx>> {
+ self.probe_op(
+ item_name.span,
+ mode,
+ Some(item_name),
+ None,
+ is_suggestion,
+ self_ty,
+ scope_expr_id,
+ scope,
+ |probe_cx| {
+ Ok(probe_cx
+ .inherent_candidates
+ .into_iter()
+ .chain(probe_cx.extension_candidates)
+ .collect())
+ },
+ )
+ .unwrap()
+ }
+
fn probe_op<OP, R>(
&'a self,
span: Span,
});
} else {
debug_assert!(self.tcx.is_trait(trait_def_id));
+ if self.tcx.trait_is_auto(trait_def_id) {
+ return;
+ }
for item in self.impl_or_trait_item(trait_def_id) {
// Check whether `trait_def_id` defines a method with suitable name.
if !self.has_applicable_self(&item) {
// a raw pointer
!step.self_ty.references_error() && !step.from_unsafe_deref
})
- .flat_map(|step| {
+ .find_map(|step| {
let InferOk { value: self_ty, obligations: _ } = self
.fcx
.probe_instantiate_query_response(
})
})
})
- .next()
}
/// For each type `T` in the step list, this attempts to find a method where
pub fn report_method_error(
&self,
- mut span: Span,
+ span: Span,
rcvr_ty: Ty<'tcx>,
item_name: Ident,
source: SelfSource<'tcx>,
return None;
}
- let report_candidates = |span: Span,
- err: &mut Diagnostic,
- sources: &mut Vec<CandidateSource>,
- sugg_span: Option<Span>| {
- sources.sort();
- sources.dedup();
- // Dynamic limit to avoid hiding just one candidate, which is silly.
- let limit = if sources.len() == 5 { 5 } else { 4 };
-
- for (idx, source) in sources.iter().take(limit).enumerate() {
- match *source {
- CandidateSource::Impl(impl_did) => {
- // Provide the best span we can. Use the item, if local to crate, else
- // the impl, if local to crate (item may be defaulted), else nothing.
- let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
- let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
- self.associated_value(impl_trait_ref.def_id, item_name)
- }) else {
- continue;
- };
-
- let note_span = if item.def_id.is_local() {
- Some(self.tcx.def_span(item.def_id))
- } else if impl_did.is_local() {
- Some(self.tcx.def_span(impl_did))
- } else {
- None
- };
-
- let impl_ty = self.tcx.at(span).type_of(impl_did);
-
- let insertion = match self.tcx.impl_trait_ref(impl_did) {
- None => String::new(),
- Some(trait_ref) => format!(
- " of the trait `{}`",
- self.tcx.def_path_str(trait_ref.def_id)
- ),
- };
-
- let (note_str, idx) = if sources.len() > 1 {
- (
- format!(
- "candidate #{} is defined in an impl{} for the type `{}`",
- idx + 1,
- insertion,
- impl_ty,
- ),
- Some(idx + 1),
- )
- } else {
- (
- format!(
- "the candidate is defined in an impl{} for the type `{}`",
- insertion, impl_ty,
- ),
- None,
- )
- };
- if let Some(note_span) = note_span {
- // We have a span pointing to the method. Show note with snippet.
- err.span_note(note_span, ¬e_str);
- } else {
- err.note(¬e_str);
- }
- if let Some(sugg_span) = sugg_span
- && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
- let path = self.tcx.def_path_str(trait_ref.def_id);
-
- let ty = match item.kind {
- ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
- ty::AssocKind::Fn => self
- .tcx
- .fn_sig(item.def_id)
- .inputs()
- .skip_binder()
- .get(0)
- .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
- .copied()
- .unwrap_or(rcvr_ty),
- };
- print_disambiguation_help(
- item_name,
- args,
- err,
- path,
- ty,
- item.kind,
- item.def_id,
- sugg_span,
- idx,
- self.tcx.sess.source_map(),
- item.fn_has_self_parameter,
- );
- }
- }
- CandidateSource::Trait(trait_did) => {
- let Some(item) = self.associated_value(trait_did, item_name) else { continue };
- let item_span = self.tcx.def_span(item.def_id);
- let idx = if sources.len() > 1 {
- let msg = &format!(
- "candidate #{} is defined in the trait `{}`",
- idx + 1,
- self.tcx.def_path_str(trait_did)
- );
- err.span_note(item_span, msg);
- Some(idx + 1)
- } else {
- let msg = &format!(
- "the candidate is defined in the trait `{}`",
- self.tcx.def_path_str(trait_did)
- );
- err.span_note(item_span, msg);
- None
- };
- if let Some(sugg_span) = sugg_span {
- let path = self.tcx.def_path_str(trait_did);
- print_disambiguation_help(
- item_name,
- args,
- err,
- path,
- rcvr_ty,
- item.kind,
- item.def_id,
- sugg_span,
- idx,
- self.tcx.sess.source_map(),
- item.fn_has_self_parameter,
- );
- }
- }
- }
- }
- if sources.len() > limit {
- err.note(&format!("and {} others", sources.len() - limit));
- }
- };
-
let sugg_span = if let SelfSource::MethodCall(expr) = source {
// Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
- self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span
+ self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id)).span
} else {
span
};
match error {
- MethodError::NoMatch(NoMatchData {
- mut static_candidates,
- unsatisfied_predicates,
- out_of_scope_traits,
- lev_candidate,
- mode,
- }) => {
- let tcx = self.tcx;
-
- let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
- let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
- let is_method = mode == Mode::MethodCall;
- let item_kind = if is_method {
- "method"
- } else if rcvr_ty.is_enum() {
- "variant or associated item"
- } else {
- match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
- (Some(name), false) if name.is_lowercase() => "function or associated item",
- (Some(_), false) => "associated item",
- (Some(_), true) | (None, false) => "variant or associated item",
- (None, true) => "variant",
- }
- };
-
- if self.suggest_wrapping_range_with_parens(
- tcx, rcvr_ty, source, span, item_name, &ty_str,
- ) || self.suggest_constraining_numerical_ty(
- tcx, rcvr_ty, source, span, item_kind, item_name, &ty_str,
- ) {
- return None;
- }
- span = item_name.span;
-
- // Don't show generic arguments when the method can't be found in any implementation (#81576).
- let mut ty_str_reported = ty_str.clone();
- if let ty::Adt(_, generics) = rcvr_ty.kind() {
- if generics.len() > 0 {
- let mut autoderef = self.autoderef(span, rcvr_ty);
- let candidate_found = autoderef.any(|(ty, _)| {
- if let ty::Adt(adt_def, _) = ty.kind() {
- self.tcx
- .inherent_impls(adt_def.did())
- .iter()
- .filter_map(|def_id| self.associated_value(*def_id, item_name))
- .count()
- >= 1
- } else {
- false
- }
- });
- let has_deref = autoderef.step_count() > 0;
- if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
- if let Some((path_string, _)) = ty_str.split_once('<') {
- ty_str_reported = path_string.to_string();
- }
- }
- }
- }
-
- let mut err = struct_span_err!(
- tcx.sess,
+ MethodError::NoMatch(mut no_match_data) => {
+ return self.report_no_match_method_error(
span,
- E0599,
- "no {} named `{}` found for {} `{}` in the current scope",
- item_kind,
+ rcvr_ty,
item_name,
- rcvr_ty.prefix_string(self.tcx),
- ty_str_reported,
+ source,
+ args,
+ sugg_span,
+ &mut no_match_data,
);
- if rcvr_ty.references_error() {
- err.downgrade_to_delayed_bug();
- }
-
- if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
- self.suggest_await_before_method(
- &mut err, item_name, rcvr_ty, cal, span,
- );
- }
- if let Some(span) = tcx.resolutions(()).confused_type_with_std_module.get(&span) {
- err.span_suggestion(
- span.shrink_to_lo(),
- "you are looking for the module in `std`, not the primitive type",
- "std::",
- Applicability::MachineApplicable,
- );
- }
- if let ty::RawPtr(_) = &rcvr_ty.kind() {
- err.note(
- "try using `<*const T>::as_ref()` to get a reference to the \
- type behind the pointer: https://doc.rust-lang.org/std/\
- primitive.pointer.html#method.as_ref",
- );
- err.note(
- "using `<*const T>::as_ref()` on a pointer which is unaligned or points \
- to invalid or uninitialized memory is undefined behavior",
- );
- }
-
- let ty_span = match rcvr_ty.kind() {
- ty::Param(param_type) => Some(
- param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()),
- ),
- ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
- _ => None,
- };
- if let Some(span) = ty_span {
- err.span_label(
- span,
- format!(
- "{item_kind} `{item_name}` not found for this {}",
- rcvr_ty.prefix_string(self.tcx)
- ),
- );
- }
-
- if let SelfSource::MethodCall(rcvr_expr) = source {
- self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
- let call_expr = self
- .tcx
- .hir()
- .expect_expr(self.tcx.hir().get_parent_node(rcvr_expr.hir_id));
- let probe = self.lookup_probe(
- item_name,
- output_ty,
- call_expr,
- ProbeScope::AllTraits,
- );
- probe.is_ok()
- });
- }
-
- let mut custom_span_label = false;
-
- if !static_candidates.is_empty() {
- err.note(
- "found the following associated functions; to be used as methods, \
- functions must have a `self` parameter",
- );
- err.span_label(span, "this is an associated function, not a method");
- custom_span_label = true;
- }
- if static_candidates.len() == 1 {
- self.suggest_associated_call_syntax(
- &mut err,
- &static_candidates,
- rcvr_ty,
- source,
- item_name,
- args,
- sugg_span,
- );
-
- report_candidates(span, &mut err, &mut static_candidates, None);
- } else if static_candidates.len() > 1 {
- report_candidates(span, &mut err, &mut static_candidates, Some(sugg_span));
- }
-
- let mut bound_spans = vec![];
- let mut restrict_type_params = false;
- let mut unsatisfied_bounds = false;
- if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
- let msg = "consider using `len` instead";
- if let SelfSource::MethodCall(_expr) = source {
- err.span_suggestion_short(
- span,
- msg,
- "len",
- Applicability::MachineApplicable,
- );
- } else {
- err.span_label(span, msg);
- }
- if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
- let iterator_trait = self.tcx.def_path_str(iterator_trait);
- err.note(&format!("`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"));
- }
- } else if !unsatisfied_predicates.is_empty() {
- let mut type_params = FxHashMap::default();
-
- // Pick out the list of unimplemented traits on the receiver.
- // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
- let mut unimplemented_traits = FxHashMap::default();
- let mut unimplemented_traits_only = true;
- for (predicate, _parent_pred, cause) in &unsatisfied_predicates {
- if let (ty::PredicateKind::Clause(ty::Clause::Trait(p)), Some(cause)) =
- (predicate.kind().skip_binder(), cause.as_ref())
- {
- if p.trait_ref.self_ty() != rcvr_ty {
- // This is necessary, not just to keep the errors clean, but also
- // because our derived obligations can wind up with a trait ref that
- // requires a different param_env to be correctly compared.
- continue;
- }
- unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
- predicate.kind().rebind(p.trait_ref),
- Obligation {
- cause: cause.clone(),
- param_env: self.param_env,
- predicate: *predicate,
- recursion_depth: 0,
- },
- ));
- }
- }
-
- // Make sure that, if any traits other than the found ones were involved,
- // we don't don't report an unimplemented trait.
- // We don't want to say that `iter::Cloned` is not an iterator, just
- // because of some non-Clone item being iterated over.
- for (predicate, _parent_pred, _cause) in &unsatisfied_predicates {
- match predicate.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(p))
- if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
- _ => {
- unimplemented_traits_only = false;
- break;
- }
- }
- }
-
- let mut collect_type_param_suggestions =
- |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
- // We don't care about regions here, so it's fine to skip the binder here.
- if let (ty::Param(_), ty::PredicateKind::Clause(ty::Clause::Trait(p))) =
- (self_ty.kind(), parent_pred.kind().skip_binder())
- {
- let hir = self.tcx.hir();
- let node = match p.trait_ref.self_ty().kind() {
- ty::Param(_) => {
- // Account for `fn` items like in `issue-35677.rs` to
- // suggest restricting its type params.
- let parent_body =
- hir.body_owner(hir::BodyId { hir_id: self.body_id });
- Some(hir.get(parent_body))
- }
- ty::Adt(def, _) => {
- def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
- }
- _ => None,
- };
- if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
- if let Some(g) = kind.generics() {
- let key = (
- g.tail_span_for_predicate_suggestion(),
- g.add_where_or_trailing_comma(),
- );
- type_params
- .entry(key)
- .or_insert_with(FxHashSet::default)
- .insert(obligation.to_owned());
- }
- }
- }
- };
- let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
- let msg = format!(
- "doesn't satisfy `{}`",
- if obligation.len() > 50 { quiet } else { obligation }
- );
- match &self_ty.kind() {
- // Point at the type that couldn't satisfy the bound.
- ty::Adt(def, _) => {
- bound_spans.push((self.tcx.def_span(def.did()), msg))
- }
- // Point at the trait object that couldn't satisfy the bound.
- ty::Dynamic(preds, _, _) => {
- for pred in preds.iter() {
- match pred.skip_binder() {
- ty::ExistentialPredicate::Trait(tr) => bound_spans
- .push((self.tcx.def_span(tr.def_id), msg.clone())),
- ty::ExistentialPredicate::Projection(_)
- | ty::ExistentialPredicate::AutoTrait(_) => {}
- }
- }
- }
- // Point at the closure that couldn't satisfy the bound.
- ty::Closure(def_id, _) => bound_spans.push((
- tcx.def_span(*def_id),
- format!("doesn't satisfy `{}`", quiet),
- )),
- _ => {}
- }
- };
- let mut format_pred = |pred: ty::Predicate<'tcx>| {
- let bound_predicate = pred.kind();
- match bound_predicate.skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
- let pred = bound_predicate.rebind(pred);
- // `<Foo as Iterator>::Item = String`.
- let projection_ty = pred.skip_binder().projection_ty;
-
- let substs_with_infer_self = tcx.mk_substs(
- iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
- .chain(projection_ty.substs.iter().skip(1)),
- );
-
- let quiet_projection_ty =
- tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
-
- let term = pred.skip_binder().term;
-
- let obligation = format!("{} = {}", projection_ty, term);
- let quiet = with_forced_trimmed_paths!(format!(
- "{} = {}",
- quiet_projection_ty, term
- ));
-
- bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
- Some((obligation, projection_ty.self_ty()))
- }
- ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
- let p = poly_trait_ref.trait_ref;
- let self_ty = p.self_ty();
- let path = p.print_only_trait_path();
- let obligation = format!("{}: {}", self_ty, path);
- let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
- bound_span_label(self_ty, &obligation, &quiet);
- Some((obligation, self_ty))
- }
- _ => None,
- }
- };
-
- // Find all the requirements that come from a local `impl` block.
- let mut skip_list: FxHashSet<_> = Default::default();
- let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
- for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates
- .iter()
- .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
- .filter_map(|(p, parent, c)| match c.code() {
- ObligationCauseCode::ImplDerivedObligation(data) => {
- Some((&data.derived, p, parent, data.impl_def_id, data))
- }
- _ => None,
- })
- {
- let parent_trait_ref = data.parent_trait_pred;
- let path = parent_trait_ref.print_modifiers_and_trait_path();
- let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
- let unsatisfied_msg = "unsatisfied trait bound introduced here";
- let derive_msg =
- "unsatisfied trait bound introduced in this `derive` macro";
- match self.tcx.hir().get_if_local(impl_def_id) {
- // Unmet obligation comes from a `derive` macro, point at it once to
- // avoid multiple span labels pointing at the same place.
- Some(Node::Item(hir::Item {
- kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
- ..
- })) if matches!(
- self_ty.span.ctxt().outer_expn_data().kind,
- ExpnKind::Macro(MacroKind::Derive, _)
- ) || matches!(
- of_trait.as_ref().map(|t| t
- .path
- .span
- .ctxt()
- .outer_expn_data()
- .kind),
- Some(ExpnKind::Macro(MacroKind::Derive, _))
- ) =>
- {
- let span = self_ty.span.ctxt().outer_expn_data().call_site;
- let mut spans: MultiSpan = span.into();
- spans.push_span_label(span, derive_msg);
- let entry = spanned_predicates.entry(spans);
- entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
- }
-
- // Unmet obligation coming from an `impl`.
- Some(Node::Item(hir::Item {
- kind:
- hir::ItemKind::Impl(hir::Impl {
- of_trait, self_ty, generics, ..
- }),
- span: item_span,
- ..
- })) => {
- let sized_pred =
- unsatisfied_predicates.iter().any(|(pred, _, _)| {
- match pred.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
- Some(pred.def_id())
- == self.tcx.lang_items().sized_trait()
- && pred.polarity == ty::ImplPolarity::Positive
- }
- _ => false,
- }
- });
- for param in generics.params {
- if param.span == cause.span && sized_pred {
- let (sp, sugg) = match param.colon_span {
- Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
- None => (param.span.shrink_to_hi(), ": ?Sized"),
- };
- err.span_suggestion_verbose(
- sp,
- "consider relaxing the type parameter's implicit \
- `Sized` bound",
- sugg,
- Applicability::MachineApplicable,
- );
- }
- }
- if let Some(pred) = parent_p {
- // Done to add the "doesn't satisfy" `span_label`.
- let _ = format_pred(*pred);
- }
- skip_list.insert(p);
- let mut spans = if cause.span != *item_span {
- let mut spans: MultiSpan = cause.span.into();
- spans.push_span_label(cause.span, unsatisfied_msg);
- spans
- } else {
- let mut spans = Vec::with_capacity(2);
- if let Some(trait_ref) = of_trait {
- spans.push(trait_ref.path.span);
- }
- spans.push(self_ty.span);
- spans.into()
- };
- if let Some(trait_ref) = of_trait {
- spans.push_span_label(trait_ref.path.span, "");
- }
- spans.push_span_label(self_ty.span, "");
-
- let entry = spanned_predicates.entry(spans);
- entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
- }
- Some(Node::Item(hir::Item {
- kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
- span: item_span,
- ..
- })) => {
- tcx.sess.delay_span_bug(
- *item_span,
- "auto trait is invoked with no method error, but no error reported?",
- );
- }
- Some(_) => unreachable!(),
- None => (),
- }
- }
- let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
- spanned_predicates.sort_by_key(|(span, (_, _, _))| span.primary_span());
- for (span, (_path, _self_ty, preds)) in spanned_predicates {
- let mut preds: Vec<_> = preds
- .into_iter()
- .filter_map(|pred| format_pred(*pred))
- .map(|(p, _)| format!("`{}`", p))
- .collect();
- preds.sort();
- preds.dedup();
- let msg = if let [pred] = &preds[..] {
- format!("trait bound {} was not satisfied", pred)
- } else {
- format!(
- "the following trait bounds were not satisfied:\n{}",
- preds.join("\n"),
- )
- };
- err.span_note(span, &msg);
- unsatisfied_bounds = true;
- }
-
- // The requirements that didn't have an `impl` span to show.
- let mut bound_list = unsatisfied_predicates
- .iter()
- .filter_map(|(pred, parent_pred, _cause)| {
- format_pred(*pred).map(|(p, self_ty)| {
- collect_type_param_suggestions(self_ty, *pred, &p);
- (
- match parent_pred {
- None => format!("`{}`", &p),
- Some(parent_pred) => match format_pred(*parent_pred) {
- None => format!("`{}`", &p),
- Some((parent_p, _)) => {
- collect_type_param_suggestions(
- self_ty,
- *parent_pred,
- &p,
- );
- format!(
- "`{}`\nwhich is required by `{}`",
- p, parent_p
- )
- }
- },
- },
- *pred,
- )
- })
- })
- .filter(|(_, pred)| !skip_list.contains(&pred))
- .map(|(t, _)| t)
- .enumerate()
- .collect::<Vec<(usize, String)>>();
-
- for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
- restrict_type_params = true;
- // #74886: Sort here so that the output is always the same.
- let mut obligations = obligations.into_iter().collect::<Vec<_>>();
- obligations.sort();
- err.span_suggestion_verbose(
- span,
- &format!(
- "consider restricting the type parameter{s} to satisfy the \
- trait bound{s}",
- s = pluralize!(obligations.len())
- ),
- format!("{} {}", add_where_or_comma, obligations.join(", ")),
- Applicability::MaybeIncorrect,
- );
- }
-
- bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
- bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
- bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
-
- if !bound_list.is_empty() || !skip_list.is_empty() {
- let bound_list = bound_list
- .into_iter()
- .map(|(_, path)| path)
- .collect::<Vec<_>>()
- .join("\n");
- let actual_prefix = rcvr_ty.prefix_string(self.tcx);
- info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
- let (primary_message, label) =
- if unimplemented_traits.len() == 1 && unimplemented_traits_only {
- unimplemented_traits
- .into_iter()
- .next()
- .map(|(_, (trait_ref, obligation))| {
- if trait_ref.self_ty().references_error()
- || rcvr_ty.references_error()
- {
- // Avoid crashing.
- return (None, None);
- }
- let OnUnimplementedNote { message, label, .. } = self
- .err_ctxt()
- .on_unimplemented_note(trait_ref, &obligation);
- (message, label)
- })
- .unwrap()
- } else {
- (None, None)
- };
- let primary_message = primary_message.unwrap_or_else(|| format!(
- "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
- but its trait bounds were not satisfied"
- ));
- err.set_primary_message(&primary_message);
- if let Some(label) = label {
- custom_span_label = true;
- err.span_label(span, label);
- }
- if !bound_list.is_empty() {
- err.note(&format!(
- "the following trait bounds were not satisfied:\n{bound_list}"
- ));
- }
- self.suggest_derive(&mut err, &unsatisfied_predicates);
-
- unsatisfied_bounds = true;
- }
- }
-
- let label_span_not_found = |err: &mut Diagnostic| {
- if unsatisfied_predicates.is_empty() {
- err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
- let is_string_or_ref_str = match rcvr_ty.kind() {
- ty::Ref(_, ty, _) => {
- ty.is_str()
- || matches!(
- ty.kind(),
- ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string()
- )
- }
- ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(),
- _ => false,
- };
- if is_string_or_ref_str && item_name.name == sym::iter {
- err.span_suggestion_verbose(
- item_name.span,
- "because of the in-memory representation of `&str`, to obtain \
- an `Iterator` over each of its codepoint use method `chars`",
- "chars",
- Applicability::MachineApplicable,
- );
- }
- if let ty::Adt(adt, _) = rcvr_ty.kind() {
- let mut inherent_impls_candidate = self
- .tcx
- .inherent_impls(adt.did())
- .iter()
- .copied()
- .filter(|def_id| {
- if let Some(assoc) = self.associated_value(*def_id, item_name) {
- // Check for both mode is the same so we avoid suggesting
- // incorrect associated item.
- match (mode, assoc.fn_has_self_parameter, source) {
- (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
- // We check that the suggest type is actually
- // different from the received one
- // So we avoid suggestion method with Box<Self>
- // for instance
- self.tcx.at(span).type_of(*def_id) != rcvr_ty
- && self.tcx.at(span).type_of(*def_id) != rcvr_ty
- }
- (Mode::Path, false, _) => true,
- _ => false,
- }
- } else {
- false
- }
- })
- .collect::<Vec<_>>();
- if !inherent_impls_candidate.is_empty() {
- inherent_impls_candidate.sort();
- inherent_impls_candidate.dedup();
-
- // number of type to shows at most.
- let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
- let type_candidates = inherent_impls_candidate
- .iter()
- .take(limit)
- .map(|impl_item| {
- format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
- })
- .collect::<Vec<_>>()
- .join("\n");
- let additional_types = if inherent_impls_candidate.len() > limit {
- format!(
- "\nand {} more types",
- inherent_impls_candidate.len() - limit
- )
- } else {
- "".to_string()
- };
- err.note(&format!(
- "the {item_kind} was found for\n{}{}",
- type_candidates, additional_types
- ));
- }
- }
- } else {
- let ty_str = if ty_str.len() > 50 {
- String::new()
- } else {
- format!("on `{ty_str}` ")
- };
- err.span_label(span, format!(
- "{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds"
- ));
- }
- };
-
- // If the method name is the name of a field with a function or closure type,
- // give a helping note that it has to be called as `(x.f)(...)`.
- if let SelfSource::MethodCall(expr) = source {
- if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
- && lev_candidate.is_none()
- && !custom_span_label
- {
- label_span_not_found(&mut err);
- }
- } else if !custom_span_label {
- label_span_not_found(&mut err);
- }
-
- // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
- // can't be called due to `typeof(expr): Clone` not holding.
- if unsatisfied_predicates.is_empty() {
- self.suggest_calling_method_on_field(
- &mut err, source, span, rcvr_ty, item_name,
- );
- }
-
- self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
-
- bound_spans.sort();
- bound_spans.dedup();
- for (span, msg) in bound_spans.into_iter() {
- err.span_label(span, &msg);
- }
-
- if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
- } else {
- self.suggest_traits_to_import(
- &mut err,
- span,
- rcvr_ty,
- item_name,
- args.map(|(_, args)| args.len() + 1),
- source,
- out_of_scope_traits,
- &unsatisfied_predicates,
- &static_candidates,
- unsatisfied_bounds,
- );
- }
-
- // Don't emit a suggestion if we found an actual method
- // that had unsatisfied trait bounds
- if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
- let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
- if let Some(suggestion) = lev_distance::find_best_match_for_name(
- &adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
- item_name.name,
- None,
- ) {
- err.span_suggestion(
- span,
- "there is a variant with a similar name",
- suggestion,
- Applicability::MaybeIncorrect,
- );
- }
- }
-
- if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
- let msg = "remove this method call";
- let mut fallback_span = true;
- if let SelfSource::MethodCall(expr) = source {
- let call_expr =
- self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
- if let Some(span) = call_expr.span.trim_start(expr.span) {
- err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
- fallback_span = false;
- }
- }
- if fallback_span {
- err.span_label(span, msg);
- }
- } else if let Some(lev_candidate) = lev_candidate {
- // Don't emit a suggestion if we found an actual method
- // that had unsatisfied trait bounds
- if unsatisfied_predicates.is_empty() {
- let def_kind = lev_candidate.kind.as_def_kind();
- // Methods are defined within the context of a struct and their first parameter is always self,
- // which represents the instance of the struct the method is being called on
- // Associated functions don’t take self as a parameter and
- // they are not methods because they don’t have an instance of the struct to work with.
- if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
- err.span_suggestion(
- span,
- "there is a method with a similar name",
- lev_candidate.name,
- Applicability::MaybeIncorrect,
- );
- } else {
- err.span_suggestion(
- span,
- &format!(
- "there is {} {} with a similar name",
- def_kind.article(),
- def_kind.descr(lev_candidate.def_id),
- ),
- lev_candidate.name,
- Applicability::MaybeIncorrect,
- );
- }
- }
- }
-
- self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
-
- return Some(err);
}
MethodError::Ambiguity(mut sources) => {
);
err.span_label(item_name.span, format!("multiple `{}` found", item_name));
- report_candidates(span, &mut err, &mut sources, Some(sugg_span));
+ self.note_candidates_on_method_error(
+ rcvr_ty,
+ item_name,
+ args,
+ span,
+ &mut err,
+ &mut sources,
+ Some(sugg_span),
+ );
err.emit();
}
err.emit();
}
- MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
- let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
+ MethodError::IllegalSizedBound { candidates, needs_mut, bound_span, self_expr } => {
+ let msg = if needs_mut {
+ with_forced_trimmed_paths!(format!(
+ "the `{item_name}` method cannot be invoked on `{rcvr_ty}`"
+ ))
+ } else {
+ format!("the `{item_name}` method cannot be invoked on a trait object")
+ };
let mut err = self.sess().struct_span_err(span, &msg);
- err.span_label(bound_span, "this has a `Sized` requirement");
+ if !needs_mut {
+ err.span_label(bound_span, "this has a `Sized` requirement");
+ }
if !candidates.is_empty() {
let help = format!(
"{an}other candidate{s} {were} found in the following trait{s}, perhaps \
*region,
ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
);
- err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
+ let msg = format!("you need `{}` instead of `{}`", trait_type, rcvr_ty);
+ let mut kind = &self_expr.kind;
+ while let hir::ExprKind::AddrOf(_, _, expr)
+ | hir::ExprKind::Unary(hir::UnOp::Deref, expr) = kind
+ {
+ kind = &expr.kind;
+ }
+ if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind
+ && let hir::def::Res::Local(hir_id) = path.res
+ && let Some(hir::Node::Pat(b)) = self.tcx.hir().find(hir_id)
+ && let Some(hir::Node::Param(p)) = self.tcx.hir().find_parent(b.hir_id)
+ && let Some(node) = self.tcx.hir().find_parent(p.hir_id)
+ && let Some(decl) = node.fn_decl()
+ && let Some(ty) = decl.inputs.iter().find(|ty| ty.span == p.ty_span)
+ && let hir::TyKind::Ref(_, mut_ty) = &ty.kind
+ && let hir::Mutability::Not = mut_ty.mutbl
+ {
+ err.span_suggestion_verbose(
+ mut_ty.ty.span.shrink_to_lo(),
+ &msg,
+ "mut ",
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.help(&msg);
+ }
}
}
err.emit();
None
}
+ pub fn report_no_match_method_error(
+ &self,
+ mut span: Span,
+ rcvr_ty: Ty<'tcx>,
+ item_name: Ident,
+ source: SelfSource<'tcx>,
+ args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+ sugg_span: Span,
+ no_match_data: &mut NoMatchData<'tcx>,
+ ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
+ let mode = no_match_data.mode;
+ let tcx = self.tcx;
+ let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
+ let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
+ let is_method = mode == Mode::MethodCall;
+ let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
+ let lev_candidate = no_match_data.lev_candidate;
+ let item_kind = if is_method {
+ "method"
+ } else if rcvr_ty.is_enum() {
+ "variant or associated item"
+ } else {
+ match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
+ (Some(name), false) if name.is_lowercase() => "function or associated item",
+ (Some(_), false) => "associated item",
+ (Some(_), true) | (None, false) => "variant or associated item",
+ (None, true) => "variant",
+ }
+ };
+
+ if self.suggest_wrapping_range_with_parens(tcx, rcvr_ty, source, span, item_name, &ty_str)
+ || self.suggest_constraining_numerical_ty(
+ tcx, rcvr_ty, source, span, item_kind, item_name, &ty_str,
+ )
+ {
+ return None;
+ }
+ span = item_name.span;
+
+ // Don't show generic arguments when the method can't be found in any implementation (#81576).
+ let mut ty_str_reported = ty_str.clone();
+ if let ty::Adt(_, generics) = rcvr_ty.kind() {
+ if generics.len() > 0 {
+ let mut autoderef = self.autoderef(span, rcvr_ty);
+ let candidate_found = autoderef.any(|(ty, _)| {
+ if let ty::Adt(adt_def, _) = ty.kind() {
+ self.tcx
+ .inherent_impls(adt_def.did())
+ .iter()
+ .any(|def_id| self.associated_value(*def_id, item_name).is_some())
+ } else {
+ false
+ }
+ });
+ let has_deref = autoderef.step_count() > 0;
+ if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
+ if let Some((path_string, _)) = ty_str.split_once('<') {
+ ty_str_reported = path_string.to_string();
+ }
+ }
+ }
+ }
+
+ let mut err = struct_span_err!(
+ tcx.sess,
+ span,
+ E0599,
+ "no {} named `{}` found for {} `{}` in the current scope",
+ item_kind,
+ item_name,
+ rcvr_ty.prefix_string(self.tcx),
+ ty_str_reported,
+ );
+ if rcvr_ty.references_error() {
+ err.downgrade_to_delayed_bug();
+ }
+
+ if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
+ self.suggest_await_before_method(
+ &mut err, item_name, rcvr_ty, cal, span,
+ );
+ }
+ if let Some(span) =
+ tcx.resolutions(()).confused_type_with_std_module.get(&span.with_parent(None))
+ {
+ err.span_suggestion(
+ span.shrink_to_lo(),
+ "you are looking for the module in `std`, not the primitive type",
+ "std::",
+ Applicability::MachineApplicable,
+ );
+ }
+ if let ty::RawPtr(_) = &rcvr_ty.kind() {
+ err.note(
+ "try using `<*const T>::as_ref()` to get a reference to the \
+ type behind the pointer: https://doc.rust-lang.org/std/\
+ primitive.pointer.html#method.as_ref",
+ );
+ err.note(
+ "using `<*const T>::as_ref()` on a pointer which is unaligned or points \
+ to invalid or uninitialized memory is undefined behavior",
+ );
+ }
+
+ let ty_span = match rcvr_ty.kind() {
+ ty::Param(param_type) => {
+ Some(param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()))
+ }
+ ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
+ _ => None,
+ };
+ if let Some(span) = ty_span {
+ err.span_label(
+ span,
+ format!(
+ "{item_kind} `{item_name}` not found for this {}",
+ rcvr_ty.prefix_string(self.tcx)
+ ),
+ );
+ }
+
+ if let SelfSource::MethodCall(rcvr_expr) = source {
+ self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
+ let call_expr =
+ self.tcx.hir().expect_expr(self.tcx.hir().parent_id(rcvr_expr.hir_id));
+ let probe =
+ self.lookup_probe(item_name, output_ty, call_expr, ProbeScope::AllTraits);
+ probe.is_ok()
+ });
+ }
+
+ let mut custom_span_label = false;
+
+ let static_candidates = &mut no_match_data.static_candidates;
+ if !static_candidates.is_empty() {
+ err.note(
+ "found the following associated functions; to be used as methods, \
+ functions must have a `self` parameter",
+ );
+ err.span_label(span, "this is an associated function, not a method");
+ custom_span_label = true;
+ }
+ if static_candidates.len() == 1 {
+ self.suggest_associated_call_syntax(
+ &mut err,
+ &static_candidates,
+ rcvr_ty,
+ source,
+ item_name,
+ args,
+ sugg_span,
+ );
+
+ self.note_candidates_on_method_error(
+ rcvr_ty,
+ item_name,
+ args,
+ span,
+ &mut err,
+ static_candidates,
+ None,
+ );
+ } else if static_candidates.len() > 1 {
+ self.note_candidates_on_method_error(
+ rcvr_ty,
+ item_name,
+ args,
+ span,
+ &mut err,
+ static_candidates,
+ Some(sugg_span),
+ );
+ }
+
+ let mut bound_spans = vec![];
+ let mut restrict_type_params = false;
+ let mut unsatisfied_bounds = false;
+ if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
+ let msg = "consider using `len` instead";
+ if let SelfSource::MethodCall(_expr) = source {
+ err.span_suggestion_short(span, msg, "len", Applicability::MachineApplicable);
+ } else {
+ err.span_label(span, msg);
+ }
+ if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
+ let iterator_trait = self.tcx.def_path_str(iterator_trait);
+ err.note(&format!(
+ "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
+ ));
+ }
+ } else if !unsatisfied_predicates.is_empty() {
+ let mut type_params = FxHashMap::default();
+
+ // Pick out the list of unimplemented traits on the receiver.
+ // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
+ let mut unimplemented_traits = FxHashMap::default();
+ let mut unimplemented_traits_only = true;
+ for (predicate, _parent_pred, cause) in unsatisfied_predicates {
+ if let (ty::PredicateKind::Clause(ty::Clause::Trait(p)), Some(cause)) =
+ (predicate.kind().skip_binder(), cause.as_ref())
+ {
+ if p.trait_ref.self_ty() != rcvr_ty {
+ // This is necessary, not just to keep the errors clean, but also
+ // because our derived obligations can wind up with a trait ref that
+ // requires a different param_env to be correctly compared.
+ continue;
+ }
+ unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
+ predicate.kind().rebind(p.trait_ref),
+ Obligation {
+ cause: cause.clone(),
+ param_env: self.param_env,
+ predicate: *predicate,
+ recursion_depth: 0,
+ },
+ ));
+ }
+ }
+
+ // Make sure that, if any traits other than the found ones were involved,
+ // we don't don't report an unimplemented trait.
+ // We don't want to say that `iter::Cloned` is not an iterator, just
+ // because of some non-Clone item being iterated over.
+ for (predicate, _parent_pred, _cause) in unsatisfied_predicates {
+ match predicate.kind().skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Trait(p))
+ if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
+ _ => {
+ unimplemented_traits_only = false;
+ break;
+ }
+ }
+ }
+
+ let mut collect_type_param_suggestions =
+ |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
+ // We don't care about regions here, so it's fine to skip the binder here.
+ if let (ty::Param(_), ty::PredicateKind::Clause(ty::Clause::Trait(p))) =
+ (self_ty.kind(), parent_pred.kind().skip_binder())
+ {
+ let hir = self.tcx.hir();
+ let node = match p.trait_ref.self_ty().kind() {
+ ty::Param(_) => {
+ // Account for `fn` items like in `issue-35677.rs` to
+ // suggest restricting its type params.
+ let parent_body =
+ hir.body_owner(hir::BodyId { hir_id: self.body_id });
+ Some(hir.get(parent_body))
+ }
+ ty::Adt(def, _) => {
+ def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
+ }
+ _ => None,
+ };
+ if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
+ if let Some(g) = kind.generics() {
+ let key = (
+ g.tail_span_for_predicate_suggestion(),
+ g.add_where_or_trailing_comma(),
+ );
+ type_params
+ .entry(key)
+ .or_insert_with(FxHashSet::default)
+ .insert(obligation.to_owned());
+ }
+ }
+ }
+ };
+ let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
+ let msg = format!(
+ "doesn't satisfy `{}`",
+ if obligation.len() > 50 { quiet } else { obligation }
+ );
+ match &self_ty.kind() {
+ // Point at the type that couldn't satisfy the bound.
+ ty::Adt(def, _) => bound_spans.push((self.tcx.def_span(def.did()), msg)),
+ // Point at the trait object that couldn't satisfy the bound.
+ ty::Dynamic(preds, _, _) => {
+ for pred in preds.iter() {
+ match pred.skip_binder() {
+ ty::ExistentialPredicate::Trait(tr) => {
+ bound_spans.push((self.tcx.def_span(tr.def_id), msg.clone()))
+ }
+ ty::ExistentialPredicate::Projection(_)
+ | ty::ExistentialPredicate::AutoTrait(_) => {}
+ }
+ }
+ }
+ // Point at the closure that couldn't satisfy the bound.
+ ty::Closure(def_id, _) => bound_spans
+ .push((tcx.def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
+ _ => {}
+ }
+ };
+ let mut format_pred = |pred: ty::Predicate<'tcx>| {
+ let bound_predicate = pred.kind();
+ match bound_predicate.skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
+ let pred = bound_predicate.rebind(pred);
+ // `<Foo as Iterator>::Item = String`.
+ let projection_ty = pred.skip_binder().projection_ty;
+
+ let substs_with_infer_self = tcx.mk_substs(
+ iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
+ .chain(projection_ty.substs.iter().skip(1)),
+ );
+
+ let quiet_projection_ty =
+ tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
+
+ let term = pred.skip_binder().term;
+
+ let obligation = format!("{} = {}", projection_ty, term);
+ let quiet = with_forced_trimmed_paths!(format!(
+ "{} = {}",
+ quiet_projection_ty, term
+ ));
+
+ bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
+ Some((obligation, projection_ty.self_ty()))
+ }
+ ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
+ let p = poly_trait_ref.trait_ref;
+ let self_ty = p.self_ty();
+ let path = p.print_only_trait_path();
+ let obligation = format!("{}: {}", self_ty, path);
+ let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
+ bound_span_label(self_ty, &obligation, &quiet);
+ Some((obligation, self_ty))
+ }
+ _ => None,
+ }
+ };
+
+ // Find all the requirements that come from a local `impl` block.
+ let mut skip_list: FxHashSet<_> = Default::default();
+ let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
+ for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates
+ .iter()
+ .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
+ .filter_map(|(p, parent, c)| match c.code() {
+ ObligationCauseCode::ImplDerivedObligation(data) => {
+ Some((&data.derived, p, parent, data.impl_def_id, data))
+ }
+ _ => None,
+ })
+ {
+ let parent_trait_ref = data.parent_trait_pred;
+ let path = parent_trait_ref.print_modifiers_and_trait_path();
+ let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
+ let unsatisfied_msg = "unsatisfied trait bound introduced here";
+ let derive_msg = "unsatisfied trait bound introduced in this `derive` macro";
+ match self.tcx.hir().get_if_local(impl_def_id) {
+ // Unmet obligation comes from a `derive` macro, point at it once to
+ // avoid multiple span labels pointing at the same place.
+ Some(Node::Item(hir::Item {
+ kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
+ ..
+ })) if matches!(
+ self_ty.span.ctxt().outer_expn_data().kind,
+ ExpnKind::Macro(MacroKind::Derive, _)
+ ) || matches!(
+ of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind),
+ Some(ExpnKind::Macro(MacroKind::Derive, _))
+ ) =>
+ {
+ let span = self_ty.span.ctxt().outer_expn_data().call_site;
+ let mut spans: MultiSpan = span.into();
+ spans.push_span_label(span, derive_msg);
+ let entry = spanned_predicates.entry(spans);
+ entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
+ }
+
+ // Unmet obligation coming from an `impl`.
+ Some(Node::Item(hir::Item {
+ kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }),
+ span: item_span,
+ ..
+ })) => {
+ let sized_pred =
+ unsatisfied_predicates.iter().any(|(pred, _, _)| {
+ match pred.kind().skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
+ Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
+ && pred.polarity == ty::ImplPolarity::Positive
+ }
+ _ => false,
+ }
+ });
+ for param in generics.params {
+ if param.span == cause.span && sized_pred {
+ let (sp, sugg) = match param.colon_span {
+ Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
+ None => (param.span.shrink_to_hi(), ": ?Sized"),
+ };
+ err.span_suggestion_verbose(
+ sp,
+ "consider relaxing the type parameter's implicit \
+ `Sized` bound",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ if let Some(pred) = parent_p {
+ // Done to add the "doesn't satisfy" `span_label`.
+ let _ = format_pred(*pred);
+ }
+ skip_list.insert(p);
+ let mut spans = if cause.span != *item_span {
+ let mut spans: MultiSpan = cause.span.into();
+ spans.push_span_label(cause.span, unsatisfied_msg);
+ spans
+ } else {
+ let mut spans = Vec::with_capacity(2);
+ if let Some(trait_ref) = of_trait {
+ spans.push(trait_ref.path.span);
+ }
+ spans.push(self_ty.span);
+ spans.into()
+ };
+ if let Some(trait_ref) = of_trait {
+ spans.push_span_label(trait_ref.path.span, "");
+ }
+ spans.push_span_label(self_ty.span, "");
+
+ let entry = spanned_predicates.entry(spans);
+ entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
+ }
+ Some(Node::Item(hir::Item {
+ kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
+ span: item_span,
+ ..
+ })) => {
+ tcx.sess.delay_span_bug(
+ *item_span,
+ "auto trait is invoked with no method error, but no error reported?",
+ );
+ }
+ Some(_) => unreachable!(),
+ None => (),
+ }
+ }
+ let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
+ spanned_predicates.sort_by_key(|(span, (_, _, _))| span.primary_span());
+ for (span, (_path, _self_ty, preds)) in spanned_predicates {
+ let mut preds: Vec<_> = preds
+ .into_iter()
+ .filter_map(|pred| format_pred(*pred))
+ .map(|(p, _)| format!("`{}`", p))
+ .collect();
+ preds.sort();
+ preds.dedup();
+ let msg = if let [pred] = &preds[..] {
+ format!("trait bound {} was not satisfied", pred)
+ } else {
+ format!("the following trait bounds were not satisfied:\n{}", preds.join("\n"),)
+ };
+ err.span_note(span, &msg);
+ unsatisfied_bounds = true;
+ }
+
+ // The requirements that didn't have an `impl` span to show.
+ let mut bound_list = unsatisfied_predicates
+ .iter()
+ .filter_map(|(pred, parent_pred, _cause)| {
+ format_pred(*pred).map(|(p, self_ty)| {
+ collect_type_param_suggestions(self_ty, *pred, &p);
+ (
+ match parent_pred {
+ None => format!("`{}`", &p),
+ Some(parent_pred) => match format_pred(*parent_pred) {
+ None => format!("`{}`", &p),
+ Some((parent_p, _)) => {
+ collect_type_param_suggestions(self_ty, *parent_pred, &p);
+ format!("`{}`\nwhich is required by `{}`", p, parent_p)
+ }
+ },
+ },
+ *pred,
+ )
+ })
+ })
+ .filter(|(_, pred)| !skip_list.contains(&pred))
+ .map(|(t, _)| t)
+ .enumerate()
+ .collect::<Vec<(usize, String)>>();
+
+ for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
+ restrict_type_params = true;
+ // #74886: Sort here so that the output is always the same.
+ let mut obligations = obligations.into_iter().collect::<Vec<_>>();
+ obligations.sort();
+ err.span_suggestion_verbose(
+ span,
+ &format!(
+ "consider restricting the type parameter{s} to satisfy the \
+ trait bound{s}",
+ s = pluralize!(obligations.len())
+ ),
+ format!("{} {}", add_where_or_comma, obligations.join(", ")),
+ Applicability::MaybeIncorrect,
+ );
+ }
+
+ bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
+ bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
+ bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
+
+ if !bound_list.is_empty() || !skip_list.is_empty() {
+ let bound_list =
+ bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n");
+ let actual_prefix = rcvr_ty.prefix_string(self.tcx);
+ info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
+ let (primary_message, label) = if unimplemented_traits.len() == 1
+ && unimplemented_traits_only
+ {
+ unimplemented_traits
+ .into_iter()
+ .next()
+ .map(|(_, (trait_ref, obligation))| {
+ if trait_ref.self_ty().references_error() || rcvr_ty.references_error()
+ {
+ // Avoid crashing.
+ return (None, None);
+ }
+ let OnUnimplementedNote { message, label, .. } =
+ self.err_ctxt().on_unimplemented_note(trait_ref, &obligation);
+ (message, label)
+ })
+ .unwrap()
+ } else {
+ (None, None)
+ };
+ let primary_message = primary_message.unwrap_or_else(|| {
+ format!(
+ "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
+ but its trait bounds were not satisfied"
+ )
+ });
+ err.set_primary_message(&primary_message);
+ if let Some(label) = label {
+ custom_span_label = true;
+ err.span_label(span, label);
+ }
+ if !bound_list.is_empty() {
+ err.note(&format!(
+ "the following trait bounds were not satisfied:\n{bound_list}"
+ ));
+ }
+ self.suggest_derive(&mut err, &unsatisfied_predicates);
+
+ unsatisfied_bounds = true;
+ }
+ }
+
+ let label_span_not_found = |err: &mut Diagnostic| {
+ if unsatisfied_predicates.is_empty() {
+ err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+ let is_string_or_ref_str = match rcvr_ty.kind() {
+ ty::Ref(_, ty, _) => {
+ ty.is_str()
+ || matches!(
+ ty.kind(),
+ ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string()
+ )
+ }
+ ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(),
+ _ => false,
+ };
+ if is_string_or_ref_str && item_name.name == sym::iter {
+ err.span_suggestion_verbose(
+ item_name.span,
+ "because of the in-memory representation of `&str`, to obtain \
+ an `Iterator` over each of its codepoint use method `chars`",
+ "chars",
+ Applicability::MachineApplicable,
+ );
+ }
+ if let ty::Adt(adt, _) = rcvr_ty.kind() {
+ let mut inherent_impls_candidate = self
+ .tcx
+ .inherent_impls(adt.did())
+ .iter()
+ .copied()
+ .filter(|def_id| {
+ if let Some(assoc) = self.associated_value(*def_id, item_name) {
+ // Check for both mode is the same so we avoid suggesting
+ // incorrect associated item.
+ match (mode, assoc.fn_has_self_parameter, source) {
+ (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
+ // We check that the suggest type is actually
+ // different from the received one
+ // So we avoid suggestion method with Box<Self>
+ // for instance
+ self.tcx.at(span).type_of(*def_id) != rcvr_ty
+ && self.tcx.at(span).type_of(*def_id) != rcvr_ty
+ }
+ (Mode::Path, false, _) => true,
+ _ => false,
+ }
+ } else {
+ false
+ }
+ })
+ .collect::<Vec<_>>();
+ if !inherent_impls_candidate.is_empty() {
+ inherent_impls_candidate.sort();
+ inherent_impls_candidate.dedup();
+
+ // number of type to shows at most.
+ let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
+ let type_candidates = inherent_impls_candidate
+ .iter()
+ .take(limit)
+ .map(|impl_item| {
+ format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
+ })
+ .collect::<Vec<_>>()
+ .join("\n");
+ let additional_types = if inherent_impls_candidate.len() > limit {
+ format!("\nand {} more types", inherent_impls_candidate.len() - limit)
+ } else {
+ "".to_string()
+ };
+ err.note(&format!(
+ "the {item_kind} was found for\n{}{}",
+ type_candidates, additional_types
+ ));
+ }
+ }
+ } else {
+ let ty_str =
+ if ty_str.len() > 50 { String::new() } else { format!("on `{ty_str}` ") };
+ err.span_label(
+ span,
+ format!("{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds"),
+ );
+ }
+ };
+
+ // If the method name is the name of a field with a function or closure type,
+ // give a helping note that it has to be called as `(x.f)(...)`.
+ if let SelfSource::MethodCall(expr) = source {
+ if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
+ && lev_candidate.is_none()
+ && !custom_span_label
+ {
+ label_span_not_found(&mut err);
+ }
+ } else if !custom_span_label {
+ label_span_not_found(&mut err);
+ }
+
+ // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
+ // can't be called due to `typeof(expr): Clone` not holding.
+ if unsatisfied_predicates.is_empty() {
+ self.suggest_calling_method_on_field(&mut err, source, span, rcvr_ty, item_name);
+ }
+
+ self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
+
+ bound_spans.sort();
+ bound_spans.dedup();
+ for (span, msg) in bound_spans.into_iter() {
+ err.span_label(span, &msg);
+ }
+
+ if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
+ } else {
+ self.suggest_traits_to_import(
+ &mut err,
+ span,
+ rcvr_ty,
+ item_name,
+ args.map(|(_, args)| args.len() + 1),
+ source,
+ no_match_data.out_of_scope_traits.clone(),
+ &unsatisfied_predicates,
+ &static_candidates,
+ unsatisfied_bounds,
+ );
+ }
+
+ // Don't emit a suggestion if we found an actual method
+ // that had unsatisfied trait bounds
+ if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
+ let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
+ if let Some(suggestion) = lev_distance::find_best_match_for_name(
+ &adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
+ item_name.name,
+ None,
+ ) {
+ err.span_suggestion(
+ span,
+ "there is a variant with a similar name",
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+
+ if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
+ let msg = "remove this method call";
+ let mut fallback_span = true;
+ if let SelfSource::MethodCall(expr) = source {
+ let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
+ if let Some(span) = call_expr.span.trim_start(expr.span) {
+ err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
+ fallback_span = false;
+ }
+ }
+ if fallback_span {
+ err.span_label(span, msg);
+ }
+ } else if let Some(lev_candidate) = lev_candidate {
+ // Don't emit a suggestion if we found an actual method
+ // that had unsatisfied trait bounds
+ if unsatisfied_predicates.is_empty() {
+ let def_kind = lev_candidate.kind.as_def_kind();
+ // Methods are defined within the context of a struct and their first parameter is always self,
+ // which represents the instance of the struct the method is being called on
+ // Associated functions don’t take self as a parameter and
+ // they are not methods because they don’t have an instance of the struct to work with.
+ if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
+ err.span_suggestion(
+ span,
+ "there is a method with a similar name",
+ lev_candidate.name,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_suggestion(
+ span,
+ &format!(
+ "there is {} {} with a similar name",
+ def_kind.article(),
+ def_kind.descr(lev_candidate.def_id),
+ ),
+ lev_candidate.name,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+
+ self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
+ return Some(err);
+ }
+
+ fn note_candidates_on_method_error(
+ &self,
+ rcvr_ty: Ty<'tcx>,
+ item_name: Ident,
+ args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+ span: Span,
+ err: &mut Diagnostic,
+ sources: &mut Vec<CandidateSource>,
+ sugg_span: Option<Span>,
+ ) {
+ sources.sort();
+ sources.dedup();
+ // Dynamic limit to avoid hiding just one candidate, which is silly.
+ let limit = if sources.len() == 5 { 5 } else { 4 };
+
+ for (idx, source) in sources.iter().take(limit).enumerate() {
+ match *source {
+ CandidateSource::Impl(impl_did) => {
+ // Provide the best span we can. Use the item, if local to crate, else
+ // the impl, if local to crate (item may be defaulted), else nothing.
+ let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
+ let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
+ self.associated_value(impl_trait_ref.def_id, item_name)
+ }) else {
+ continue;
+ };
+
+ let note_span = if item.def_id.is_local() {
+ Some(self.tcx.def_span(item.def_id))
+ } else if impl_did.is_local() {
+ Some(self.tcx.def_span(impl_did))
+ } else {
+ None
+ };
+
+ let impl_ty = self.tcx.at(span).type_of(impl_did);
+
+ let insertion = match self.tcx.impl_trait_ref(impl_did) {
+ None => String::new(),
+ Some(trait_ref) => {
+ format!(" of the trait `{}`", self.tcx.def_path_str(trait_ref.def_id))
+ }
+ };
+
+ let (note_str, idx) = if sources.len() > 1 {
+ (
+ format!(
+ "candidate #{} is defined in an impl{} for the type `{}`",
+ idx + 1,
+ insertion,
+ impl_ty,
+ ),
+ Some(idx + 1),
+ )
+ } else {
+ (
+ format!(
+ "the candidate is defined in an impl{} for the type `{}`",
+ insertion, impl_ty,
+ ),
+ None,
+ )
+ };
+ if let Some(note_span) = note_span {
+ // We have a span pointing to the method. Show note with snippet.
+ err.span_note(note_span, ¬e_str);
+ } else {
+ err.note(¬e_str);
+ }
+ if let Some(sugg_span) = sugg_span
+ && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
+ let path = self.tcx.def_path_str(trait_ref.def_id);
+
+ let ty = match item.kind {
+ ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
+ ty::AssocKind::Fn => self
+ .tcx
+ .fn_sig(item.def_id)
+ .inputs()
+ .skip_binder()
+ .get(0)
+ .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
+ .copied()
+ .unwrap_or(rcvr_ty),
+ };
+ print_disambiguation_help(
+ item_name,
+ args,
+ err,
+ path,
+ ty,
+ item.kind,
+ item.def_id,
+ sugg_span,
+ idx,
+ self.tcx.sess.source_map(),
+ item.fn_has_self_parameter,
+ );
+ }
+ }
+ CandidateSource::Trait(trait_did) => {
+ let Some(item) = self.associated_value(trait_did, item_name) else { continue };
+ let item_span = self.tcx.def_span(item.def_id);
+ let idx = if sources.len() > 1 {
+ let msg = &format!(
+ "candidate #{} is defined in the trait `{}`",
+ idx + 1,
+ self.tcx.def_path_str(trait_did)
+ );
+ err.span_note(item_span, msg);
+ Some(idx + 1)
+ } else {
+ let msg = &format!(
+ "the candidate is defined in the trait `{}`",
+ self.tcx.def_path_str(trait_did)
+ );
+ err.span_note(item_span, msg);
+ None
+ };
+ if let Some(sugg_span) = sugg_span {
+ let path = self.tcx.def_path_str(trait_did);
+ print_disambiguation_help(
+ item_name,
+ args,
+ err,
+ path,
+ rcvr_ty,
+ item.kind,
+ item.def_id,
+ sugg_span,
+ idx,
+ self.tcx.sess.source_map(),
+ item.fn_has_self_parameter,
+ );
+ }
+ }
+ }
+ }
+ if sources.len() > limit {
+ err.note(&format!("and {} others", sources.len() - limit));
+ }
+ }
+
/// Suggest calling `Ty::method` if `.method()` isn't found because the method
/// doesn't take a `self` receiver.
fn suggest_associated_call_syntax(
Applicability::MachineApplicable,
);
} else {
- let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
+ let call_expr = tcx.hir().expect_expr(tcx.hir().parent_id(expr.hir_id));
if let Some(span) = call_expr.span.trim_start(item_name.span) {
err.span_suggestion(
let filename = tcx.sess.source_map().span_to_filename(span);
let parent_node =
- self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id));
+ self.tcx.hir().get_parent(hir_id);
let msg = format!(
"you must specify a type for this binding, like `{}`",
concrete_type,
let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name };
visitor.visit_body(&body);
- let parent = self.tcx.hir().get_parent_node(seg1.hir_id);
+ let parent = self.tcx.hir().parent_id(seg1.hir_id);
if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent)
&& let Some(expr) = visitor.result
&& let Some(self_ty) = self.node_ty_opt(expr.hir_id)
&& let Some((fields, substs)) =
self.get_field_candidates_considering_privacy(span, actual, mod_id)
{
- let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
+ let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
let lang_items = self.tcx.lang_items();
let never_mention_traits = [
) {
let tcx = self.tcx;
let SelfSource::MethodCall(expr) = source else { return; };
- let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
+ let call_expr = tcx.hir().expect_expr(tcx.hir().parent_id(expr.hir_id));
let ty::Adt(kind, substs) = actual.kind() else { return; };
match kind.adt_kind() {
_ => false,
}
}) && (type_is_local || info.def_id.is_local())
+ && !self.tcx.trait_is_auto(info.def_id)
&& self
.associated_value(info.def_id, item_name)
.filter(|item| {
return false;
}
- let parent = self.tcx.hir().get_parent_node(expr.hir_id);
+ let parent = self.tcx.hir().parent_id(expr.hir_id);
if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) &&
let hir::ExprKind::MethodCall(
hir::PathSegment { ident: method_name, .. },
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
};
use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
+use rustc_middle::ty::{
+ self, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable,
+};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::FulfillmentError;
+use rustc_trait_selection::traits::{self, FulfillmentError};
use rustc_type_ir::sty::TyKind::*;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self
.lookup_op_method(
lhs_deref_ty,
- Some(rhs_ty),
- Some(rhs),
+ Some((rhs, rhs_ty)),
Op::Binary(op, IsAssign::Yes),
expected,
)
if self
.lookup_op_method(
lhs_ty,
- Some(rhs_ty),
- Some(rhs),
+ Some((rhs, rhs_ty)),
Op::Binary(op, IsAssign::Yes),
expected,
)
let result = self.lookup_op_method(
lhs_ty,
- Some(rhs_ty_var),
- Some(rhs_expr),
+ Some((rhs_expr, rhs_ty_var)),
Op::Binary(op, is_assign),
expected,
);
if self
.lookup_op_method(
lhs_deref_ty,
- Some(rhs_ty),
- Some(rhs_expr),
+ Some((rhs_expr, rhs_ty)),
Op::Binary(op, is_assign),
expected,
)
let is_compatible = |lhs_ty, rhs_ty| {
self.lookup_op_method(
lhs_ty,
- Some(rhs_ty),
- Some(rhs_expr),
+ Some((rhs_expr, rhs_ty)),
Op::Binary(op, is_assign),
expected,
)
let errors = self
.lookup_op_method(
lhs_ty,
- Some(rhs_ty),
- Some(rhs_expr),
+ Some((rhs_expr, rhs_ty)),
Op::Binary(op, is_assign),
expected,
)
if let Some(output_def_id) = output_def_id
&& let Some(trait_def_id) = trait_def_id
&& self.tcx.parent(output_def_id) == trait_def_id
+ && output_ty.is_suggestable(self.tcx, false)
{
Some(("Output", *output_ty))
} else {
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
assert!(op.is_by_value());
- match self.lookup_op_method(operand_ty, None, None, Op::Unary(op, ex.span), expected) {
+ match self.lookup_op_method(operand_ty, None, Op::Unary(op, ex.span), expected) {
Ok(method) => {
self.write_method_call(ex.hir_id, method);
method.sig.output()
}
}
- let sp = self.tcx.sess.source_map().start_point(ex.span);
+ let sp = self.tcx.sess.source_map().start_point(ex.span).with_parent(None);
if let Some(sp) =
self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
{
fn lookup_op_method(
&self,
lhs_ty: Ty<'tcx>,
- other_ty: Option<Ty<'tcx>>,
- other_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
+ opt_rhs: Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)>,
op: Op,
expected: Expectation<'tcx>,
) -> Result<MethodCallee<'tcx>, Vec<FulfillmentError<'tcx>>> {
Op::Unary(..) => 0,
},
) {
+ self.tcx
+ .sess
+ .delay_span_bug(span, "operator didn't have the right number of generic args");
return Err(vec![]);
}
let opname = Ident::with_dummy_span(opname);
+ let input_types =
+ opt_rhs.as_ref().map(|(_, ty)| std::slice::from_ref(ty)).unwrap_or_default();
+ let cause = self.cause(
+ span,
+ traits::BinOp {
+ rhs_span: opt_rhs.map(|(expr, _)| expr.span),
+ is_lit: opt_rhs
+ .map_or(false, |(expr, _)| matches!(expr.kind, hir::ExprKind::Lit(_))),
+ output_ty: expected.only_has_type(self),
+ },
+ );
+
let method = trait_did.and_then(|trait_did| {
- self.lookup_op_method_in_trait(
- span,
- opname,
- trait_did,
- lhs_ty,
- other_ty,
- other_ty_expr,
- expected,
- )
+ self.lookup_method_in_trait(cause.clone(), opname, trait_did, lhs_ty, Some(input_types))
});
match (method, trait_did) {
}
(None, None) => Err(vec![]),
(None, Some(trait_did)) => {
- let (obligation, _) = self.obligation_for_op_method(
- span,
- trait_did,
- lhs_ty,
- other_ty,
- other_ty_expr,
- expected,
- );
+ let (obligation, _) =
+ self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types));
Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation))
}
}
-use crate::FnCtxt;
+use crate::{FnCtxt, RawTy};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{
(lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs),
_ => span_bug!(span, "Impossible, verified above."),
}
+ if (lhs, rhs).references_error() {
+ err.downgrade_to_delayed_bug();
+ }
if self.tcx.sess.teach(&err.get_code().unwrap()) {
err.note(
"In a match expression, only numbers and characters can be matched \
let tcx = self.tcx;
if let PatKind::Ref(inner, mutbl) = pat.kind
&& let PatKind::Binding(_, _, binding, ..) = inner.kind {
- let binding_parent_id = tcx.hir().get_parent_node(pat.hir_id);
+ let binding_parent_id = tcx.hir().parent_id(pat.hir_id);
let binding_parent = tcx.hir().get(binding_parent_id);
debug!(?inner, ?pat, ?binding_parent);
err.span_note(sp, format!("{msg}: `{sugg}`"));
}
}
+ hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
+ for i in pat_arr.iter() {
+ if let PatKind::Ref(the_ref, _) = i.kind
+ && let PatKind::Binding(mt, _, ident, _) = the_ref.kind {
+ let hir::BindingAnnotation(_, mtblty) = mt;
+ err.span_suggestion_verbose(
+ i.span,
+ format!("consider removing `&{mutability}` from the pattern"),
+ mtblty.prefix_str().to_string() + &ident.name.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ if let Some((sp, msg, sugg)) = mut_var_suggestion {
+ err.span_note(sp, format!("{msg}: `{sugg}`"));
+ }
+ }
hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
// rely on match ergonomics or it might be nested `&&pat`
err.span_suggestion_verbose(
&self,
pat: &Pat<'tcx>,
qpath: &hir::QPath<'_>,
- path_resolution: (Res, Option<Ty<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
+ path_resolution: (Res, Option<RawTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
expected: Ty<'tcx>,
ti: TopInfo<'tcx>,
) -> Ty<'tcx> {
res.descr(),
),
);
- match self.tcx.hir().get(self.tcx.hir().get_parent_node(pat.hir_id)) {
+ match self.tcx.hir().get_parent(pat.hir_id) {
hir::Node::PatField(..) => {
e.span_suggestion_verbose(
ident.span.shrink_to_hi(),
) -> Ty<'tcx> {
let tcx = self.tcx;
let expected = self.shallow_resolve(expected);
- let (rptr_ty, inner_ty) = if self.check_dereferenceable(pat.span, expected, inner) {
+ let (ref_ty, inner_ty) = if self.check_dereferenceable(pat.span, expected, inner) {
// `demand::subtype` would be good enough, but using `eqtype` turns
// out to be equally general. See (note_1) for details.
kind: TypeVariableOriginKind::TypeInference,
span: inner.span,
});
- let rptr_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
- debug!("check_pat_ref: demanding {:?} = {:?}", expected, rptr_ty);
- let err = self.demand_eqtype_pat_diag(pat.span, expected, rptr_ty, ti);
+ let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
+ debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
+ let err = self.demand_eqtype_pat_diag(pat.span, expected, ref_ty, ti);
// Look for a case like `fn foo(&foo: u32)` and suggest
// `fn foo(foo: &u32)`
self.borrow_pat_suggestion(&mut err, pat);
err.emit();
}
- (rptr_ty, inner_ty)
+ (ref_ty, inner_ty)
}
}
} else {
(err, err)
};
self.check_pat(inner, inner_ty, def_bm, ti);
- rptr_ty
+ ref_ty
}
/// Create a reference type with a fresh region variable.
imm_tr.and_then(|trait_did| {
self.lookup_method_in_trait(
- span,
+ self.misc(span),
Ident::with_dummy_span(imm_op),
trait_did,
base_ty,
mut_tr.and_then(|trait_did| {
self.lookup_method_in_trait(
- span,
+ self.misc(span),
Ident::with_dummy_span(mut_op),
trait_did,
base_ty,
assert!(mask <= 0xFF);
let byte = word & mask;
- result.push_str(&format!("{}{:02x}", sep, byte));
+ result.push_str(&format!("{sep}{byte:02x}"));
if remain <= 8 {
break;
};
debug_assert!(
self.check_invariants(),
- "wrong intervals after insert {:?}..={:?} to {:?}",
- start,
- end,
- self
+ "wrong intervals after insert {start:?}..={end:?} to {self:?}"
);
result
}
use hir::GenericParamKind;
use rustc_errors::{
fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
- MultiSpan, SubdiagnosticMessage,
+ IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage,
};
use rustc_hir as hir;
-use rustc_hir::{FnRetTy, Ty};
+use rustc_hir::FnRetTy;
use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_middle::ty::{Region, TyCtxt};
+use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath;
+use rustc_middle::ty::{Binder, FnSig, Region, Ty, TyCtxt};
use rustc_span::symbol::kw;
+use rustc_span::Symbol;
use rustc_span::{symbol::Ident, BytePos, Span};
+use crate::infer::error_reporting::nice_region_error::placeholder_error::Highlighted;
use crate::infer::error_reporting::{
need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
ObligationCauseAsDiagArg,
pub struct AddLifetimeParamsSuggestion<'a> {
pub tcx: TyCtxt<'a>,
pub sub: Region<'a>,
- pub ty_sup: &'a Ty<'a>,
- pub ty_sub: &'a Ty<'a>,
+ pub ty_sup: &'a hir::Ty<'a>,
+ pub ty_sub: &'a hir::Ty<'a>,
pub add_note: bool,
}
{
let mut mk_suggestion = || {
let (
- hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
- hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
+ hir::Ty { kind: hir::TyKind::Ref(lifetime_sub, _), .. },
+ hir::Ty { kind: hir::TyKind::Ref(lifetime_sup, _), .. },
) = (self.ty_sub, self.ty_sup) else {
return false;
};
#[subdiagnostic]
pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
}
+
+#[derive(Diagnostic)]
+pub enum ExplicitLifetimeRequired<'a> {
+ #[diag(infer_explicit_lifetime_required_with_ident, code = "E0621")]
+ WithIdent {
+ #[primary_span]
+ #[label]
+ span: Span,
+ simple_ident: Ident,
+ named: String,
+ #[suggestion(
+ infer_explicit_lifetime_required_sugg_with_ident,
+ code = "{new_ty}",
+ applicability = "unspecified"
+ )]
+ new_ty_span: Span,
+ #[skip_arg]
+ new_ty: Ty<'a>,
+ },
+ #[diag(infer_explicit_lifetime_required_with_param_type, code = "E0621")]
+ WithParamType {
+ #[primary_span]
+ #[label]
+ span: Span,
+ named: String,
+ #[suggestion(
+ infer_explicit_lifetime_required_sugg_with_param_type,
+ code = "{new_ty}",
+ applicability = "unspecified"
+ )]
+ new_ty_span: Span,
+ #[skip_arg]
+ new_ty: Ty<'a>,
+ },
+}
+
+pub enum TyOrSig<'tcx> {
+ Ty(Highlighted<'tcx, Ty<'tcx>>),
+ ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>),
+}
+
+impl IntoDiagnosticArg for TyOrSig<'_> {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ match self {
+ TyOrSig::Ty(ty) => ty.into_diagnostic_arg(),
+ TyOrSig::ClosureSig(sig) => sig.into_diagnostic_arg(),
+ }
+ }
+}
+
+#[derive(Subdiagnostic)]
+pub enum ActualImplExplNotes<'tcx> {
+ #[note(infer_actual_impl_expl_expected_signature_two)]
+ ExpectedSignatureTwo {
+ leading_ellipsis: bool,
+ ty_or_sig: TyOrSig<'tcx>,
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ lifetime_1: usize,
+ lifetime_2: usize,
+ },
+ #[note(infer_actual_impl_expl_expected_signature_any)]
+ ExpectedSignatureAny {
+ leading_ellipsis: bool,
+ ty_or_sig: TyOrSig<'tcx>,
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ lifetime_1: usize,
+ },
+ #[note(infer_actual_impl_expl_expected_signature_some)]
+ ExpectedSignatureSome {
+ leading_ellipsis: bool,
+ ty_or_sig: TyOrSig<'tcx>,
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ lifetime_1: usize,
+ },
+ #[note(infer_actual_impl_expl_expected_signature_nothing)]
+ ExpectedSignatureNothing {
+ leading_ellipsis: bool,
+ ty_or_sig: TyOrSig<'tcx>,
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ },
+ #[note(infer_actual_impl_expl_expected_passive_two)]
+ ExpectedPassiveTwo {
+ leading_ellipsis: bool,
+ ty_or_sig: TyOrSig<'tcx>,
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ lifetime_1: usize,
+ lifetime_2: usize,
+ },
+ #[note(infer_actual_impl_expl_expected_passive_any)]
+ ExpectedPassiveAny {
+ leading_ellipsis: bool,
+ ty_or_sig: TyOrSig<'tcx>,
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ lifetime_1: usize,
+ },
+ #[note(infer_actual_impl_expl_expected_passive_some)]
+ ExpectedPassiveSome {
+ leading_ellipsis: bool,
+ ty_or_sig: TyOrSig<'tcx>,
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ lifetime_1: usize,
+ },
+ #[note(infer_actual_impl_expl_expected_passive_nothing)]
+ ExpectedPassiveNothing {
+ leading_ellipsis: bool,
+ ty_or_sig: TyOrSig<'tcx>,
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ },
+ #[note(infer_actual_impl_expl_expected_other_two)]
+ ExpectedOtherTwo {
+ leading_ellipsis: bool,
+ ty_or_sig: TyOrSig<'tcx>,
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ lifetime_1: usize,
+ lifetime_2: usize,
+ },
+ #[note(infer_actual_impl_expl_expected_other_any)]
+ ExpectedOtherAny {
+ leading_ellipsis: bool,
+ ty_or_sig: TyOrSig<'tcx>,
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ lifetime_1: usize,
+ },
+ #[note(infer_actual_impl_expl_expected_other_some)]
+ ExpectedOtherSome {
+ leading_ellipsis: bool,
+ ty_or_sig: TyOrSig<'tcx>,
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ lifetime_1: usize,
+ },
+ #[note(infer_actual_impl_expl_expected_other_nothing)]
+ ExpectedOtherNothing {
+ leading_ellipsis: bool,
+ ty_or_sig: TyOrSig<'tcx>,
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ },
+ #[note(infer_actual_impl_expl_but_actually_implements_trait)]
+ ButActuallyImplementsTrait {
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ has_lifetime: bool,
+ lifetime: usize,
+ },
+ #[note(infer_actual_impl_expl_but_actually_implemented_for_ty)]
+ ButActuallyImplementedForTy {
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ has_lifetime: bool,
+ lifetime: usize,
+ ty: String,
+ },
+ #[note(infer_actual_impl_expl_but_actually_ty_implements)]
+ ButActuallyTyImplements {
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ has_lifetime: bool,
+ lifetime: usize,
+ ty: String,
+ },
+}
+
+pub enum ActualImplExpectedKind {
+ Signature,
+ Passive,
+ Other,
+}
+
+pub enum ActualImplExpectedLifetimeKind {
+ Two,
+ Any,
+ Some,
+ Nothing,
+}
+
+impl<'tcx> ActualImplExplNotes<'tcx> {
+ pub fn new_expected(
+ kind: ActualImplExpectedKind,
+ lt_kind: ActualImplExpectedLifetimeKind,
+ leading_ellipsis: bool,
+ ty_or_sig: TyOrSig<'tcx>,
+ trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ lifetime_1: usize,
+ lifetime_2: usize,
+ ) -> Self {
+ match (kind, lt_kind) {
+ (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => {
+ Self::ExpectedSignatureTwo {
+ leading_ellipsis,
+ ty_or_sig,
+ trait_path,
+ lifetime_1,
+ lifetime_2,
+ }
+ }
+ (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => {
+ Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+ }
+ (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => {
+ Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+ }
+ (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => {
+ Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path }
+ }
+ (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => {
+ Self::ExpectedPassiveTwo {
+ leading_ellipsis,
+ ty_or_sig,
+ trait_path,
+ lifetime_1,
+ lifetime_2,
+ }
+ }
+ (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => {
+ Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+ }
+ (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => {
+ Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+ }
+ (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => {
+ Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path }
+ }
+ (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => {
+ Self::ExpectedOtherTwo {
+ leading_ellipsis,
+ ty_or_sig,
+ trait_path,
+ lifetime_1,
+ lifetime_2,
+ }
+ }
+ (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => {
+ Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+ }
+ (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => {
+ Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+ }
+ (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => {
+ Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path }
+ }
+ }
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(infer_trait_placeholder_mismatch)]
+pub struct TraitPlaceholderMismatch<'tcx> {
+ #[primary_span]
+ pub span: Span,
+ #[label(label_satisfy)]
+ pub satisfy_span: Option<Span>,
+ #[label(label_where)]
+ pub where_span: Option<Span>,
+ #[label(label_dup)]
+ pub dup_span: Option<Span>,
+ pub def_id: String,
+ pub trait_def_id: String,
+
+ #[subdiagnostic]
+ pub actual_impl_expl_notes: Vec<ActualImplExplNotes<'tcx>>,
+}
+
+pub struct ConsiderBorrowingParamHelp {
+ pub spans: Vec<Span>,
+}
+
+impl AddToDiagnostic for ConsiderBorrowingParamHelp {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
+ let mut type_param_span: MultiSpan = self.spans.clone().into();
+ for &span in &self.spans {
+ // Seems like we can't call f() here as Into<DiagnosticMessage> is required
+ type_param_span.push_span_label(span, fluent::infer_tid_consider_borrowing);
+ }
+ let msg = f(diag, fluent::infer_tid_param_help.into());
+ diag.span_help(type_param_span, msg);
+ }
+}
+
+#[derive(Subdiagnostic)]
+#[help(infer_tid_rel_help)]
+pub struct RelationshipHelp;
+
+#[derive(Diagnostic)]
+#[diag(infer_trait_impl_diff)]
+pub struct TraitImplDiff {
+ #[primary_span]
+ #[label(found)]
+ pub sp: Span,
+ #[label(expected)]
+ pub trait_sp: Span,
+ #[note(expected_found)]
+ pub note: (),
+ #[subdiagnostic]
+ pub param_help: ConsiderBorrowingParamHelp,
+ #[subdiagnostic]
+ // Seems like subdiagnostics are always pushed to the end, so this one
+ // also has to be a subdiagnostic to maintain order.
+ pub rel_help: Option<RelationshipHelp>,
+ pub expected: String,
+ pub found: String,
+}
+
+pub struct DynTraitConstraintSuggestion {
+ pub span: Span,
+ pub ident: Ident,
+}
+
+impl AddToDiagnostic for DynTraitConstraintSuggestion {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
+ let mut multi_span: MultiSpan = vec![self.span].into();
+ multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label);
+ multi_span.push_span_label(self.ident.span, fluent::infer_dtcs_introduces_requirement);
+ let msg = f(diag, fluent::infer_dtcs_has_req_note.into());
+ diag.span_note(multi_span, msg);
+ let msg = f(diag, fluent::infer_dtcs_suggestion.into());
+ diag.span_suggestion_verbose(
+ self.span.shrink_to_hi(),
+ msg,
+ " + '_",
+ Applicability::MaybeIncorrect,
+ );
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(infer_but_calling_introduces, code = "E0772")]
+pub struct ButCallingIntroduces {
+ #[label(label1)]
+ pub param_ty_span: Span,
+ #[primary_span]
+ #[label(label2)]
+ pub cause_span: Span,
+
+ pub has_param_name: bool,
+ pub param_name: String,
+ pub has_lifetime: bool,
+ pub lifetime: String,
+ pub assoc_item: Symbol,
+ pub has_impl_path: bool,
+ pub impl_path: String,
+}
+
+pub struct ReqIntroducedLocations {
+ pub span: MultiSpan,
+ pub spans: Vec<Span>,
+ pub fn_decl_span: Span,
+ pub cause_span: Span,
+ pub add_label: bool,
+}
+
+impl AddToDiagnostic for ReqIntroducedLocations {
+ fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, f: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
+ for sp in self.spans {
+ self.span.push_span_label(sp, fluent::infer_ril_introduced_here);
+ }
+
+ if self.add_label {
+ self.span.push_span_label(self.fn_decl_span, fluent::infer_ril_introduced_by);
+ }
+ self.span.push_span_label(self.cause_span, fluent::infer_ril_because_of);
+ let msg = f(diag, fluent::infer_ril_static_introduced_by.into());
+ diag.span_note(self.span, msg);
+ }
+}
+
+pub struct MoreTargeted {
+ pub ident: Symbol,
+}
+
+impl AddToDiagnostic for MoreTargeted {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _f: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
+ diag.code(rustc_errors::error_code!(E0772));
+ diag.set_primary_message(fluent::infer_more_targeted);
+ diag.set_arg("ident", self.ident);
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(infer_but_needs_to_satisfy, code = "E0759")]
+pub struct ButNeedsToSatisfy {
+ #[primary_span]
+ pub sp: Span,
+ #[label(influencer)]
+ pub influencer_point: Span,
+ #[label(used_here)]
+ pub spans: Vec<Span>,
+ #[label(require)]
+ pub require_span_as_label: Option<Span>,
+ #[note(require)]
+ pub require_span_as_note: Option<Span>,
+ #[note(introduced_by_bound)]
+ pub bound: Option<Span>,
+
+ #[subdiagnostic]
+ pub req_introduces_loc: Option<ReqIntroducedLocations>,
+
+ pub spans_empty: bool,
+ pub has_lifetime: bool,
+ pub lifetime: String,
+}
}
}
}
+
+impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
+ fn to_trace(
+ _: TyCtxt<'tcx>,
+ cause: &ObligationCause<'tcx>,
+ a_is_expected: bool,
+ a: Self,
+ b: Self,
+ ) -> TypeTrace<'tcx> {
+ TypeTrace { cause: cause.clone(), values: Sigs(ExpectedFound::new(a_is_expected, a, b)) }
+ }
+}
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
use crate::infer::canonical::{
- Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Canonicalized,
- OriginalQueryValues,
+ Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues,
};
use crate::infer::InferCtxt;
use rustc_middle::ty::flags::FlagComputation;
&self,
value: V,
query_state: &mut OriginalQueryValues<'tcx>,
- ) -> Canonicalized<'tcx, V>
+ ) -> Canonical<'tcx, V>
where
V: TypeFoldable<'tcx>,
{
&self,
value: V,
query_state: &mut OriginalQueryValues<'tcx>,
- ) -> Canonicalized<'tcx, V>
+ ) -> Canonical<'tcx, V>
where
V: TypeFoldable<'tcx>,
{
/// out the [chapter in the rustc dev guide][c].
///
/// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query-result
- pub fn canonicalize_response<V>(&self, value: V) -> Canonicalized<'tcx, V>
+ pub fn canonicalize_response<V>(&self, value: V) -> Canonical<'tcx, V>
where
V: TypeFoldable<'tcx>,
{
)
}
- pub fn canonicalize_user_type_annotation<V>(&self, value: V) -> Canonicalized<'tcx, V>
+ pub fn canonicalize_user_type_annotation<V>(&self, value: V) -> Canonical<'tcx, V>
where
V: TypeFoldable<'tcx>,
{
&self,
value: V,
query_state: &mut OriginalQueryValues<'tcx>,
- ) -> Canonicalized<'tcx, V>
+ ) -> Canonical<'tcx, V>
where
V: TypeFoldable<'tcx>,
{
tcx: TyCtxt<'tcx>,
canonicalize_region_mode: &dyn CanonicalizeMode,
query_state: &mut OriginalQueryValues<'tcx>,
- ) -> Canonicalized<'tcx, V>
+ ) -> Canonical<'tcx, V>
where
V: TypeFoldable<'tcx>,
{
use crate::infer::canonical::substitute::{substitute_value, CanonicalExt};
use crate::infer::canonical::{
- Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, OriginalQueryValues,
+ Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues,
QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse,
};
use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
inference_vars: CanonicalVarValues<'tcx>,
answer: T,
fulfill_cx: &mut dyn TraitEngine<'tcx>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, T>>
+ ) -> Fallible<CanonicalQueryResponse<'tcx, T>>
where
T: Debug + TypeFoldable<'tcx>,
Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
-// ignore-tidy-filelength
//! Error Reporting Code for the inference engine
//!
//! Because of the way inference, and in particular region inference,
None,
format!("captures `{}`", hidden_region),
None,
+ Some(reg_info.def_id),
)
}
}
format!("this and all prior arms are found to be of type `{}`", t),
);
}
- let outer_error_span = if any_multiline_arm {
+ let outer = if any_multiline_arm || !source_map.is_multiline(cause.span) {
// Cover just `match` and the scrutinee expression, not
// the entire match body, to reduce diagram noise.
cause.span.shrink_to_lo().to(scrut_span)
cause.span
};
let msg = "`match` arms have incompatible types";
- err.span_label(outer_error_span, msg);
+ err.span_label(outer, msg);
self.suggest_remove_semi_or_return_binding(
err,
prior_arm_block_id,
impl<'tcx> OpaqueTypesVisitor<'tcx> {
fn visit_expected_found(
tcx: TyCtxt<'tcx>,
- expected: Ty<'tcx>,
- found: Ty<'tcx>,
+ expected: impl TypeVisitable<'tcx>,
+ found: impl TypeVisitable<'tcx>,
ignore_span: Span,
) -> Self {
let mut types_visitor = OpaqueTypesVisitor {
_ => (false, Mismatch::Fixed("type")),
}
}
+ ValuePairs::Sigs(infer::ExpectedFound { expected, found }) => {
+ OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span)
+ .report(diag);
+ (false, Mismatch::Fixed("signature"))
+ }
ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
(false, Mismatch::Fixed("trait"))
}
// In some (most?) cases cause.body_id points to actual body, but in some cases
// it's an actual definition. According to the comments (e.g. in
- // rustc_hir_analysis/check/compare_method.rs:compare_predicate_entailment) the latter
+ // rustc_hir_analysis/check/compare_impl_item.rs:compare_predicate_entailment) the latter
// is relied upon by some other code. This might (or might not) need cleanup.
let body_owner_def_id =
self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| {
ret => ret,
}
}
+ infer::Sigs(exp_found) => {
+ let exp_found = self.resolve_vars_if_possible(exp_found);
+ if exp_found.references_error() {
+ return None;
+ }
+ let (exp, fnd) = self.cmp_fn_sig(
+ &ty::Binder::dummy(exp_found.expected),
+ &ty::Binder::dummy(exp_found.found),
+ );
+ Some((exp, fnd, None, None))
+ }
}
}
}
}
- hir::TyKind::Rptr(ref lifetime, _) => {
- // the lifetime of the TyRptr
+ hir::TyKind::Ref(ref lifetime, _) => {
+ // the lifetime of the Ref
let hir_id = lifetime.hir_id;
match (self.tcx.named_region(hir_id), self.bound_region) {
// Find the index of the named region that was part of the
pub mod find_anon_type;
mod mismatched_static_lifetime;
mod named_anon_conflict;
-mod placeholder_error;
+pub(crate) mod placeholder_error;
mod placeholder_relation;
mod static_impl_trait;
mod trait_impl_difference;
//! Error Reporting for Anonymous Region Lifetime Errors
//! where one region is named and the other is anonymous.
-use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use crate::{
+ errors::ExplicitLifetimeRequired,
+ infer::error_reporting::nice_region_error::find_anon_type::find_anon_type,
+};
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
use rustc_middle::ty;
use rustc_span::symbol::kw;
{
return None;
}
-
- let (error_var, span_label_var) = match param.pat.simple_ident() {
- Some(simple_ident) => (
- format!("the type of `{}`", simple_ident),
- format!("the type of `{}`", simple_ident),
- ),
- None => ("parameter type".to_owned(), "type".to_owned()),
+ let named = named.to_string();
+ let err = match param.pat.simple_ident() {
+ Some(simple_ident) => ExplicitLifetimeRequired::WithIdent {
+ span,
+ simple_ident,
+ named,
+ new_ty_span,
+ new_ty,
+ },
+ None => ExplicitLifetimeRequired::WithParamType { span, named, new_ty_span, new_ty },
};
-
- let mut diag = struct_span_err!(
- self.tcx().sess,
- span,
- E0621,
- "explicit lifetime required in {}",
- error_var
- );
-
- diag.span_label(span, format!("lifetime `{}` required", named));
- diag.span_suggestion(
- new_ty_span,
- &format!("add explicit lifetime `{}` to {}", named, span_label_var),
- new_ty,
- Applicability::Unspecified,
- );
-
- Some(diag)
+ Some(self.tcx().sess.parse_sess.create_err(err))
}
}
+use crate::errors::{
+ ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes,
+ TraitPlaceholderMismatch, TyOrSig,
+};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::ValuePairs;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_data_structures::intern::Interned;
-use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt};
-use std::fmt::{self, Write};
+use std::fmt;
+
+// HACK(eddyb) maybe move this in a more central location.
+#[derive(Copy, Clone)]
+pub struct Highlighted<'tcx, T> {
+ tcx: TyCtxt<'tcx>,
+ highlight: RegionHighlightMode<'tcx>,
+ value: T,
+}
+
+impl<'tcx, T> IntoDiagnosticArg for Highlighted<'tcx, T>
+where
+ T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
+{
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ rustc_errors::DiagnosticArgValue::Str(self.to_string().into())
+ }
+}
+
+impl<'tcx, T> Highlighted<'tcx, T> {
+ fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
+ Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
+ }
+}
+
+impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
+where
+ T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
+ printer.region_highlight_mode = self.highlight;
+
+ let s = self.value.print(printer)?.into_buffer();
+ f.write_str(&s)
+ }
+}
impl<'tcx> NiceRegionError<'_, 'tcx> {
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
actual_substs: SubstsRef<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let span = cause.span();
- let msg = format!(
- "implementation of `{}` is not general enough",
- self.tcx().def_path_str(trait_def_id),
- );
- let mut err = self.tcx().sess.struct_span_err(span, &msg);
-
- let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id)
- | ObligationCauseCode::ExprItemObligation(def_id, ..) =
- *cause.code()
- {
- err.span_label(span, "doesn't satisfy where-clause");
- err.span_label(
- self.tcx().def_span(def_id),
- &format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)),
- );
- true
- } else {
- err.span_label(span, &msg);
- false
- };
+
+ let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
+ if let ObligationCauseCode::ItemObligation(def_id)
+ | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code()
+ {
+ (
+ true,
+ Some(span),
+ Some(self.tcx().def_span(def_id)),
+ None,
+ self.tcx().def_path_str(def_id),
+ )
+ } else {
+ (false, None, None, Some(span), String::new())
+ };
let expected_trait_ref = self
.cx
?expected_self_ty_has_vid,
);
- self.explain_actual_impl_that_was_found(
- &mut err,
+ let actual_impl_expl_notes = self.explain_actual_impl_that_was_found(
sub_placeholder,
sup_placeholder,
has_sub,
leading_ellipsis,
);
- err
+ self.tcx().sess.create_err(TraitPlaceholderMismatch {
+ span,
+ satisfy_span,
+ where_span,
+ dup_span,
+ def_id,
+ trait_def_id: self.tcx().def_path_str(trait_def_id),
+ actual_impl_expl_notes,
+ })
}
/// Add notes with details about the expected and actual trait refs, with attention to cases
/// due to the number of combinations we have to deal with.
fn explain_actual_impl_that_was_found(
&self,
- err: &mut Diagnostic,
sub_placeholder: Option<Region<'tcx>>,
sup_placeholder: Option<Region<'tcx>>,
has_sub: Option<usize>,
actual_has_vid: Option<usize>,
any_self_ty_has_vid: bool,
leading_ellipsis: bool,
- ) {
- // HACK(eddyb) maybe move this in a more central location.
- #[derive(Copy, Clone)]
- struct Highlighted<'tcx, T> {
- tcx: TyCtxt<'tcx>,
- highlight: RegionHighlightMode<'tcx>,
- value: T,
- }
-
- impl<'tcx, T> Highlighted<'tcx, T> {
- fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
- Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
- }
- }
-
- impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
- where
- T: for<'a> Print<
- 'tcx,
- FmtPrinter<'a, 'tcx>,
- Error = fmt::Error,
- Output = FmtPrinter<'a, 'tcx>,
- >,
- {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
- printer.region_highlight_mode = self.highlight;
-
- let s = self.value.print(printer)?.into_buffer();
- f.write_str(&s)
- }
- }
-
+ ) -> Vec<ActualImplExplNotes<'tcx>> {
// The weird thing here with the `maybe_highlighting_region` calls and the
// the match inside is meant to be like this:
//
let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
- err.note(&{
- let passive_voice = match (has_sub, has_sup) {
- (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
- (None, None) => {
- expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
- match expected_has_vid {
- Some(_) => true,
- None => any_self_ty_has_vid,
- }
- }
- };
- let mut note = if same_self_type {
- let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
- self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
-
- if self_ty.value.is_closure()
- && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
- {
- let closure_sig = self_ty.map(|closure| {
- if let ty::Closure(_, substs) = closure.kind() {
- self.tcx().signature_unclosure(
- substs.as_closure().sig(),
- rustc_hir::Unsafety::Normal,
- )
- } else {
- bug!("type is not longer closure");
- }
- });
-
- format!(
- "{}closure with signature `{}` must implement `{}`",
- if leading_ellipsis { "..." } else { "" },
- closure_sig,
- expected_trait_ref.map(|tr| tr.print_only_trait_path()),
- )
- } else {
- format!(
- "{}`{}` must implement `{}`",
- if leading_ellipsis { "..." } else { "" },
- self_ty,
- expected_trait_ref.map(|tr| tr.print_only_trait_path()),
- )
+ let passive_voice = match (has_sub, has_sup) {
+ (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
+ (None, None) => {
+ expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
+ match expected_has_vid {
+ Some(_) => true,
+ None => any_self_ty_has_vid,
}
- } else if passive_voice {
- format!(
- "{}`{}` would have to be implemented for the type `{}`",
- if leading_ellipsis { "..." } else { "" },
+ }
+ };
+
+ let (kind, ty_or_sig, trait_path) = if same_self_type {
+ let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
+ self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
+
+ if self_ty.value.is_closure() && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
+ {
+ let closure_sig = self_ty.map(|closure| {
+ if let ty::Closure(_, substs) = closure.kind() {
+ self.tcx().signature_unclosure(
+ substs.as_closure().sig(),
+ rustc_hir::Unsafety::Normal,
+ )
+ } else {
+ bug!("type is not longer closure");
+ }
+ });
+ (
+ ActualImplExpectedKind::Signature,
+ TyOrSig::ClosureSig(closure_sig),
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
- expected_trait_ref.map(|tr| tr.self_ty()),
)
} else {
- format!(
- "{}`{}` must implement `{}`",
- if leading_ellipsis { "..." } else { "" },
- expected_trait_ref.map(|tr| tr.self_ty()),
+ (
+ ActualImplExpectedKind::Other,
+ TyOrSig::Ty(self_ty),
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
)
- };
+ }
+ } else if passive_voice {
+ (
+ ActualImplExpectedKind::Passive,
+ TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
+ expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+ )
+ } else {
+ (
+ ActualImplExpectedKind::Other,
+ TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
+ expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+ )
+ };
- match (has_sub, has_sup) {
- (Some(n1), Some(n2)) => {
- let _ = write!(
- note,
- ", for any two lifetimes `'{}` and `'{}`...",
- std::cmp::min(n1, n2),
- std::cmp::max(n1, n2),
- );
- }
- (Some(n), _) | (_, Some(n)) => {
- let _ = write!(note, ", for any lifetime `'{}`...", n,);
- }
- (None, None) => {
- if let Some(n) = expected_has_vid {
- let _ = write!(note, ", for some specific lifetime `'{}`...", n,);
- }
+ let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) {
+ (Some(n1), Some(n2)) => {
+ (ActualImplExpectedLifetimeKind::Two, std::cmp::min(n1, n2), std::cmp::max(n1, n2))
+ }
+ (Some(n), _) | (_, Some(n)) => (ActualImplExpectedLifetimeKind::Any, n, 0),
+ (None, None) => {
+ if let Some(n) = expected_has_vid {
+ (ActualImplExpectedLifetimeKind::Some, n, 0)
+ } else {
+ (ActualImplExpectedLifetimeKind::Nothing, 0, 0)
}
}
+ };
- note
- });
+ let note_1 = ActualImplExplNotes::new_expected(
+ kind,
+ lt_kind,
+ leading_ellipsis,
+ ty_or_sig,
+ trait_path,
+ lifetime_1,
+ lifetime_2,
+ );
let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);
- err.note(&{
- let passive_voice = match actual_has_vid {
- Some(_) => any_self_ty_has_vid,
- None => true,
- };
- let mut note = if same_self_type {
- format!(
- "...but it actually implements `{}`",
- actual_trait_ref.map(|tr| tr.print_only_trait_path()),
- )
- } else if passive_voice {
- format!(
- "...but `{}` is actually implemented for the type `{}`",
- actual_trait_ref.map(|tr| tr.print_only_trait_path()),
- actual_trait_ref.map(|tr| tr.self_ty()),
- )
- } else {
- format!(
- "...but `{}` actually implements `{}`",
- actual_trait_ref.map(|tr| tr.self_ty()),
- actual_trait_ref.map(|tr| tr.print_only_trait_path()),
- )
- };
+ let passive_voice = match actual_has_vid {
+ Some(_) => any_self_ty_has_vid,
+ None => true,
+ };
- if let Some(n) = actual_has_vid {
- let _ = write!(note, ", for some specific lifetime `'{}`", n);
+ let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path());
+ let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string();
+ let has_lifetime = actual_has_vid.is_some();
+ let lifetime = actual_has_vid.unwrap_or_default();
+
+ let note_2 = if same_self_type {
+ ActualImplExplNotes::ButActuallyImplementsTrait { trait_path, has_lifetime, lifetime }
+ } else if passive_voice {
+ ActualImplExplNotes::ButActuallyImplementedForTy {
+ trait_path,
+ ty,
+ has_lifetime,
+ lifetime,
}
+ } else {
+ ActualImplExplNotes::ButActuallyTyImplements { trait_path, ty, has_lifetime, lifetime }
+ };
- note
- });
+ vec![note_1, note_2]
}
}
//! Error Reporting for static impl Traits.
+use crate::errors::{
+ ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted,
+ ReqIntroducedLocations,
+};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_ty, Visitor};
-use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
+use rustc_hir::{
+ self as hir, GenericBound, GenericParamKind, Item, ItemKind, Lifetime, LifetimeName, Node,
+ TyKind,
+};
use rustc_middle::ty::{
self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
};
use rustc_span::symbol::Ident;
use rustc_span::Span;
+use rustc_span::def_id::LocalDefId;
use std::ops::ControlFlow;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
let param = self.find_param_with_region(*sup_r, *sub_r)?;
- let lifetime = if sup_r.has_name() {
- format!("lifetime `{}`", sup_r)
- } else {
- "an anonymous lifetime `'_`".to_string()
+ let simple_ident = param.param.pat.simple_ident();
+
+ let (has_impl_path, impl_path) = match ctxt.assoc_item.container {
+ AssocItemContainer::TraitContainer => {
+ let id = ctxt.assoc_item.container_id(tcx);
+ (true, tcx.def_path_str(id))
+ }
+ AssocItemContainer::ImplContainer => (false, String::new()),
};
- let mut err = struct_span_err!(
- tcx.sess,
- cause.span,
- E0772,
- "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
- requirement",
- param
- .param
- .pat
- .simple_ident()
- .map(|s| format!("`{}`", s))
- .unwrap_or_else(|| "`fn` parameter".to_string()),
- lifetime,
- ctxt.assoc_item.name,
- );
- err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
- err.span_label(
- cause.span,
- &format!(
- "...is used and required to live as long as `'static` here \
- because of an implicit lifetime bound on the {}",
- match ctxt.assoc_item.container {
- AssocItemContainer::TraitContainer => {
- let id = ctxt.assoc_item.container_id(tcx);
- format!("`impl` of `{}`", tcx.def_path_str(id))
- }
- AssocItemContainer::ImplContainer => "inherent `impl`".to_string(),
- },
- ),
- );
+
+ let mut err = self.tcx().sess.create_err(ButCallingIntroduces {
+ param_ty_span: param.param_ty_span,
+ cause_span: cause.span,
+ has_param_name: simple_ident.is_some(),
+ param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(),
+ has_lifetime: sup_r.has_name(),
+ lifetime: sup_r.to_string(),
+ assoc_item: ctxt.assoc_item.name,
+ has_impl_path,
+ impl_path,
+ });
if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
let reported = err.emit();
return Some(reported);
} else {
- err.cancel();
+ err.cancel()
}
}
return None;
let sp = var_origin.span();
let return_sp = sub_origin.span();
let param = 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 param_name = param
- .param
- .pat
- .simple_ident()
- .map(|s| format!("`{}`", s))
- .unwrap_or_else(|| "`fn` parameter".to_string());
- let mut err = struct_span_err!(
- tcx.sess,
- sp,
- E0759,
- "{} has {} but it needs to satisfy a `'static` lifetime requirement",
- param_name,
- lifetime,
- );
+ let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
let (mention_influencer, influencer_point) =
if sup_origin.span().overlaps(param.param_ty_span) {
} else {
(!sup_origin.span().overlaps(return_sp), param.param_ty_span)
};
- err.span_label(influencer_point, &format!("this data with {}...", lifetime));
debug!("try_report_static_impl_trait: param_info={:?}", param);
spans.dedup_by_key(|span| (span.lo(), span.hi()));
// We try to make the output have fewer overlapping spans if possible.
- let require_msg = if spans.is_empty() {
- "...is used and required to live as long as `'static` here"
- } else {
- "...and is required to live as long as `'static` here"
- };
let require_span =
if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp };
- for span in &spans {
- err.span_label(*span, "...is used here...");
- }
-
- if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) {
- // If any of the "captured here" labels appears on the same line or after
- // `require_span`, we put it on a note to ensure the text flows by appearing
- // always at the end.
- err.span_note(require_span, require_msg);
+ let spans_empty = spans.is_empty();
+ let require_as_note = spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp);
+ let bound = if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
+ Some(*bound)
} else {
- // We don't need a note, it's already at the end, it can be shown as a `span_label`.
- err.span_label(require_span, require_msg);
- }
+ None
+ };
+
+ let mut subdiag = None;
- if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
- err.span_note(*bound, "`'static` lifetime requirement introduced by this bound");
- }
if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin {
if let ObligationCauseCode::ReturnValue(hir_id)
| ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
let parent_id = tcx.hir().get_parent_item(*hir_id);
if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
let mut span: MultiSpan = fn_decl.output.span().into();
+ let mut spans = Vec::new();
let mut add_label = true;
if let hir::FnRetTy::Return(ty) = fn_decl.output {
let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
v.visit_ty(ty);
if !v.0.is_empty() {
span = v.0.clone().into();
- for sp in v.0 {
- span.push_span_label(sp, "`'static` requirement introduced here");
- }
+ spans = v.0;
add_label = false;
}
}
- if add_label {
- span.push_span_label(
- fn_decl.output.span(),
- "requirement introduced by this return type",
- );
- }
- span.push_span_label(cause.span, "because of this returned expression");
- err.span_note(
+ let fn_decl_span = fn_decl.output.span();
+
+ subdiag = Some(ReqIntroducedLocations {
span,
- "`'static` lifetime requirement introduced by the return type",
- );
+ spans,
+ fn_decl_span,
+ cause_span: cause.span,
+ add_label,
+ });
}
}
}
+ let diag = ButNeedsToSatisfy {
+ sp,
+ influencer_point,
+ spans: spans.clone(),
+ // If any of the "captured here" labels appears on the same line or after
+ // `require_span`, we put it on a note to ensure the text flows by appearing
+ // always at the end.
+ require_span_as_note: require_as_note.then_some(require_span),
+ // We don't need a note, it's already at the end, it can be shown as a `span_label`.
+ require_span_as_label: (!require_as_note).then_some(require_span),
+ req_introduces_loc: subdiag,
+
+ has_lifetime: sup_r.has_name(),
+ lifetime: sup_r.to_string(),
+ spans_empty,
+ bound,
+ };
+
+ let mut err = self.tcx().sess.create_err(diag);
+
let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
let mut override_error_code = None;
let mut v = TraitObjectVisitor(FxIndexSet::default());
v.visit_ty(param.param_ty);
if let Some((ident, self_ty)) =
- self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0)
+ NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, item_def_id, &v.0)
&& self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty)
{
override_error_code = Some(ident.name);
}
if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) {
// Provide a more targeted error code and description.
- err.code(rustc_errors::error_code!(E0772));
- err.set_primary_message(&format!(
- "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
- requirement",
- param_name, lifetime, ident,
- ));
+ let retarget_subdiag = MoreTargeted { ident };
+ retarget_subdiag.add_to_diagnostic(&mut err);
}
let arg = match param.param.pat.simple_ident() {
Some(arg),
captures,
Some((param.param_ty_span, param.param_ty.to_string())),
+ Some(anon_reg_sup.def_id),
);
let reported = err.emit();
arg: Option<String>,
captures: String,
param: Option<(Span, String)>,
+ scope_def_id: Option<LocalDefId>,
) {
debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
let did = item_id.owner_id.to_def_id();
let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did));
- if let Some(span) = opaque
- .bounds
- .iter()
- .filter_map(|arg| match arg {
- GenericBound::Outlives(Lifetime {
- res: LifetimeName::Static,
- ident,
- ..
- }) => Some(ident.span),
- _ => None,
- })
- .next()
- {
+ if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg {
+ GenericBound::Outlives(Lifetime {
+ res: LifetimeName::Static, ident, ..
+ }) => Some(ident.span),
+ _ => None,
+ }) {
if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose(
span,
Applicability::MaybeIncorrect,
);
}
- } else if opaque
- .bounds
- .iter()
- .filter_map(|arg| match arg {
- GenericBound::Outlives(Lifetime { ident, .. })
- if ident.name.to_string() == lifetime_name =>
- {
- Some(ident.span)
- }
- _ => None,
- })
- .next()
- .is_some()
- {
+ } else if opaque.bounds.iter().any(|arg| match arg {
+ GenericBound::Outlives(Lifetime { ident, .. })
+ if ident.name.to_string() == lifetime_name =>
+ {
+ true
+ }
+ _ => false,
+ }) {
} else {
- err.span_suggestion_verbose(
- fn_return.span.shrink_to_hi(),
- &format!("{declare} `{ty}` {captures}, {explicit}",),
- &plus_lt,
- Applicability::MaybeIncorrect,
- );
+ // get a lifetime name of existing named lifetimes if any
+ let existing_lt_name = if let Some(id) = scope_def_id
+ && let Some(generics) = tcx.hir().get_generics(id)
+ && let named_lifetimes = generics
+ .params
+ .iter()
+ .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }))
+ .map(|p| { if let hir::ParamName::Plain(name) = p.name {Some(name.to_string())} else {None}})
+ .filter(|n| ! matches!(n, None))
+ .collect::<Vec<_>>()
+ && named_lifetimes.len() > 0 {
+ named_lifetimes[0].clone()
+ } else {
+ None
+ };
+ let name = if let Some(name) = &existing_lt_name {
+ format!("{}", name)
+ } else {
+ format!("'a")
+ };
+ // if there are more than one elided lifetimes in inputs, the explicit `'_` lifetime cannot be used.
+ // introducing a new lifetime `'a` or making use of one from existing named lifetimes if any
+ if let Some(id) = scope_def_id
+ && let Some(generics) = tcx.hir().get_generics(id)
+ && let mut spans_suggs = generics
+ .params
+ .iter()
+ .filter(|p| p.is_elided_lifetime())
+ .map(|p|
+ if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) { // Ampersand (elided without '_)
+ (p.span.shrink_to_hi(),format!("{name} "))
+ } else { // Underscore (elided with '_)
+ (p.span, format!("{name}"))
+ }
+ )
+ .collect::<Vec<_>>()
+ && spans_suggs.len() > 1
+ {
+ let use_lt =
+ if existing_lt_name == None {
+ spans_suggs.push((generics.span.shrink_to_hi(), format!("<{name}>")));
+ format!("you can introduce a named lifetime parameter `{name}`")
+ } else {
+ // make use the existing named lifetime
+ format!("you can use the named lifetime parameter `{name}`")
+ };
+ spans_suggs
+ .push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
+ err.multipart_suggestion_verbose(
+ &format!(
+ "{declare} `{ty}` {captures}, {use_lt}",
+ ),
+ spans_suggs,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_suggestion_verbose(
+ fn_return.span.shrink_to_hi(),
+ &format!("{declare} `{ty}` {captures}, {explicit}",),
+ &plus_lt,
+ Applicability::MaybeIncorrect,
+ );
+ }
}
}
TyKind::TraitObject(_, lt, _) => {
}
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
- fn get_impl_ident_and_self_ty_from_trait(
- &self,
+ pub fn get_impl_ident_and_self_ty_from_trait(
+ tcx: TyCtxt<'tcx>,
def_id: DefId,
trait_objects: &FxIndexSet<DefId>,
) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
- let tcx = self.tcx();
- match tcx.hir().get_if_local(def_id) {
- Some(Node::ImplItem(impl_item)) => {
- match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
+ match tcx.hir().get_if_local(def_id)? {
+ Node::ImplItem(impl_item) => {
+ let impl_did = tcx.hir().get_parent_item(impl_item.hir_id());
+ if let hir::OwnerNode::Item(Item {
+ kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+ ..
+ }) = tcx.hir().owner(impl_did)
{
- Some(Node::Item(Item {
- kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
- ..
- })) => Some((impl_item.ident, self_ty)),
- _ => None,
+ Some((impl_item.ident, self_ty))
+ } else {
+ None
}
}
- Some(Node::TraitItem(trait_item)) => {
- let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
- match tcx.hir().find_by_def_id(trait_did.def_id) {
- Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
- // The method being called is defined in the `trait`, but the `'static`
- // obligation comes from the `impl`. Find that `impl` so that we can point
- // at it in the suggestion.
- let trait_did = trait_did.to_def_id();
- match tcx
- .hir()
- .trait_impls(trait_did)
- .iter()
- .filter_map(|&impl_did| {
- match tcx.hir().get_if_local(impl_did.to_def_id()) {
- Some(Node::Item(Item {
- kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
- ..
- })) if trait_objects.iter().all(|did| {
- // FIXME: we should check `self_ty` against the receiver
- // type in the `UnifyReceiver` context, but for now, use
- // this imperfect proxy. This will fail if there are
- // multiple `impl`s for the same trait like
- // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
- // In that case, only the first one will get suggestions.
- let mut traits = vec![];
- let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
- hir_v.visit_ty(self_ty);
- !traits.is_empty()
- }) =>
- {
- Some(self_ty)
- }
- _ => None,
- }
- })
- .next()
- {
- Some(self_ty) => Some((trait_item.ident, self_ty)),
- _ => None,
- }
+ Node::TraitItem(trait_item) => {
+ let trait_id = tcx.hir().get_parent_item(trait_item.hir_id());
+ debug_assert_eq!(tcx.def_kind(trait_id.def_id), hir::def::DefKind::Trait);
+ // The method being called is defined in the `trait`, but the `'static`
+ // obligation comes from the `impl`. Find that `impl` so that we can point
+ // at it in the suggestion.
+ let trait_did = trait_id.to_def_id();
+ tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
+ if let Node::Item(Item {
+ kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+ ..
+ }) = tcx.hir().find_by_def_id(impl_did)?
+ && trait_objects.iter().all(|did| {
+ // FIXME: we should check `self_ty` against the receiver
+ // type in the `UnifyReceiver` context, but for now, use
+ // this imperfect proxy. This will fail if there are
+ // multiple `impl`s for the same trait like
+ // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
+ // In that case, only the first one will get suggestions.
+ let mut traits = vec![];
+ let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
+ hir_v.visit_ty(self_ty);
+ !traits.is_empty()
+ })
+ {
+ Some((trait_item.ident, *self_ty))
+ } else {
+ None
}
- _ => None,
- }
+ })
}
_ => None,
}
// Get the `Ident` of the method being called and the corresponding `impl` (to point at
// `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
- let Some((ident, self_ty)) = self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0) else {
+ let Some((ident, self_ty)) = NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &v.0) else {
return false;
};
let mut traits = vec![];
let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
hir_v.visit_ty(&self_ty);
- for span in &traits {
- let mut multi_span: MultiSpan = vec![*span].into();
- multi_span
- .push_span_label(*span, "this has an implicit `'static` lifetime requirement");
- multi_span.push_span_label(
- ident.span,
- "calling this method introduces the `impl`'s 'static` requirement",
- );
- err.span_note(multi_span, "the used `impl` has a `'static` requirement");
- err.span_suggestion_verbose(
- span.shrink_to_hi(),
- "consider relaxing the implicit `'static` requirement",
- " + '_",
- Applicability::MaybeIncorrect,
- );
+ for &span in &traits {
+ let subdiag = DynTraitConstraintSuggestion { span, ident };
+ subdiag.add_to_diagnostic(err);
suggested = true;
}
}
//! Error Reporting for `impl` items that do not match the obligations from their `trait`.
+use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::Subtype;
+use crate::infer::{Subtype, ValuePairs};
use crate::traits::ObligationCauseCode::CompareImplItemObligation;
-use rustc_errors::{ErrorGuaranteed, MultiSpan};
+use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::print::RegionHighlightMode;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_span::Span;
let error = self.error.as_ref()?;
debug!("try_report_impl_not_conforming_to_trait {:?}", error);
if let RegionResolutionError::SubSupConflict(
- _,
- var_origin,
- sub_origin,
- _sub,
- sup_origin,
- _sup,
- _,
- ) = error.clone()
+ _,
+ var_origin,
+ sub_origin,
+ _sub,
+ sup_origin,
+ _sup,
+ _,
+ ) = error.clone()
&& let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
- && let sub_expected_found @ Some((sub_expected, sub_found)) = sub_trace.values.ty()
- && let sup_expected_found @ Some(_) = sup_trace.values.ty()
&& let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code()
- && sup_expected_found == sub_expected_found
+ && sub_trace.values == sup_trace.values
+ && let ValuePairs::Sigs(ExpectedFound { expected, found }) = sub_trace.values
{
- let guar =
- self.emit_err(var_origin.span(), sub_expected, sub_found, *trait_item_def_id);
+ // FIXME(compiler-errors): Don't like that this needs `Ty`s, but
+ // all of the region highlighting machinery only deals with those.
+ let guar = self.emit_err(
+ var_origin.span(),
+ self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(expected)),
+ self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(found)),
+ *trait_item_def_id,
+ );
return Some(guar);
}
None
trait_def_id: DefId,
) -> ErrorGuaranteed {
let trait_sp = self.tcx().def_span(trait_def_id);
- let mut err = self
- .tcx()
- .sess
- .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
// Mark all unnamed regions in the type with a number.
// This diagnostic is called in response to lifetime errors, so be informative.
let found =
self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
- err.span_label(sp, &format!("found `{}`", found));
- err.span_label(trait_sp, &format!("expected `{}`", expected));
-
// Get the span of all the used type parameters in the method.
let assoc_item = self.tcx().associated_item(trait_def_id);
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
}
_ => {}
}
- let mut type_param_span: MultiSpan = visitor.types.to_vec().into();
- for &span in &visitor.types {
- type_param_span
- .push_span_label(span, "consider borrowing this type parameter in the trait");
- }
- err.note(&format!("expected `{}`\n found `{}`", expected, found));
-
- err.span_help(
- type_param_span,
- "the lifetime requirements from the `impl` do not correspond to the requirements in \
- the `trait`",
- );
- if visitor.types.is_empty() {
- err.help(
- "verify the lifetime relationships in the `trait` and `impl` between the `self` \
- argument, the other inputs and its output",
- );
- }
- err.emit()
+ let diag = TraitImplDiff {
+ sp,
+ trait_sp,
+ note: (),
+ param_help: ConsiderBorrowingParamHelp { spans: visitor.types.to_vec() },
+ rel_help: visitor.types.is_empty().then_some(RelationshipHelp),
+ expected,
+ found,
+ };
+
+ self.tcx().sess.emit_err(diag)
}
}
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
match arg.kind {
- hir::TyKind::Rptr(_, ref mut_ty) => {
+ hir::TyKind::Ref(_, ref mut_ty) => {
// We don't want to suggest looking into borrowing `&T` or `&Self`.
hir::intravisit::walk_ty(self, mut_ty.ty);
return;
use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
use crate::infer::{self, SubregionOrigin};
use rustc_errors::{
- fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+ fluent, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder,
+ ErrorGuaranteed,
};
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::{self, Region};
+use rustc_middle::ty::{self, IsSuggestable, Region};
+use rustc_span::symbol::kw;
use super::ObligationCauseAsDiagArg;
infer::Reborrow(span) => {
RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
}
- infer::ReborrowUpvar(span, ref upvar_id) => {
- let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
- RegionOriginNote::WithName {
- span,
- msg: fluent::infer_reborrow,
- name: &var_name.to_string(),
- continues: false,
- }
- .add_to_diagnostic(err);
- }
infer::RelateObjectBound(span) => {
RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
.add_to_diagnostic(err);
);
err
}
- infer::ReborrowUpvar(span, ref upvar_id) => {
- let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0313,
- "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...",
- var_name
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "...the borrowed pointer is valid for ",
- sub,
- "...",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- &format!("...but `{}` is only valid for ", var_name),
- sup,
- "",
- None,
- );
- err
- }
infer::RelateObjectBound(span) => {
let mut err = struct_span_err!(
self.tcx.sess,
);
err
}
- infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
- .report_extra_impl_obligation(
+ infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
+ let mut err = self.report_extra_impl_obligation(
span,
impl_item_def_id,
trait_item_def_id,
&format!("`{}: {}`", sup, sub),
- ),
+ );
+ // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
+ if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
+ && generics.where_clause_span.contains(span)
+ {
+ self.suggest_copy_trait_method_bounds(
+ trait_item_def_id,
+ impl_item_def_id,
+ &mut err,
+ );
+ }
+ err
+ }
infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
let mut err = self.report_concrete_failure(*parent, sub, sup);
-
let trait_item_span = self.tcx.def_span(trait_item_def_id);
let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
err.span_label(
trait_item_span,
format!("definition of `{}` from trait", item_name),
);
-
- let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
- let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
-
- let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
- impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
- let clauses: Vec<_> = trait_predicates
- .predicates
- .into_iter()
- .filter(|&(pred, _)| !impl_predicates.contains(pred))
- .map(|(pred, _)| format!("{}", pred))
- .collect();
-
- if !clauses.is_empty() {
- let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
- let where_clause_span = generics.tail_span_for_predicate_suggestion();
-
- let suggestion = format!(
- "{} {}",
- generics.add_where_or_trailing_comma(),
- clauses.join(", "),
- );
- err.span_suggestion(
- where_clause_span,
- &format!(
- "try copying {} from the trait",
- if clauses.len() > 1 { "these clauses" } else { "this clause" }
- ),
- suggestion,
- rustc_errors::Applicability::MaybeIncorrect,
- );
- }
-
+ self.suggest_copy_trait_method_bounds(
+ trait_item_def_id,
+ impl_item_def_id,
+ &mut err,
+ );
err
}
infer::AscribeUserTypeProvePredicate(span) => {
}
}
+ pub fn suggest_copy_trait_method_bounds(
+ &self,
+ trait_item_def_id: DefId,
+ impl_item_def_id: LocalDefId,
+ err: &mut Diagnostic,
+ ) {
+ // FIXME(compiler-errors): Right now this is only being used for region
+ // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
+ // but right now it's not really very smart when it comes to implicit `Sized`
+ // predicates and bounds on the trait itself.
+
+ let Some(impl_def_id) =
+ self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx) else { return; };
+ let Some(trait_ref) = self
+ .tcx
+ .impl_trait_ref(impl_def_id)
+ else { return; };
+ let trait_substs = trait_ref
+ // Replace the explicit self type with `Self` for better suggestion rendering
+ .with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
+ .substs;
+ let trait_item_substs =
+ ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id.to_def_id())
+ .rebase_onto(self.tcx, impl_def_id, trait_substs);
+
+ let Ok(trait_predicates) = self
+ .tcx
+ .bound_explicit_predicates_of(trait_item_def_id)
+ .map_bound(|p| p.predicates)
+ .subst_iter_copied(self.tcx, trait_item_substs)
+ .map(|(pred, _)| {
+ if pred.is_suggestable(self.tcx, false) {
+ Ok(pred.to_string())
+ } else {
+ Err(())
+ }
+ })
+ .collect::<Result<Vec<_>, ()>>() else { return; };
+
+ let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { return; };
+
+ if trait_predicates.is_empty() {
+ err.span_suggestion_verbose(
+ generics.where_clause_span,
+ "remove the `where` clause",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ let space = if generics.where_clause_span.is_empty() { " " } else { "" };
+ err.span_suggestion_verbose(
+ generics.where_clause_span,
+ "copy the `where` clause predicates from the trait",
+ format!("{space}where {}", trait_predicates.join(", ")),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
pub(super) fn report_placeholder_failure(
&self,
placeholder_origin: SubregionOrigin<'tcx>,
+++ /dev/null
-use crate::errors::RegionOriginNote;
-use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
-use crate::infer::{self, SubregionOrigin};
-use rustc_errors::{
- fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-};
-use rustc_middle::traits::ObligationCauseCode;
-use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::{self, Region};
-
-use super::ObligationCauseAsDiagArg;
-
-impl<'tcx> TypeErrCtxt<'_, 'tcx> {
- pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
- match *origin {
- infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
- span: trace.cause.span,
- requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
- expected_found: self.values_str(trace.values),
- }
- .add_to_diagnostic(err),
- infer::Reborrow(span) => {
- RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
- }
- infer::ReborrowUpvar(span, ref upvar_id) => {
- let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
- RegionOriginNote::WithName {
- span,
- msg: fluent::infer_reborrow,
- name: &var_name.to_string(),
- continues: false,
- }
- .add_to_diagnostic(err);
- }
- infer::RelateObjectBound(span) => {
- RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
- .add_to_diagnostic(err);
- }
- infer::DataBorrowed(ty, span) => {
- RegionOriginNote::WithName {
- span,
- msg: fluent::infer_data_borrowed,
- name: &self.ty_to_string(ty),
- continues: false,
- }
- .add_to_diagnostic(err);
- }
- infer::ReferenceOutlivesReferent(ty, span) => {
- RegionOriginNote::WithName {
- span,
- msg: fluent::infer_reference_outlives_referent,
- name: &self.ty_to_string(ty),
- continues: false,
- }
- .add_to_diagnostic(err);
- }
- infer::RelateParamBound(span, ty, opt_span) => {
- RegionOriginNote::WithName {
- span,
- msg: fluent::infer_relate_param_bound,
- name: &self.ty_to_string(ty),
- continues: opt_span.is_some(),
- }
- .add_to_diagnostic(err);
- if let Some(span) = opt_span {
- RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
- .add_to_diagnostic(err);
- }
- }
- infer::RelateRegionParamBound(span) => {
- RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
- .add_to_diagnostic(err);
- }
- infer::CompareImplItemObligation { span, .. } => {
- RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
- .add_to_diagnostic(err);
- }
- infer::CheckAssociatedTypeBounds { ref parent, .. } => {
- self.note_region_origin(err, &parent);
- }
- infer::AscribeUserTypeProvePredicate(span) => {
- RegionOriginNote::Plain {
- span,
- msg: fluent::infer_ascribe_user_type_prove_predicate,
- }
- .add_to_diagnostic(err);
- }
- }
- }
-
- pub(super) fn report_concrete_failure(
- &self,
- origin: SubregionOrigin<'tcx>,
- sub: Region<'tcx>,
- sup: Region<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- match origin {
- infer::Subtype(box trace) => {
- let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
- let mut err = self.report_and_explain_type_error(trace, terr);
- match (*sub, *sup) {
- (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
- (ty::RePlaceholder(_), _) => {
- note_and_explain_region(
- self.tcx,
- &mut err,
- "",
- sup,
- " doesn't meet the lifetime requirements",
- None,
- );
- }
- (_, ty::RePlaceholder(_)) => {
- note_and_explain_region(
- self.tcx,
- &mut err,
- "the required lifetime does not necessarily outlive ",
- sub,
- "",
- None,
- );
- }
- _ => {
- note_and_explain_region(self.tcx, &mut err, "", sup, "...", None);
- note_and_explain_region(
- self.tcx,
- &mut err,
- "...does not necessarily outlive ",
- sub,
- "",
- None,
- );
- }
- }
- err
- }
- infer::Reborrow(span) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0312,
- "lifetime of reference outlives lifetime of borrowed content..."
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "...the reference is valid for ",
- sub,
- "...",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "...but the borrowed content is only valid for ",
- sup,
- "",
- None,
- );
- err
- }
- infer::ReborrowUpvar(span, ref upvar_id) => {
- let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0313,
- "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...",
- var_name
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "...the borrowed pointer is valid for ",
- sub,
- "...",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- &format!("...but `{}` is only valid for ", var_name),
- sup,
- "",
- None,
- );
- err
- }
- infer::RelateObjectBound(span) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0476,
- "lifetime of the source pointer does not outlive lifetime bound of the \
- object type"
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "object type is valid for ",
- sub,
- "",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "source pointer is only valid for ",
- sup,
- "",
- None,
- );
- err
- }
- infer::RelateParamBound(span, ty, opt_span) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0477,
- "the type `{}` does not fulfill the required lifetime",
- self.ty_to_string(ty)
- );
- match *sub {
- ty::ReStatic => note_and_explain_region(
- self.tcx,
- &mut err,
- "type must satisfy ",
- sub,
- if opt_span.is_some() { " as required by this binding" } else { "" },
- opt_span,
- ),
- _ => note_and_explain_region(
- self.tcx,
- &mut err,
- "type must outlive ",
- sub,
- if opt_span.is_some() { " as required by this binding" } else { "" },
- opt_span,
- ),
- }
- err
- }
- infer::RelateRegionParamBound(span) => {
- let mut err =
- struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
- note_and_explain_region(
- self.tcx,
- &mut err,
- "lifetime parameter instantiated with ",
- sup,
- "",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "but lifetime parameter must outlive ",
- sub,
- "",
- None,
- );
- err
- }
- infer::DataBorrowed(ty, span) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0490,
- "a value of type `{}` is borrowed for too long",
- self.ty_to_string(ty)
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "the type is valid for ",
- sub,
- "",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "but the borrow lasts for ",
- sup,
- "",
- None,
- );
- err
- }
- infer::ReferenceOutlivesReferent(ty, span) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0491,
- "in type `{}`, reference has a longer lifetime than the data it references",
- self.ty_to_string(ty)
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "the pointer is valid for ",
- sub,
- "",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "but the referenced data is only valid for ",
- sup,
- "",
- None,
- );
- err
- }
- infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
- .report_extra_impl_obligation(
- span,
- impl_item_def_id,
- trait_item_def_id,
- &format!("`{}: {}`", sup, sub),
- ),
- infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
- let mut err = self.report_concrete_failure(*parent, sub, sup);
-
- let trait_item_span = self.tcx.def_span(trait_item_def_id);
- let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
- err.span_label(
- trait_item_span,
- format!("definition of `{}` from trait", item_name),
- );
-
- let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
- let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
-
- let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
- impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
- let clauses: Vec<_> = trait_predicates
- .predicates
- .into_iter()
- .filter(|&(pred, _)| !impl_predicates.contains(pred))
- .map(|(pred, _)| format!("{}", pred))
- .collect();
-
- if !clauses.is_empty() {
- let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
- let where_clause_span = generics.tail_span_for_predicate_suggestion();
-
- let suggestion = format!(
- "{} {}",
- generics.add_where_or_trailing_comma(),
- clauses.join(", "),
- );
- err.span_suggestion(
- where_clause_span,
- &format!(
- "try copying {} from the trait",
- if clauses.len() > 1 { "these clauses" } else { "this clause" }
- ),
- suggestion,
- rustc_errors::Applicability::MaybeIncorrect,
- );
- }
-
- err
- }
- infer::AscribeUserTypeProvePredicate(span) => {
- let mut err =
- struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
- note_and_explain_region(
- self.tcx,
- &mut err,
- "lifetime instantiated with ",
- sup,
- "",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "but lifetime must outlive ",
- sub,
- "",
- None,
- );
- err
- }
- }
- }
-
- pub(super) fn report_placeholder_failure(
- &self,
- placeholder_origin: SubregionOrigin<'tcx>,
- sub: Region<'tcx>,
- sup: Region<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- // I can't think how to do better than this right now. -nikomatsakis
- debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
- match placeholder_origin {
- infer::Subtype(box ref trace)
- if matches!(
- &trace.cause.code().peel_derives(),
- ObligationCauseCode::BindingObligation(..)
- | ObligationCauseCode::ExprBindingObligation(..)
- ) =>
- {
- // Hack to get around the borrow checker because trace.cause has an `Rc`.
- if let ObligationCauseCode::BindingObligation(_, span)
- | ObligationCauseCode::ExprBindingObligation(_, span, ..) =
- &trace.cause.code().peel_derives()
- {
- let span = *span;
- let mut err = self.report_concrete_failure(placeholder_origin, sub, sup);
- err.span_note(span, "the lifetime requirement is introduced here");
- err
- } else {
- unreachable!()
- }
- }
- infer::Subtype(box trace) => {
- let terr = TypeError::RegionsPlaceholderMismatch;
- return self.report_and_explain_type_error(trace, terr);
- }
- _ => return self.report_concrete_failure(placeholder_origin, sub, sup),
- }
- }
-}
span: Span,
) {
let hir = self.tcx.hir();
- let fn_hir_id = hir.get_parent_node(cause.body_id);
+ let fn_hir_id = hir.parent_id(cause.body_id);
if let Some(node) = self.tcx.hir().find(fn_hir_id) &&
let hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(_sig, _, body_id), ..
let hir::StmtKind::Local(local) = &stmt.kind else { continue; };
local.pat.walk(&mut find_compatible_candidates);
}
- match hir.find(hir.get_parent_node(blk.hir_id)) {
- Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => {
- match hir.find(hir.get_parent_node(*hir_id)) {
- Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
- pat.walk(&mut find_compatible_candidates);
- }
- Some(
- hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
- | hir::Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Fn(_, body),
- ..
- })
- | hir::Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
- ..
- })
- | hir::Node::Expr(hir::Expr {
- kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
- ..
- }),
- ) => {
- for param in hir.body(*body).params {
- param.pat.walk(&mut find_compatible_candidates);
- }
- }
- Some(hir::Node::Expr(hir::Expr {
- kind:
- hir::ExprKind::If(
- hir::Expr { kind: hir::ExprKind::Let(let_), .. },
- then_block,
- _,
- ),
+ match hir.find_parent(blk.hir_id) {
+ Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => match hir.find_parent(*hir_id) {
+ Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
+ pat.walk(&mut find_compatible_candidates);
+ }
+ Some(
+ hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
+ | hir::Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(_, body), ..
+ })
+ | hir::Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
+ ..
+ })
+ | hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
..
- })) if then_block.hir_id == *hir_id => {
- let_.pat.walk(&mut find_compatible_candidates);
+ }),
+ ) => {
+ for param in hir.body(*body).params {
+ param.pat.walk(&mut find_compatible_candidates);
}
- _ => {}
}
- }
+ Some(hir::Node::Expr(hir::Expr {
+ kind:
+ hir::ExprKind::If(
+ hir::Expr { kind: hir::ExprKind::Let(let_), .. },
+ then_block,
+ _,
+ ),
+ ..
+ })) if then_block.hir_id == *hir_id => {
+ let_.pat.walk(&mut find_compatible_candidates);
+ }
+ _ => {}
+ },
_ => {}
}
Terms(ExpectedFound<ty::Term<'tcx>>),
TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
+ Sigs(ExpectedFound<ty::FnSig<'tcx>>),
}
impl<'tcx> ValuePairs<'tcx> {
/// Creating a pointer `b` to contents of another reference
Reborrow(Span),
- /// Creating a pointer `b` to contents of an upvar
- ReborrowUpvar(Span, ty::UpvarId),
-
/// Data with type `Ty<'tcx>` was borrowed
DataBorrowed(Ty<'tcx>, Span),
}
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+ /// Processes registered region obliations and resolves regions, reporting
+ /// any errors if any were raised. Prefer using this function over manually
+ /// calling `resolve_regions_and_report_errors`.
+ pub fn check_region_obligations_and_report_errors(
+ &self,
+ generic_param_scope: LocalDefId,
+ outlives_env: &OutlivesEnvironment<'tcx>,
+ ) -> Result<(), ErrorGuaranteed> {
+ self.process_registered_region_obligations(
+ outlives_env.region_bound_pairs(),
+ outlives_env.param_env,
+ );
+
+ self.resolve_regions_and_report_errors(generic_param_scope, outlives_env)
+ }
+
/// Process the region constraints and report any errors that
/// result. After this, no more unification operations should be
/// done -- or the compiler will panic -- but it is legal to use
/// `resolve_vars_if_possible` as well as `fully_resolve`.
///
/// Make sure to call [`InferCtxt::process_registered_region_obligations`]
- /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`]
+ /// first, or preferably use [`TypeErrCtxt::check_region_obligations_and_report_errors`]
/// to do both of these operations together.
pub fn resolve_regions_and_report_errors(
&self,
generic_param_scope: LocalDefId,
outlives_env: &OutlivesEnvironment<'tcx>,
- ) -> Option<ErrorGuaranteed> {
+ ) -> Result<(), ErrorGuaranteed> {
let errors = self.resolve_regions(outlives_env);
if let None = self.tainted_by_errors() {
self.report_region_errors(generic_param_scope, &errors);
}
- (!errors.is_empty()).then(|| {
- self.tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted")
- })
+ if errors.is_empty() {
+ Ok(())
+ } else {
+ Err(self
+ .tcx
+ .sess
+ .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"))
+ }
}
// [Note-Type-error-reporting]
RelateParamBound(a, ..) => a,
RelateRegionParamBound(a) => a,
Reborrow(a) => a,
- ReborrowUpvar(a, _) => a,
DataBorrowed(_, a) => a,
ReferenceOutlivesReferent(_, a) => a,
CompareImplItemObligation { span, .. } => span,
+++ /dev/null
-impl<'tcx> TypeErrCtxt<'_, 'tcx> {
- fn note_error_origin(
- &self,
- err: &mut Diagnostic,
- cause: &ObligationCause<'tcx>,
- exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
- terr: TypeError<'tcx>,
- ) {
- match *cause.code() {
- ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
- let ty = self.resolve_vars_if_possible(root_ty);
- if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)))
- {
- // don't show type `_`
- if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
- && let ty::Adt(def, substs) = ty.kind()
- && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
- {
- err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
- } else {
- err.span_label(span, format!("this expression has type `{}`", ty));
- }
- }
- if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
- && ty.is_box() && ty.boxed_ty() == found
- && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
- {
- err.span_suggestion(
- span,
- "consider dereferencing the boxed value",
- format!("*{}", snippet),
- Applicability::MachineApplicable,
- );
- }
- }
- ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => {
- err.span_label(span, "expected due to this");
- }
- ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
- arm_block_id,
- arm_span,
- arm_ty,
- prior_arm_block_id,
- prior_arm_span,
- prior_arm_ty,
- source,
- ref prior_arms,
- scrut_hir_id,
- opt_suggest_box_span,
- scrut_span,
- ..
- }) => match source {
- hir::MatchSource::TryDesugar => {
- if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
- let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
- let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
- let arg_expr = args.first().expect("try desugaring call w/out arg");
- self.typeck_results.as_ref().and_then(|typeck_results| {
- typeck_results.expr_ty_opt(arg_expr)
- })
- } else {
- bug!("try desugaring w/out call expr as scrutinee");
- };
-
- match scrut_ty {
- Some(ty) if expected == ty => {
- let source_map = self.tcx.sess.source_map();
- err.span_suggestion(
- source_map.end_point(cause.span),
- "try removing this `?`",
- "",
- Applicability::MachineApplicable,
- );
- }
- _ => {}
- }
- }
- }
- _ => {
- // `prior_arm_ty` can be `!`, `expected` will have better info when present.
- let t = self.resolve_vars_if_possible(match exp_found {
- Some(ty::error::ExpectedFound { expected, .. }) => expected,
- _ => prior_arm_ty,
- });
- let source_map = self.tcx.sess.source_map();
- let mut any_multiline_arm = source_map.is_multiline(arm_span);
- if prior_arms.len() <= 4 {
- for sp in prior_arms {
- any_multiline_arm |= source_map.is_multiline(*sp);
- err.span_label(*sp, format!("this is found to be of type `{}`", t));
- }
- } else if let Some(sp) = prior_arms.last() {
- any_multiline_arm |= source_map.is_multiline(*sp);
- err.span_label(
- *sp,
- format!("this and all prior arms are found to be of type `{}`", t),
- );
- }
- let outer_error_span = if any_multiline_arm {
- // Cover just `match` and the scrutinee expression, not
- // the entire match body, to reduce diagram noise.
- cause.span.shrink_to_lo().to(scrut_span)
- } else {
- cause.span
- };
- let msg = "`match` arms have incompatible types";
- err.span_label(outer_error_span, msg);
- self.suggest_remove_semi_or_return_binding(
- err,
- prior_arm_block_id,
- prior_arm_ty,
- prior_arm_span,
- arm_block_id,
- arm_ty,
- arm_span,
- );
- if let Some(ret_sp) = opt_suggest_box_span {
- // Get return type span and point to it.
- self.suggest_boxing_for_return_impl_trait(
- err,
- ret_sp,
- prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
- );
- }
- }
- },
- ObligationCauseCode::IfExpression(box IfExpressionCause {
- then_id,
- else_id,
- then_ty,
- else_ty,
- outer_span,
- opt_suggest_box_span,
- }) => {
- let then_span = self.find_block_span_from_hir_id(then_id);
- let else_span = self.find_block_span_from_hir_id(else_id);
- err.span_label(then_span, "expected because of this");
- if let Some(sp) = outer_span {
- err.span_label(sp, "`if` and `else` have incompatible types");
- }
- self.suggest_remove_semi_or_return_binding(
- err,
- Some(then_id),
- then_ty,
- then_span,
- Some(else_id),
- else_ty,
- else_span,
- );
- if let Some(ret_sp) = opt_suggest_box_span {
- self.suggest_boxing_for_return_impl_trait(
- err,
- ret_sp,
- [then_span, else_span].into_iter(),
- );
- }
- }
- ObligationCauseCode::LetElse => {
- err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
- err.help("...or use `match` instead of `let...else`");
- }
- _ => {
- if let ObligationCauseCode::BindingObligation(_, span)
- | ObligationCauseCode::ExprBindingObligation(_, span, ..)
- = cause.code().peel_derives()
- && let TypeError::RegionsPlaceholderMismatch = terr
- {
- err.span_note( * span,
- "the lifetime requirement is introduced here");
- }
- }
- }
- }
-}
-
-impl<'tcx> InferCtxt<'tcx> {
- /// Given a [`hir::Block`], get the span of its last expression or
- /// statement, peeling off any inner blocks.
- pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span {
- let block = block.innermost_block();
- if let Some(expr) = &block.expr {
- expr.span
- } else if let Some(stmt) = block.stmts.last() {
- // possibly incorrect trailing `;` in the else arm
- stmt.span
- } else {
- // empty block; point at its entirety
- block.span
- }
- }
-
- /// Given a [`hir::HirId`] for a block, get the span of its last expression
- /// or statement, peeling off any inner blocks.
- pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span {
- match self.tcx.hir().get(hir_id) {
- hir::Node::Block(blk) => self.find_block_span(blk),
- // The parser was in a weird state if either of these happen, but
- // it's better not to panic.
- hir::Node::Expr(e) => e.span,
- _ => rustc_span::DUMMY_SP,
- }
- }
-}
.as_local()
.map_or(false, |def_id| self.opaque_type_origin(def_id, span).is_some())
};
- let value = value.fold_with(&mut ty::fold::BottomUpFolder {
+ let value = value.fold_with(&mut BottomUpFolder {
tcx: self.tcx,
lt_op: |lt| lt,
ct_op: |ct| ct,
//! imply that `'b: 'a`.
use crate::infer::outlives::components::{push_outlives_components, Component};
-use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::outlives::env::RegionBoundPairs;
use crate::infer::outlives::verify::VerifyBoundCx;
use crate::infer::{
};
use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_data_structures::undo_log::UndoLogs;
-use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::DefId;
-use rustc_hir::def_id::LocalDefId;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable};
std::mem::take(&mut self.inner.borrow_mut().region_obligations)
}
- /// NOTE: Prefer using [`InferCtxt::check_region_obligations_and_report_errors`]
+ /// NOTE: Prefer using `TypeErrCtxt::check_region_obligations_and_report_errors`
/// instead of calling this directly.
///
/// Process the region obligations that must be proven (during
outlives.type_must_outlive(origin, sup_type, sub_region, category);
}
}
-
- /// Processes registered region obliations and resolves regions, reporting
- /// any errors if any were raised. Prefer using this function over manually
- /// calling `resolve_regions_and_report_errors`.
- pub fn check_region_obligations_and_report_errors(
- &self,
- generic_param_scope: LocalDefId,
- outlives_env: &OutlivesEnvironment<'tcx>,
- ) -> Option<ErrorGuaranteed> {
- self.process_registered_region_obligations(
- outlives_env.region_bound_pairs(),
- outlives_env.param_env,
- );
-
- self.err_ctxt().resolve_regions_and_report_errors(generic_param_scope, outlives_env)
- }
}
/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
//! origin crate when the `TyCtxt` is not present in TLS.
use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
+use rustc_middle::dep_graph::TaskDepsRef;
use rustc_middle::ty::tls;
use std::fmt;
/// This is a callback from `rustc_ast` as it cannot access the implicit state
/// in `rustc_middle` otherwise. It is used when diagnostic messages are
/// emitted and stores them in the current query, if there is one.
-fn track_diagnostic(diagnostic: &Diagnostic) {
+fn track_diagnostic(diagnostic: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
tls::with_context_opt(|icx| {
if let Some(icx) = icx {
if let Some(diagnostics) = icx.diagnostics {
let mut diagnostics = diagnostics.lock();
diagnostics.extend(Some(diagnostic.clone()));
+ std::mem::drop(diagnostics);
}
+
+ // Diagnostics are tracked, we can ignore the dependency.
+ let icx = tls::ImplicitCtxt { task_deps: TaskDepsRef::Ignore, ..icx.clone() };
+ return tls::enter_context(&icx, move |_| (*f)(diagnostic));
}
+
+ // In any other case, invoke diagnostics anyway.
+ (*f)(diagnostic);
})
}
pub fn setup_callbacks() {
rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
- TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_)));
+ TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _));
}
.into_iter()
.map(|s| {
let sess = ParseSess::with_silent_emitter(Some(format!(
- "this error occurred on the command line: `--cfg={}`",
- s
+ "this error occurred on the command line: `--cfg={s}`"
)));
let filename = FileName::cfg_spec_source_code(&s);
'specs: for s in specs {
let sess = ParseSess::with_silent_emitter(Some(format!(
- "this error occurred on the command line: `--check-cfg={}`",
- s
+ "this error occurred on the command line: `--check-cfg={s}`"
)));
let filename = FileName::cfg_spec_source_code(&s);
// prevents `make` from spitting out an error if a file is later
// deleted. For more info see #28735
for path in files {
- writeln!(file, "{}:", path)?;
+ writeln!(file, "{path}:")?;
}
// Emit special comments with information about accessed environment variables.
envs.sort_unstable();
writeln!(file)?;
for (k, v) in envs {
- write!(file, "# env-dep:{}", k)?;
+ write!(file, "# env-dep:{k}")?;
if let Some(v) = v {
- write!(file, "={}", v)?;
+ write!(file, "={v}")?;
}
writeln!(file)?;
}
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
-use rustc_session::config::InstrumentCoverage;
-use rustc_session::config::Strip;
+use rustc_session::config::rustc_optgroups;
+use rustc_session::config::TraitSolver;
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
-use rustc_session::config::{
- rustc_optgroups, ErrorOutputType, ExternLocation, LocationDetail, Options, Passes,
-};
use rustc_session::config::{
BranchProtection, Externs, OomStrategy, OutputType, OutputTypes, PAuthKey, PacRet,
ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel,
};
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
+use rustc_session::config::{DumpMonoStatsFormat, MirSpanview};
+use rustc_session::config::{ErrorOutputType, ExternLocation, LocationDetail, Options, Strip};
+use rustc_session::config::{InstrumentCoverage, Passes};
use rustc_session::lint::Level;
use rustc_session::search_paths::SearchPath;
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
untracked!(dump_mir_dir, String::from("abc"));
untracked!(dump_mir_exclude_pass_number, true);
untracked!(dump_mir_graphviz, true);
+ untracked!(dump_mir_spanview, Some(MirSpanview::Statement));
+ untracked!(dump_mono_stats, SwitchWithOptPath::Enabled(Some("mono-items-dir/".into())));
+ untracked!(dump_mono_stats_format, DumpMonoStatsFormat::Json);
untracked!(dylib_lto, true);
untracked!(emit_stack_sizes, true);
untracked!(future_incompat_test, true);
untracked!(hir_stats, true);
untracked!(identify_regions, true);
- untracked!(incremental_ignore_spans, true);
untracked!(incremental_info, true);
untracked!(incremental_verify_ich, true);
untracked!(input_stats, true);
pac_ret: Some(PacRet { leaf: true, key: PAuthKey::B })
})
);
- tracked!(chalk, true);
tracked!(codegen_backend, Some("abc".to_string()));
tracked!(crate_attr, vec!["abc".to_string()]);
tracked!(debug_info_for_profiling, true);
tracked!(fuel, Some(("abc".to_string(), 99)));
tracked!(function_sections, Some(false));
tracked!(human_readable_cgu_names, true);
+ tracked!(incremental_ignore_spans, true);
tracked!(inline_in_all_cgus, Some(true));
tracked!(inline_mir, Some(true));
tracked!(inline_mir_hint_threshold, Some(123));
tracked!(thinlto, Some(true));
tracked!(thir_unsafeck, true);
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
+ tracked!(trait_solver, TraitSolver::Chalk);
tracked!(translate_remapped_path_to_local_path, false);
tracked!(trap_unreachable, Some(false));
tracked!(treat_err_as_bug, NonZeroUsize::new(1));
fn load_backend_from_dylib(path: &Path) -> MakeBackendFn {
let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| {
- let err = format!("couldn't load codegen backend {:?}: {}", path, err);
+ let err = format!("couldn't load codegen backend {path:?}: {err}");
early_error(ErrorOutputType::default(), &err);
});
let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") }
.unwrap_or_else(|e| {
- let err = format!("couldn't load codegen backend: {}", e);
+ let err = format!("couldn't load codegen backend: {e}");
early_error(ErrorOutputType::default(), &err);
});
.join("\n* ");
let err = format!(
"failed to find a `codegen-backends` folder \
- in the sysroot candidates:\n* {}",
- candidates
+ in the sysroot candidates:\n* {candidates}"
);
early_error(ErrorOutputType::default(), &err);
});
let expected_names = &[
format!("rustc_codegen_{}-{}", backend_name, env!("CFG_RELEASE")),
- format!("rustc_codegen_{}", backend_name),
+ format!("rustc_codegen_{backend_name}"),
];
for entry in d.filter_map(|e| e.ok()) {
let path = entry.path();
match file {
Some(ref s) => load_backend_from_dylib(s),
None => {
- let err = format!("unsupported builtin codegen backend `{}`", backend_name);
+ let err = format!("unsupported builtin codegen backend `{backend_name}`");
early_error(ErrorOutputType::default(), &err);
}
}
BuiltinLintDiagnostics::UnknownCrateTypes(
span,
"did you mean".to_string(),
- format!("\"{}\"", candidate),
+ format!("\"{candidate}\""),
),
);
} else {
}
// Eats the identifier. Note: succeeds on `_`, which isn't a valid
- // identifer.
+ // identifier.
fn eat_identifier(&mut self) {
if !is_id_start(self.first()) {
return;
///
/// The attribute must be used in conjunction with the
/// [`closure_track_caller` feature flag]. Otherwise, the `#[track_caller]`
- /// annotation will function as as no-op.
+ /// annotation will function as a no-op.
///
/// [`closure_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/closure-track-caller.html
UNGATED_ASYNC_FN_TRACK_CALLER,
fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
let map = cx.tcx.hir();
- if matches!(map.get(map.get_parent_node(field.hir_id)), Node::Variant(_)) {
+ if matches!(map.get_parent(field.hir_id), Node::Variant(_)) {
return;
}
self.perform_lint(cx, "field", field.def_id, field.vis_span, false);
tcx: TyCtxt<'tcx>,
bounds: &hir::GenericBounds<'_>,
inferred_outlives: &[ty::Region<'tcx>],
+ predicate_span: Span,
) -> Vec<(usize, Span)> {
use rustc_middle::middle::resolve_lifetime::Region;
.iter()
.enumerate()
.filter_map(|(i, bound)| {
- if let hir::GenericBound::Outlives(lifetime) = bound {
- let is_inferred = match tcx.named_region(lifetime.hir_id) {
- Some(Region::EarlyBound(def_id)) => inferred_outlives.iter().any(|r| {
- if let ty::ReEarlyBound(ebr) = **r {
- ebr.def_id == def_id
- } else {
- false
- }
- }),
- _ => false,
- };
- is_inferred.then_some((i, bound.span()))
- } else {
- None
+ let hir::GenericBound::Outlives(lifetime) = bound else {
+ return None;
+ };
+
+ let is_inferred = match tcx.named_region(lifetime.hir_id) {
+ Some(Region::EarlyBound(def_id)) => inferred_outlives
+ .iter()
+ .any(|r| matches!(**r, ty::ReEarlyBound(ebr) if { ebr.def_id == def_id })),
+ _ => false,
+ };
+
+ if !is_inferred {
+ return None;
}
+
+ let span = bound.span().find_ancestor_inside(predicate_span)?;
+ if in_external_macro(tcx.sess, span) {
+ return None;
+ }
+
+ Some((i, span))
})
- .filter(|(_, span)| !in_external_macro(tcx.sess, *span))
.collect()
}
use rustc_middle::middle::resolve_lifetime::Region;
let def_id = item.owner_id.def_id;
- if let hir::ItemKind::Struct(_, ref hir_generics)
- | hir::ItemKind::Enum(_, ref hir_generics)
- | hir::ItemKind::Union(_, ref hir_generics) = item.kind
+ if let hir::ItemKind::Struct(_, hir_generics)
+ | hir::ItemKind::Enum(_, hir_generics)
+ | hir::ItemKind::Union(_, hir_generics) = item.kind
{
let inferred_outlives = cx.tcx.inferred_outlives_of(def_id);
if inferred_outlives.is_empty() {
let mut dropped_predicate_count = 0;
let num_predicates = hir_generics.predicates.len();
for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
- let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate {
- hir::WherePredicate::RegionPredicate(predicate) => {
- if let Some(Region::EarlyBound(region_def_id)) =
- cx.tcx.named_region(predicate.lifetime.hir_id)
- {
- (
- Self::lifetimes_outliving_lifetime(
- inferred_outlives,
- region_def_id,
- ),
- &predicate.bounds,
- predicate.span,
- predicate.in_where_clause,
- )
- } else {
- continue;
- }
- }
- hir::WherePredicate::BoundPredicate(predicate) => {
- // FIXME we can also infer bounds on associated types,
- // and should check for them here.
- match predicate.bounded_ty.kind {
- hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
- let Res::Def(DefKind::TyParam, def_id) = path.res else {
- continue
- };
- let index = ty_generics.param_def_id_to_index[&def_id];
+ let (relevant_lifetimes, bounds, predicate_span, in_where_clause) =
+ match where_predicate {
+ hir::WherePredicate::RegionPredicate(predicate) => {
+ if let Some(Region::EarlyBound(region_def_id)) =
+ cx.tcx.named_region(predicate.lifetime.hir_id)
+ {
(
- Self::lifetimes_outliving_type(inferred_outlives, index),
+ Self::lifetimes_outliving_lifetime(
+ inferred_outlives,
+ region_def_id,
+ ),
&predicate.bounds,
predicate.span,
- predicate.origin == PredicateOrigin::WhereClause,
+ predicate.in_where_clause,
)
- }
- _ => {
+ } else {
continue;
}
}
- }
- _ => continue,
- };
+ hir::WherePredicate::BoundPredicate(predicate) => {
+ // FIXME we can also infer bounds on associated types,
+ // and should check for them here.
+ match predicate.bounded_ty.kind {
+ hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
+ let Res::Def(DefKind::TyParam, def_id) = path.res else {
+ continue;
+ };
+ let index = ty_generics.param_def_id_to_index[&def_id];
+ (
+ Self::lifetimes_outliving_type(inferred_outlives, index),
+ &predicate.bounds,
+ predicate.span,
+ predicate.origin == PredicateOrigin::WhereClause,
+ )
+ }
+ _ => {
+ continue;
+ }
+ }
+ }
+ _ => continue,
+ };
if relevant_lifetimes.is_empty() {
continue;
}
- let bound_spans =
- self.collect_outlives_bound_spans(cx.tcx, bounds, &relevant_lifetimes);
+ let bound_spans = self.collect_outlives_bound_spans(
+ cx.tcx,
+ bounds,
+ &relevant_lifetimes,
+ predicate_span,
+ );
bound_count += bound_spans.len();
let drop_predicate = bound_spans.len() == bounds.len();
}
if drop_predicate && !in_where_clause {
- lint_spans.push(span);
+ lint_spans.push(predicate_span);
} else if drop_predicate && i + 1 < num_predicates {
// If all the bounds on a predicate were inferable and there are
// further predicates, we want to eat the trailing comma.
let next_predicate_span = hir_generics.predicates[i + 1].span();
- where_lint_spans.push(span.to(next_predicate_span.shrink_to_lo()));
+ where_lint_spans.push(predicate_span.to(next_predicate_span.shrink_to_lo()));
} else {
where_lint_spans.extend(self.consolidate_outlives_bound_spans(
- span.shrink_to_lo(),
+ predicate_span.shrink_to_lo(),
bounds,
bound_spans,
));
} else {
hir_generics.span.shrink_to_hi().to(where_span)
};
- lint_spans.push(full_where_span);
+
+ // Due to macro expansions, the `full_where_span` might not actually contain all predicates.
+ if where_lint_spans.iter().all(|&sp| full_where_span.contains(sp)) {
+ lint_spans.push(full_where_span);
+ } else {
+ lint_spans.extend(where_lint_spans);
+ }
} else {
lint_spans.extend(where_lint_spans);
}
if !lint_spans.is_empty() {
+ // Do not automatically delete outlives requirements from macros.
+ let applicability = if lint_spans.iter().all(|sp| sp.can_be_used_for_suggestions())
+ {
+ Applicability::MachineApplicable
+ } else {
+ Applicability::MaybeIncorrect
+ };
+
cx.struct_span_lint(
EXPLICIT_OUTLIVES_REQUIREMENTS,
lint_spans.clone(),
|lint| {
lint.set_arg("count", bound_count).multipart_suggestion(
fluent::suggestion,
- lint_spans
- .into_iter()
- .map(|span| (span, String::new()))
- .collect::<Vec<_>>(),
- Applicability::MachineApplicable,
+ lint_spans.into_iter().map(|span| (span, String::new())).collect(),
+ applicability,
)
},
);
$cx.pass.$f(&$cx.context, $($args),*);
}) }
-/// Implements the AST traversal for early lint passes. `T` provides the the
+/// Implements the AST traversal for early lint passes. `T` provides the
/// `check_*` methods.
pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
context: EarlyContext<'a>,
TyKind::Path(QPath::Resolved(_, path)) => {
if lint_ty_kind_usage(cx, &path.res) {
let hir = cx.tcx.hir();
- let span = match hir.find(hir.get_parent_node(ty.hir_id)) {
+ let span = match hir.find_parent(ty.hir_id) {
Some(Node::Pat(Pat {
kind:
PatKind::Path(qpath)
$cx.pass.$f(&$cx.context, $($args),*);
}) }
-/// Implements the AST traversal for late lint passes. `T` provides the the
+/// Implements the AST traversal for late lint passes. `T` provides the
/// `check_*` methods.
pub struct LateContextAndPass<'tcx, T: LateLintPass<'tcx>> {
context: LateContext<'tcx>,
fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) {
if let PatKind::Binding(_, hid, ident, _) = p.kind {
- if let hir::Node::PatField(field) = cx.tcx.hir().get(cx.tcx.hir().get_parent_node(hid))
- {
+ if let hir::Node::PatField(field) = cx.tcx.hir().get_parent(hid) {
if !field.is_shorthand {
// Only check if a new name has been introduced, to avoid warning
// on both the struct definition and this pattern.
impl<'tcx> LateLintPass<'tcx> for PassByValue {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
match &ty.kind {
- TyKind::Rptr(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => {
+ TyKind::Ref(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => {
if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) {
if cx.tcx.impl_trait_ref(impl_did).is_some() {
return;
) -> bool {
// We only want to handle exclusive (`..`) ranges,
// which are represented as `ExprKind::Struct`.
- let par_id = cx.tcx.hir().get_parent_node(expr.hir_id);
+ let par_id = cx.tcx.hir().parent_id(expr.hir_id);
let Node::ExprField(field) = cx.tcx.hir().get(par_id) else { return false };
- let field_par_id = cx.tcx.hir().get_parent_node(field.hir_id);
- let Node::Expr(struct_expr) = cx.tcx.hir().get(field_par_id) else { return false };
+ let Node::Expr(struct_expr) = cx.tcx.hir().get_parent(field.hir_id) else { return false };
if !is_range_literal(struct_expr) {
return false;
};
_ => bug!(),
};
if lit_val < min || lit_val > max {
- let parent_id = cx.tcx.hir().get_parent_node(e.hir_id);
+ let parent_id = cx.tcx.hir().parent_id(e.hir_id);
if let Node::Expr(par_e) = cx.tcx.hir().get(parent_id) {
match par_e.kind {
hir::ExprKind::Cast(..) => {
cx.tcx,
cx.tcx.explicit_item_bounds(def).iter().cloned(),
)
- .filter_map(|obligation| {
+ .find_map(|obligation| {
// We only look at the `DefId`, so it is safe to skip the binder here.
if let ty::PredicateKind::Clause(ty::Clause::Trait(
ref poly_trait_predicate,
}
})
.map(|inner| MustUsePath::Opaque(Box::new(inner)))
- .next()
}
- ty::Dynamic(binders, _, _) => binders
- .iter()
- .filter_map(|predicate| {
- if let ty::ExistentialPredicate::Trait(ref trait_ref) =
- predicate.skip_binder()
- {
- let def_id = trait_ref.def_id;
- is_def_must_use(cx, def_id, span)
- } else {
- None
- }
- .map(|inner| MustUsePath::TraitObject(Box::new(inner)))
- })
- .next(),
+ ty::Dynamic(binders, _, _) => binders.iter().find_map(|predicate| {
+ if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
+ {
+ let def_id = trait_ref.def_id;
+ is_def_must_use(cx, def_id, span)
+ .map(|inner| MustUsePath::TraitObject(Box::new(inner)))
+ } else {
+ None
+ }
+ }),
ty::Tuple(tys) => {
let elem_exprs = if let hir::ExprKind::Tup(elem_exprs) = expr.kind {
debug_assert_eq!(elem_exprs.len(), tys.len());
&& !cx.sess().source_map().is_multiline(value.span)
&& value.attrs.is_empty()
&& !value.span.from_expansion()
+ && !inner.span.from_expansion()
{
self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos)
}
/// Supposed to be used for all variables except those set for build scripts by cargo
/// <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts>
fn tracked_env_var_os<K: AsRef<OsStr> + Display>(key: K) -> Option<OsString> {
- println!("cargo:rerun-if-env-changed={}", key);
+ println!("cargo:rerun-if-env-changed={key}");
env::var_os(key)
}
let output = match cmd.stderr(Stdio::inherit()).output() {
Ok(status) => status,
Err(e) => {
- println!("\n\nfailed to execute command: {:?}\nerror: {}\n\n", cmd, e);
+ println!("\n\nfailed to execute command: {cmd:?}\nerror: {e}\n\n");
std::process::exit(1);
}
};
fn main() {
for component in REQUIRED_COMPONENTS.iter().chain(OPTIONAL_COMPONENTS.iter()) {
- println!("cargo:rustc-check-cfg=values(llvm_component,\"{}\")", component);
+ println!("cargo:rustc-check-cfg=values(llvm_component,\"{component}\")");
}
if tracked_env_var_os("RUST_CHECK").is_some() {
for component in REQUIRED_COMPONENTS {
if !components.contains(component) {
- panic!("require llvm component {} but wasn't found", component);
+ panic!("require llvm component {component} but wasn't found");
}
}
for component in components.iter() {
- println!("cargo:rustc-cfg=llvm_component=\"{}\"", component);
+ println!("cargo:rustc-cfg=llvm_component=\"{component}\"");
}
// Link in our own LLVM shims, compiled with the same flags as LLVM
}
let kind = if name.starts_with("LLVM") { llvm_kind } else { "dylib" };
- println!("cargo:rustc-link-lib={}={}", kind, name);
+ println!("cargo:rustc-link-lib={kind}={name}");
}
// LLVM ldflags
println!("cargo:rustc-link-search=native={}", stripped.replace(&host, &target));
}
} else if let Some(stripped) = lib.strip_prefix("-LIBPATH:") {
- println!("cargo:rustc-link-search=native={}", stripped);
+ println!("cargo:rustc-link-search=native={stripped}");
} else if let Some(stripped) = lib.strip_prefix("-l") {
- println!("cargo:rustc-link-lib={}", stripped);
+ println!("cargo:rustc-link-lib={stripped}");
} else if let Some(stripped) = lib.strip_prefix("-L") {
- println!("cargo:rustc-link-search=native={}", stripped);
+ println!("cargo:rustc-link-search=native={stripped}");
}
}
if let Some(s) = llvm_linker_flags {
for lib in s.into_string().unwrap().split_whitespace() {
if let Some(stripped) = lib.strip_prefix("-l") {
- println!("cargo:rustc-link-lib={}", stripped);
+ println!("cargo:rustc-link-lib={stripped}");
} else if let Some(stripped) = lib.strip_prefix("-L") {
- println!("cargo:rustc-link-search=native={}", stripped);
+ println!("cargo:rustc-link-search=native={stripped}");
}
}
}
let path = PathBuf::from(s);
println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
if target.contains("windows") {
- println!("cargo:rustc-link-lib=static:-bundle={}", stdcppname);
+ println!("cargo:rustc-link-lib=static:-bundle={stdcppname}");
} else {
- println!("cargo:rustc-link-lib=static={}", stdcppname);
+ println!("cargo:rustc-link-lib=static={stdcppname}");
}
} else if cxxflags.contains("stdlib=libc++") {
println!("cargo:rustc-link-lib=c++");
} else {
- println!("cargo:rustc-link-lib={}", stdcppname);
+ println!("cargo:rustc-link-lib={stdcppname}");
}
}
match self {
Error::InvalidColorValue(value) => write!(
formatter,
- "invalid log color value '{}': expected one of always, never, or auto",
- value,
+ "invalid log color value '{value}': expected one of always, never, or auto",
),
Error::NonUnicodeColorValue => write!(
formatter,
let span = attr.span().unwrap();
let path = path_to_string(&attr.path);
match meta {
- Meta::Path(_) => span_err(span, &format!("`#[{}]` is not a valid attribute", path)),
+ Meta::Path(_) => span_err(span, &format!("`#[{path}]` is not a valid attribute")),
Meta::NameValue(_) => {
- span_err(span, &format!("`#[{} = ...]` is not a valid attribute", path))
+ span_err(span, &format!("`#[{path} = ...]` is not a valid attribute"))
}
- Meta::List(_) => span_err(span, &format!("`#[{}(...)]` is not a valid attribute", path)),
+ Meta::List(_) => span_err(span, &format!("`#[{path}(...)]` is not a valid attribute")),
}
}
let meta = match nested {
syn::NestedMeta::Meta(meta) => meta,
syn::NestedMeta::Lit(_) => {
- return span_err(span, &format!("`#[{}(\"...\")]` is not a valid attribute", name));
+ return span_err(span, &format!("`#[{name}(\"...\")]` is not a valid attribute"));
}
};
let path = path_to_string(meta.path());
match meta {
Meta::NameValue(..) => {
- span_err(span, &format!("`#[{}({} = ...)]` is not a valid attribute", name, path))
- }
- Meta::Path(..) => {
- span_err(span, &format!("`#[{}({})]` is not a valid attribute", name, path))
+ span_err(span, &format!("`#[{name}({path} = ...)]` is not a valid attribute"))
}
+ Meta::Path(..) => span_err(span, &format!("`#[{name}({path})]` is not a valid attribute")),
Meta::List(..) => {
- span_err(span, &format!("`#[{}({}(...))]` is not a valid attribute", name, path))
+ span_err(span, &format!("`#[{name}({path}(...))]` is not a valid attribute"))
}
}
}
opt: Default::default(),
};
let dl = DisplayList::from(snippet);
- eprintln!("{}\n", dl);
+ eprintln!("{dl}\n");
}
continue;
}
Diagnostic::spanned(
path_span,
Level::Error,
- format!("overrides existing {}: `{}`", kind, id),
+ format!("overrides existing {kind}: `{id}`"),
)
.span_help(previous_defns[&id], "previously defined in this resource")
.emit();
throw_span_err!(
attr.span().unwrap(),
&format!(
- "diagnostic slug must be first argument of a `#[{}(...)]` attribute",
- name
+ "diagnostic slug must be first argument of a `#[{name}(...)]` attribute"
)
);
};
None => {
span_err(
span.unwrap(),
- &format!("`{}` doesn't refer to a field on this type", field),
+ &format!("`{field}` doesn't refer to a field on this type"),
)
.emit();
quote! {
if suggestion_kind != SuggestionKind::Normal {
invalid_attr(attr, &meta)
.help(format!(
- r#"Use `#[suggestion(..., style = "{}")]` instead"#,
- suggestion_kind
+ r#"Use `#[suggestion(..., style = "{suggestion_kind}")]` instead"#
))
.emit();
}
if suggestion_kind != SuggestionKind::Normal {
invalid_attr(attr, &meta)
.help(format!(
- r#"Use `#[multipart_suggestion(..., style = "{}")]` instead"#,
- suggestion_kind
+ r#"Use `#[multipart_suggestion(..., style = "{suggestion_kind}")]` instead"#
))
.emit();
}
};
if let Some(old) = max.replace(literal.lit) {
- panic!("Specified multiple max: {:?}", old);
+ panic!("Specified multiple max: {old:?}");
}
false
};
if let Some(old) = debug_format.replace(literal.lit) {
- panic!("Specified multiple debug format options: {:?}", old);
+ panic!("Specified multiple debug format options: {old:?}");
}
false
.unwrap();
},
);
- let doc_string = format!("[query description - consider adding a doc-comment!] {}", doc_string);
+ let doc_string = format!("[query description - consider adding a doc-comment!] {doc_string}");
Ok(parse_quote! { #[doc = #doc_string] })
}
let mut check_dup = |span: Span, str: &str, errors: &mut Errors| {
if let Some(prev_span) = keys.get(str) {
- errors.error(span, format!("Symbol `{}` is duplicated", str));
+ errors.error(span, format!("Symbol `{str}` is duplicated"));
errors.error(*prev_span, "location of previous definition".to_string());
} else {
keys.insert(str.to_string(), span);
let mut check_order = |span: Span, str: &str, errors: &mut Errors| {
if let Some((prev_span, ref prev_str)) = prev_key {
if str < prev_str {
- errors.error(span, format!("Symbol `{}` must precede `{}`", str, prev_str));
- errors.error(prev_span, format!("location of previous symbol `{}`", prev_str));
+ errors.error(span, format!("Symbol `{str}` must precede `{prev_str}`"));
+ errors.error(prev_span, format!("location of previous symbol `{prev_str}`"));
}
}
prev_key = Some((span, str.to_string()));
let m: &syn::ItemMacro = file
.items
.iter()
- .filter_map(|i| {
+ .find_map(|i| {
if let syn::Item::Macro(m) = i {
if m.mac.path == symbols_path { Some(m) } else { None }
} else {
None
}
})
- .next()
.expect("did not find `symbols!` macro invocation.");
let body_tokens = m.mac.tokens.clone();
writeln!(fmt, "resolved crates:")?;
for (cnum, data) in self.0.iter_crate_data() {
writeln!(fmt, " name: {}", data.name())?;
- writeln!(fmt, " cnum: {}", cnum)?;
+ writeln!(fmt, " cnum: {cnum}")?;
writeln!(fmt, " hash: {}", data.hash())?;
writeln!(fmt, " reqd: {:?}", data.dep_kind())?;
let CrateSource { dylib, rlib, rmeta } = data.source();
pub(crate) fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> {
let cdata = self.metas[cnum]
.as_ref()
- .unwrap_or_else(|| panic!("Failed to get crate data for {:?}", cnum));
+ .unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}"));
CrateMetadataRef { cdata, cstore: self }
}
use crate::creader::CStore;
use crate::errors::{
BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired,
- RequiredPanicStrategy, RlibRequired, TwoPanicRuntimes,
+ RequiredPanicStrategy, RlibRequired, RustcLibRequired, TwoPanicRuntimes,
};
use rustc_data_structures::fx::FxHashMap;
Linkage::Static => "rlib",
_ => "dylib",
};
- sess.emit_err(LibRequired { crate_name: tcx.crate_name(cnum), kind: kind });
+ let crate_name = tcx.crate_name(cnum);
+ if crate_name.as_str().starts_with("rustc_") {
+ sess.emit_err(RustcLibRequired { crate_name, kind });
+ } else {
+ sess.emit_err(LibRequired { crate_name, kind });
+ }
}
}
}
pub kind: &'a str,
}
+#[derive(Diagnostic)]
+#[diag(metadata_rustc_lib_required)]
+#[help]
+pub struct RustcLibRequired<'a> {
+ pub crate_name: Symbol,
+ pub kind: &'a str,
+}
+
#[derive(Diagnostic)]
#[diag(metadata_crate_dep_multiple)]
#[help]
let mut diag = handler.struct_err(rustc_errors::fluent::metadata_multiple_candidates);
diag.set_arg("crate_name", self.crate_name);
diag.set_arg("flavor", self.flavor);
- diag.code(error_code!(E0465));
+ diag.code(error_code!(E0464));
diag.set_span(self.span);
for (i, candidate) in self.candidates.iter().enumerate() {
- diag.span_note(self.span, &format!("candidate #{}: {}", i + 1, candidate.display()));
+ diag.note(&format!("candidate #{}: {}", i + 1, candidate.display()));
}
diag
}
}
-#[derive(Diagnostic)]
-#[diag(metadata_multiple_matching_crates, code = "E0464")]
-#[note]
-pub struct MultipleMatchingCrates {
- #[primary_span]
- pub span: Span,
- pub crate_name: Symbol,
- pub candidates: String,
-}
-
#[derive(Diagnostic)]
#[diag(metadata_symbol_conflicts_current, code = "E0519")]
pub struct SymbolConflictsCurrent {
use crate::errors::{
CannotFindCrate, CrateLocationUnknownType, DlError, ExternLocationNotExist,
ExternLocationNotFile, FoundStaticlib, IncompatibleRustc, InvalidMetadataFiles,
- LibFilenameForm, MultipleCandidates, MultipleMatchingCrates, NewerCrateVersion,
- NoCrateWithTriple, NoDylibPlugin, NonAsciiName, StableCrateIdCollision, SymbolConflictsCurrent,
- SymbolConflictsOthers,
+ LibFilenameForm, MultipleCandidates, NewerCrateVersion, NoCrateWithTriple, NoDylibPlugin,
+ NonAsciiName, StableCrateIdCollision, SymbolConflictsCurrent, SymbolConflictsOthers,
};
use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER};
use snap::read::FrameDecoder;
use std::borrow::Cow;
-use std::fmt::Write as _;
use std::io::{Read, Result as IoResult, Write};
use std::path::{Path, PathBuf};
use std::{cmp, fmt, fs};
match libraries.len() {
0 => Ok(None),
1 => Ok(Some(libraries.into_iter().next().unwrap().1)),
- _ => Err(CrateError::MultipleMatchingCrates(self.crate_name, libraries)),
+ _ => {
+ let mut libraries: Vec<_> = libraries.into_values().collect();
+
+ libraries.sort_by_cached_key(|lib| lib.source.paths().next().unwrap().clone());
+ let candidates = libraries
+ .iter()
+ .map(|lib| lib.source.paths().next().unwrap().clone())
+ .collect::<Vec<_>>();
+
+ Err(CrateError::MultipleCandidates(
+ self.crate_name,
+ // these are the same for all candidates
+ get_flavor_from_path(candidates.first().unwrap()),
+ candidates,
+ ))
+ }
}
}
metadata_loader: &dyn MetadataLoader,
out: &mut dyn Write,
) -> IoResult<()> {
+ let flavor = get_flavor_from_path(path);
+ match get_metadata_section(target, flavor, path, metadata_loader) {
+ Ok(metadata) => metadata.list_crate_metadata(out),
+ Err(msg) => write!(out, "{}\n", msg),
+ }
+}
+
+fn get_flavor_from_path(path: &Path) -> CrateFlavor {
let filename = path.file_name().unwrap().to_str().unwrap();
- let flavor = if filename.ends_with(".rlib") {
+
+ if filename.ends_with(".rlib") {
CrateFlavor::Rlib
} else if filename.ends_with(".rmeta") {
CrateFlavor::Rmeta
} else {
CrateFlavor::Dylib
- };
- match get_metadata_section(target, flavor, path, metadata_loader) {
- Ok(metadata) => metadata.list_crate_metadata(out),
- Err(msg) => write!(out, "{}\n", msg),
}
}
ExternLocationNotExist(Symbol, PathBuf),
ExternLocationNotFile(Symbol, PathBuf),
MultipleCandidates(Symbol, CrateFlavor, Vec<PathBuf>),
- MultipleMatchingCrates(Symbol, FxHashMap<Svh, Library>),
SymbolConflictsCurrent(Symbol),
SymbolConflictsOthers(Symbol),
StableCrateIdCollision(Symbol, Symbol),
sess.emit_err(ExternLocationNotFile { span, crate_name, location: &loc });
}
CrateError::MultipleCandidates(crate_name, flavor, candidates) => {
- sess.emit_err(MultipleCandidates { span, flavor: flavor, crate_name, candidates });
- }
- CrateError::MultipleMatchingCrates(crate_name, libraries) => {
- let mut libraries: Vec<_> = libraries.into_values().collect();
- // Make ordering of candidates deterministic.
- // This has to `clone()` to work around lifetime restrictions with `sort_by_key()`.
- // `sort_by()` could be used instead, but this is in the error path,
- // so the performance shouldn't matter.
- libraries.sort_by_cached_key(|lib| lib.source.paths().next().unwrap().clone());
- let candidates = libraries
- .iter()
- .map(|lib| {
- let crate_name = lib.metadata.get_root().name();
- let crate_name = crate_name.as_str();
- let mut paths = lib.source.paths();
-
- // This `unwrap()` should be okay because there has to be at least one
- // source file. `CrateSource`'s docs confirm that too.
- let mut s = format!(
- "\ncrate `{}`: {}",
- crate_name,
- paths.next().unwrap().display()
- );
- let padding = 8 + crate_name.len();
- for path in paths {
- write!(s, "\n{:>padding$}", path.display(), padding = padding).unwrap();
- }
- s
- })
- .collect::<String>();
- sess.emit_err(MultipleMatchingCrates { span, crate_name, candidates });
+ sess.emit_err(MultipleCandidates { span, crate_name, flavor, candidates });
}
CrateError::SymbolConflictsCurrent(root_name) => {
sess.emit_err(SymbolConflictsCurrent { span, crate_name: root_name });
for path in search_paths {
for (prefix, suffix) in &formats {
- let test = path.join(format!("{}{}{}", prefix, name, suffix));
+ let test = path.join(format!("{prefix}{name}{suffix}"));
if test.exists() {
return test;
}
.root
.syntax_contexts
.get(cdata, id)
- .unwrap_or_else(|| panic!("Missing SyntaxContext {:?} for crate {:?}", id, cname))
+ .unwrap_or_else(|| panic!("Missing SyntaxContext {id:?} for crate {cname:?}"))
.decode((cdata, sess))
})
}
.tables
.def_span
.get(self, index)
- .unwrap_or_else(|| panic!("Missing span for {:?}", index))
+ .unwrap_or_else(|| panic!("Missing span for {index:?}"))
.decode((self, sess))
}
.tables
.proc_macro_quoted_spans
.get(self, index)
- .unwrap_or_else(|| panic!("Missing proc macro quoted span: {:?}", index))
+ .unwrap_or_else(|| panic!("Missing proc macro quoted span: {index:?}"))
.decode((self, sess))
}
generator_kind => { table }
trait_def => { table }
deduced_param_attrs => { table }
- collect_trait_impl_trait_tys => {
+ collect_return_position_impl_trait_in_trait_tys => {
Ok(cdata
.root
.tables
.trait_impl_trait_tys
.get(cdata, def_id.index)
.map(|lazy| lazy.decode((cdata, tcx)))
- .process_decoded(tcx, || panic!("{:?} does not have trait_impl_trait_tys", def_id)))
+ .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys")))
}
visibility => { cdata.get_visibility(def_id.index) }
let _ = d.read_raw_bytes(len);
let inner = odht::HashTable::from_raw_bytes(o).unwrap_or_else(|e| {
- panic!("decode error: {}", e);
+ panic!("decode error: {e}");
});
DefPathHashMapRef::OwnedFromMetadata(inner)
}
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for CrateNum {
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
if *self != LOCAL_CRATE && s.is_proc_macro {
- panic!("Attempted to encode non-local CrateNum {:?} for proc-macro crate", self);
+ panic!("Attempted to encode non-local CrateNum {self:?} for proc-macro crate");
}
s.emit_u32(self.as_u32());
}
// Introduce a new scope so that we drop the 'lock()' temporary
match &*source_file.external_src.lock() {
ExternalSource::Foreign { metadata_index, .. } => *metadata_index,
- src => panic!("Unexpected external source {:?}", src),
+ src => panic!("Unexpected external source {src:?}"),
}
};
let prefix = "meta-stats";
let perc = |bytes| (bytes * 100) as f64 / total_bytes as f64;
- eprintln!("{} METADATA STATS", prefix);
+ eprintln!("{prefix} METADATA STATS");
eprintln!("{} {:<23}{:>10}", prefix, "Section", "Size");
- eprintln!(
- "{} ----------------------------------------------------------------",
- prefix
- );
+ eprintln!("{prefix} ----------------------------------------------------------------");
for (label, size) in stats {
eprintln!(
"{} {:<23}{:>10} ({:4.1}%)",
perc(size)
);
}
- eprintln!(
- "{} ----------------------------------------------------------------",
- prefix
- );
+ eprintln!("{prefix} ----------------------------------------------------------------");
eprintln!(
"{} {:<23}{:>10} (of which {:.1}% are zero bytes)",
prefix,
to_readable_str(total_bytes),
perc(zero_bytes)
);
- eprintln!("{}", prefix);
+ eprintln!("{prefix}");
}
root
record!(self.tables.params_in_repr[def_id] <- params_in_repr);
}
if should_encode_trait_impl_trait_tys(tcx, def_id)
- && let Ok(table) = self.tcx.collect_trait_impl_trait_tys(def_id)
+ && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
{
record!(self.tables.trait_impl_trait_tys[def_id] <- table);
}
}
loop {
// There are nodes that do not have entries, so we need to skip them.
- let parent_id = self.map.get_parent_node(self.current_id);
+ let parent_id = self.map.parent_id(self.current_id);
if parent_id == self.current_id {
self.current_id = CRATE_HIR_ID;
},
Node::Variant(_) => DefKind::Variant,
Node::Ctor(variant_data) => {
- let ctor_of = match self.find(self.get_parent_node(hir_id)) {
+ let ctor_of = match self.find_parent(hir_id) {
Some(Node::Item(..)) => def::CtorOf::Struct,
Some(Node::Variant(..)) => def::CtorOf::Variant,
_ => unreachable!(),
}
}
Node::AnonConst(_) => {
- let inline = match self.find(self.get_parent_node(hir_id)) {
+ let inline = match self.find_parent(hir_id) {
Some(Node::Expr(&Expr {
kind: ExprKind::ConstBlock(ref anon_const), ..
})) if anon_const.hir_id == hir_id => true,
/// Finds the id of the parent node to this one.
///
/// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`].
- pub fn find_parent_node(self, id: HirId) -> Option<HirId> {
+ pub fn opt_parent_id(self, id: HirId) -> Option<HirId> {
if id.local_id == ItemLocalId::from_u32(0) {
Some(self.tcx.hir_owner_parent(id.owner))
} else {
}
#[track_caller]
- pub fn get_parent_node(self, hir_id: HirId) -> HirId {
- self.find_parent_node(hir_id)
+ pub fn parent_id(self, hir_id: HirId) -> HirId {
+ self.opt_parent_id(hir_id)
.unwrap_or_else(|| bug!("No parent for node {:?}", self.node_to_string(hir_id)))
}
+ pub fn get_parent(self, hir_id: HirId) -> Node<'hir> {
+ self.get(self.parent_id(hir_id))
+ }
+
+ pub fn find_parent(self, hir_id: HirId) -> Option<Node<'hir>> {
+ self.find(self.opt_parent_id(hir_id)?)
+ }
+
/// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
pub fn find(self, id: HirId) -> Option<Node<'hir>> {
if id.local_id == ItemLocalId::from_u32(0) {
/// which this is the body of, i.e., a `fn`, `const` or `static`
/// item (possibly associated), a closure, or a `hir::AnonConst`.
pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId {
- let parent = self.get_parent_node(hir_id);
+ let parent = self.parent_id(hir_id);
assert!(self.find(parent).map_or(false, |n| is_body_owner(n, hir_id)), "{hir_id:?}");
parent
}
}
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
- /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
+ /// until the crate root is reached. Prefer this over your own loop using `parent_id`.
#[inline]
pub fn parent_id_iter(self, current_id: HirId) -> impl Iterator<Item = HirId> + 'hir {
ParentHirIterator { current_id, map: self }
}
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
- /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
+ /// until the crate root is reached. Prefer this over your own loop using `parent_id`.
#[inline]
pub fn parent_iter(self, current_id: HirId) -> impl Iterator<Item = (HirId, Node<'hir>)> {
self.parent_id_iter(current_id).filter_map(move |id| Some((id, self.find(id)?)))
}
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
- /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
+ /// until the crate root is reached. Prefer this over your own loop using `parent_id`.
#[inline]
pub fn parent_owner_iter(self, current_id: HirId) -> ParentOwnerIterator<'hir> {
ParentOwnerIterator { current_id, map: self }
/// Checks if the node is left-hand side of an assignment.
pub fn is_lhs(self, id: HirId) -> bool {
- match self.find(self.get_parent_node(id)) {
+ match self.find_parent(id) {
Some(Node::Expr(expr)) => match expr.kind {
ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id,
_ => false,
Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident),
// A `Ctor` doesn't have an identifier itself, but its parent
// struct/variant does. Compare with `hir::Map::opt_span`.
- Node::Ctor(..) => match self.find(self.get_parent_node(id))? {
+ Node::Ctor(..) => match self.find_parent(id)? {
Node::Item(item) => Some(item.ident),
Node::Variant(variant) => Some(variant.ident),
_ => unreachable!(),
ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()),
_ => named_span(item.span, item.ident, None),
},
- Node::Ctor(_) => return self.opt_span(self.get_parent_node(hir_id)),
+ Node::Ctor(_) => return self.opt_span(self.parent_id(hir_id)),
Node::Expr(Expr {
kind: ExprKind::Closure(Closure { fn_decl_span, .. }),
span,
Node::PatField(field) => field.span,
Node::Arm(arm) => arm.span,
Node::Block(block) => block.span,
- Node::Ctor(..) => self.span_with_body(self.get_parent_node(hir_id)),
+ Node::Ctor(..) => self.span_with_body(self.parent_id(hir_id)),
Node::Lifetime(lifetime) => lifetime.ident.span,
Node::GenericParam(param) => param.span,
Node::Infer(i) => i.span,
/// Returns the HirId of `N` in `struct Foo<const N: usize = { ... }>` when
/// called with the HirId for the `{ ... }` anon const
pub fn opt_const_param_default_param_def_id(self, anon_const: HirId) -> Option<LocalDefId> {
- match self.get(self.get_parent_node(anon_const)) {
+ match self.get_parent(anon_const) {
Node::GenericParam(GenericParam {
def_id: param_id,
kind: GenericParamKind::Const { .. },
hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
- if tcx.sess.opts.unstable_opts.incremental_relative_spans {
+ if tcx.sess.opts.incremental_relative_spans() {
let definitions = tcx.definitions_untracked();
let mut owner_spans: Vec<_> = krate
.owners
} else if let Node::TraitItem(&TraitItem {
kind: TraitItemKind::Fn(_, TraitFn::Required(idents)),
..
+ })
+ | Node::ForeignItem(&ForeignItem {
+ kind: ForeignItemKind::Fn(_, idents, _),
+ ..
}) = hir.get(hir_id)
{
- tcx.arena.alloc_slice(idents)
+ idents
} else {
span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id);
}
}
}
-pub type Canonicalized<'tcx, V> = Canonical<'tcx, V>;
-
-pub type CanonicalizedQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>;
+pub type CanonicalQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>;
/// Indicates whether or not we were able to prove the query to be
/// true.
if hir.attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) {
return id;
}
- let next = hir.get_parent_node(id);
+ let next = hir.parent_id(id);
if next == id {
bug!("lint traversal reached the root of the crate");
}
+/// A macro for triggering an ICE.
+/// Calling `bug` instead of panicking will result in a nicer error message and should
+/// therefore be prefered over `panic`/`unreachable` or others.
+///
+/// If you have a span available, you should use [`span_bug`] instead.
+///
+/// If the bug should only be emitted when compilation didn't fail, [`Session::delay_span_bug`] may be useful.
+///
+/// [`Session::delay_span_bug`]: rustc_session::Session::delay_span_bug
+/// [`span_bug`]: crate::span_bug
#[macro_export]
macro_rules! bug {
() => ( $crate::bug!("impossible case reached") );
});
}
+/// A macro for triggering an ICE with a span.
+/// Calling `span_bug!` instead of panicking will result in a nicer error message and point
+/// at the code the compiler was compiling when it ICEd. This is the preferred way to trigger
+/// ICEs.
+///
+/// If the bug should only be emitted when compilation didn't fail, [`Session::delay_span_bug`] may be useful.
+///
+/// [`Session::delay_span_bug`]: rustc_session::Session::delay_span_bug
#[macro_export]
macro_rules! span_bug {
($span:expr, $msg:expr) => ({ $crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg)) });
}
let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
- let parent_substs = if let Some(parent_hir_id) = tcx.hir().find_parent_node(hir_id) {
+ let parent_substs = if let Some(parent_hir_id) = tcx.hir().opt_parent_id(hir_id) {
if let Some(parent_did) = tcx.hir().opt_local_def_id(parent_hir_id) {
InternalSubsts::identity_for_item(tcx, parent_did.to_def_id())
} else {
-use smallvec::{smallvec, SmallVec};
+use smallvec::SmallVec;
use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind};
use rustc_ast::InlineAsmTemplatePiece;
//! ## Overview
//!
//! There are two visitors, one for immutable and one for mutable references,
-//! but both are generated by the following macro. The code is written according
-//! to the following conventions:
+//! but both are generated by the `make_mir_visitor` macro.
+//! The code is written according to the following conventions:
//!
//! - introduce a `visit_foo` and a `super_foo` method for every MIR type
//! - `visit_foo`, by default, calls `super_foo`
//! - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
//!
-//! This allows you as a user to override `visit_foo` for types are
-//! interested in, and invoke (within that method) call
+//! This allows you to override `visit_foo` for types you are
+//! interested in, and invoke (within that method call)
//! `self.super_foo` to get the default behavior. Just as in an OO
//! language, you should never call `super` methods ordinarily except
//! in that circumstance.
separate_provide_extern
}
- query collect_trait_impl_trait_tys(key: DefId)
+ query collect_return_position_impl_trait_in_trait_tys(key: DefId)
-> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>
{
desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" }
desc { "checking to see if `{}` permits being left zeroed", key.ty }
}
- query compare_assoc_const_impl_item_with_trait_item(
+ query compare_impl_const(
key: (LocalDefId, DefId)
) -> Result<(), ErrorGuaranteed> {
desc { |tcx| "checking assoc const `{}` has the same type as trait item", tcx.def_path_str(key.0.to_def_id()) }
pub mod type_op {
use crate::ty::fold::TypeFoldable;
- use crate::ty::subst::UserSubsts;
- use crate::ty::{Predicate, Ty};
- use rustc_hir::def_id::DefId;
+ use crate::ty::{Predicate, Ty, UserType};
use std::fmt;
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct AscribeUserType<'tcx> {
pub mir_ty: Ty<'tcx>,
- pub def_id: DefId,
- pub user_substs: UserSubsts<'tcx>,
+ pub user_ty: UserType<'tcx>,
}
impl<'tcx> AscribeUserType<'tcx> {
- pub fn new(mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>) -> Self {
- Self { mir_ty, def_id, user_substs }
+ pub fn new(mir_ty: Ty<'tcx>, user_ty: UserType<'tcx>) -> Self {
+ Self { mir_ty, user_ty }
}
}
T: TypeFoldable<'tcx>,
{
// If there's nothing to erase avoid performing the query at all
- if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) {
+ if !value.has_type_flags(TypeFlags::HAS_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) {
return value;
}
debug!("erase_regions({:?})", value);
.def_id
.as_local()
.map(|id| hir.local_def_id_to_hir_id(id))
- .and_then(|id| self.hir().find(self.hir().get_parent_node(id)))
+ .and_then(|id| self.hir().find_parent(id))
.as_ref()
.and_then(|node| node.generics())
{
{
let mut computation = FlagComputation::new();
- if !value.bound_vars().is_empty() {
- computation.flags = computation.flags | TypeFlags::HAS_RE_LATE_BOUND;
+ for bv in value.bound_vars() {
+ match bv {
+ ty::BoundVariableKind::Ty(_) => {
+ computation.flags |= TypeFlags::HAS_TY_LATE_BOUND;
+ }
+ ty::BoundVariableKind::Region(_) => {
+ computation.flags |= TypeFlags::HAS_RE_LATE_BOUND;
+ }
+ ty::BoundVariableKind::Const => {
+ computation.flags |= TypeFlags::HAS_CT_LATE_BOUND;
+ }
+ }
}
f(&mut computation, value.skip_binder());
&ty::Bound(debruijn, _) => {
self.add_bound_var(debruijn);
+ self.add_flags(TypeFlags::HAS_TY_LATE_BOUND);
}
&ty::Placeholder(..) => {
}
ty::ConstKind::Bound(debruijn, _) => {
self.add_bound_var(debruijn);
+ self.add_flags(TypeFlags::HAS_CT_LATE_BOUND);
}
ty::ConstKind::Param(_) => {
self.add_flags(TypeFlags::HAS_CT_PARAM);
});
}
- match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
- ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize),
- ty::Dynamic(_, _, ty::Dyn) => {
- TyMaybeWithLayout::Ty(tcx.mk_imm_ref(
- tcx.lifetimes.re_static,
- tcx.mk_array(tcx.types.usize, 3),
- ))
- /* FIXME: use actual fn pointers
- Warning: naively computing the number of entries in the
- vtable by counting the methods on the trait + methods on
- all parent traits does not work, because some methods can
- be not object safe and thus excluded from the vtable.
- Increase this counter if you tried to implement this but
- failed to do it without duplicating a lot of code from
- other places in the compiler: 2
- tcx.mk_tup(&[
- tcx.mk_array(tcx.types.usize, 3),
- tcx.mk_array(Option<fn()>),
- ])
- */
+ let mk_dyn_vtable = || {
+ tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3))
+ /* FIXME: use actual fn pointers
+ Warning: naively computing the number of entries in the
+ vtable by counting the methods on the trait + methods on
+ all parent traits does not work, because some methods can
+ be not object safe and thus excluded from the vtable.
+ Increase this counter if you tried to implement this but
+ failed to do it without duplicating a lot of code from
+ other places in the compiler: 2
+ tcx.mk_tup(&[
+ tcx.mk_array(tcx.types.usize, 3),
+ tcx.mk_array(Option<fn()>),
+ ])
+ */
+ };
+
+ let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
+ let metadata = tcx.normalize_erasing_regions(
+ cx.param_env(),
+ tcx.mk_projection(metadata_def_id, [pointee]),
+ );
+
+ // Map `Metadata = DynMetadata<dyn Trait>` back to a vtable, since it
+ // offers better information than `std::ptr::metadata::VTable`,
+ // and we rely on this layout information to trigger a panic in
+ // `std::mem::uninitialized::<&dyn Trait>()`, for example.
+ if let ty::Adt(def, substs) = metadata.kind()
+ && Some(def.did()) == tcx.lang_items().dyn_metadata()
+ && substs.type_at(0).is_trait()
+ {
+ mk_dyn_vtable()
+ } else {
+ metadata
}
- _ => bug!("TyAndLayout::field({:?}): not applicable", this),
- }
+ } else {
+ match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
+ ty::Slice(_) | ty::Str => tcx.types.usize,
+ ty::Dynamic(_, _, ty::Dyn) => mk_dyn_vtable(),
+ _ => bug!("TyAndLayout::field({:?}): not applicable", this),
+ }
+ };
+
+ TyMaybeWithLayout::Ty(metadata)
}
// Arrays and slices.
pub inferred_ty: Ty<'tcx>,
}
-/// Canonicalized user type annotation.
+/// Canonical user type annotation.
pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
impl<'tcx> CanonicalUserType<'tcx> {
/// from constants that are named via paths, like `Foo::<A>::new` and
/// so forth.
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable, Lift)]
pub enum UserType<'tcx> {
Ty(Ty<'tcx>),
ty::EarlyBinder(self.type_of(def_id))
}
- pub fn bound_trait_impl_trait_tys(
+ pub fn bound_return_position_impl_trait_in_trait_tys(
self,
def_id: DefId,
) -> ty::EarlyBinder<Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>> {
- ty::EarlyBinder(self.collect_trait_impl_trait_tys(def_id))
+ ty::EarlyBinder(self.collect_return_position_impl_trait_in_trait_tys(def_id))
}
pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> {
fn has_late_bound_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
}
+ /// True if there are any late-bound non-region variables
+ fn has_non_region_late_bound(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_LATE_BOUND - TypeFlags::HAS_RE_LATE_BOUND)
+ }
+ /// True if there are any late-bound variables
+ fn has_late_bound_vars(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_LATE_BOUND)
+ }
/// Indicates whether this value still has parameters/placeholders/inference variables
/// which could be replaced later, in a way that would change the results of `impl`
use crate::ty::subst::{GenericArg, GenericArgKind};
use crate::ty::{self, Ty};
use rustc_data_structures::sso::SsoHashSet;
-use smallvec::{self, SmallVec};
+use smallvec::SmallVec;
// The TypeWalker's stack is hot enough that it's worth going to some effort to
// avoid heap allocations.
(Some(tcx), None) => tcx.sess.diagnostic().bug(&msg),
(None, _) => panic_any(msg),
}
- });
- unreachable!();
+ })
}
/// A query to trigger a `delay_span_bug`. Clearly, if one has a `tcx` one can already trigger a
use rustc_hir as hir;
use rustc_middle::mir::BorrowKind;
use rustc_middle::thir::*;
+use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
use rustc_session::lint::Level;
hir_id: hir::HirId,
span: Span,
) {
+ // FIXME: ideally we would want to trim the def paths, but this is not
+ // feasible with the current lint emission API (see issue #106126).
match self {
- CallToUnsafeFunction(did) if did.is_some() => tcx.emit_spanned_lint(
+ CallToUnsafeFunction(Some(did)) => tcx.emit_spanned_lint(
UNSAFE_OP_IN_UNSAFE_FN,
hir_id,
span,
UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe {
span,
- function: &tcx.def_path_str(did.unwrap()),
+ function: &with_no_trimmed_paths!(tcx.def_path_str(*did)),
},
),
- CallToUnsafeFunction(..) => tcx.emit_spanned_lint(
+ CallToUnsafeFunction(None) => tcx.emit_spanned_lint(
UNSAFE_OP_IN_UNSAFE_FN,
hir_id,
span,
span,
UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
span,
- function: &tcx.def_path_str(*did),
+ function: &with_no_trimmed_paths!(tcx.def_path_str(*did)),
},
),
}
unsafe_op_in_unsafe_fn_allowed: bool,
) {
match self {
- CallToUnsafeFunction(did) if did.is_some() && unsafe_op_in_unsafe_fn_allowed => {
+ CallToUnsafeFunction(Some(did)) if unsafe_op_in_unsafe_fn_allowed => {
tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
span,
- function: &tcx.def_path_str(did.unwrap()),
+ function: &tcx.def_path_str(*did),
});
}
- CallToUnsafeFunction(did) if did.is_some() => {
+ CallToUnsafeFunction(Some(did)) => {
tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafe {
span,
- function: &tcx.def_path_str(did.unwrap()),
+ function: &tcx.def_path_str(*did),
});
}
- CallToUnsafeFunction(..) if unsafe_op_in_unsafe_fn_allowed => {
+ CallToUnsafeFunction(None) if unsafe_op_in_unsafe_fn_allowed => {
tcx.sess.emit_err(
CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { span },
);
}
- CallToUnsafeFunction(..) => {
+ CallToUnsafeFunction(None) => {
tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless { span });
}
UseOfInlineAssembly if unsafe_op_in_unsafe_fn_allowed => {
fn check_let_chain(&mut self, cx: &mut MatchCheckCtxt<'p, 'tcx>, pat_id: HirId) -> bool {
let hir = self.tcx.hir();
- let parent = hir.get_parent_node(pat_id);
+ let parent = hir.parent_id(pat_id);
// First, figure out if the given pattern is part of a let chain,
// and if so, obtain the top node of the chain.
let mut top = parent;
let mut part_of_chain = false;
loop {
- let new_top = hir.get_parent_node(top);
+ let new_top = hir.parent_id(top);
if let hir::Node::Expr(
hir::Expr {
kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, lhs, rhs),
fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
let hir = tcx.hir();
- let parent = hir.get_parent_node(pat_id);
+ let parent = hir.parent_id(pat_id);
let_source_parent(tcx, parent, Some(pat_id))
}
_ => {}
}
- let parent_parent = hir.get_parent_node(parent);
+ let parent_parent = hir.parent_id(parent);
let parent_parent_node = hir.get(parent_parent);
match parent_parent_node {
hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), .. }) => {
_ => {}
}
- let parent_parent_parent = hir.get_parent_node(parent_parent);
- let parent_parent_parent_parent = hir.get_parent_node(parent_parent_parent);
+ let parent_parent_parent = hir.parent_id(parent_parent);
+ let parent_parent_parent_parent = hir.parent_id(parent_parent_parent);
let parent_parent_parent_parent_node = hir.get(parent_parent_parent_parent);
if let hir::Node::Expr(hir::Expr {
| mir::TerminatorKind::InlineAsm { cleanup: Some(unwind), .. }
if unwind == bb =>
{
- if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
+ if dead_unwinds.map_or(true, |dead| !dead.contains(pred)) {
propagate(pred, exit_state);
}
}
", "
};
- write!(f, "{}", delim)?;
+ write!(f, "{delim}")?;
idx.fmt_with(ctxt, f)?;
first = false;
}
", "
};
- write!(f, "{}", delim)?;
+ write!(f, "{delim}")?;
idx.fmt_with(ctxt, f)?;
first = false;
}
fn graph_id(&self) -> dot::Id<'_> {
let name = graphviz_safe_def_name(self.body.source.def_id());
- dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap()
+ dot::Id::new(format!("graph_for_def_id_{name}")).unwrap()
}
fn node_id(&self, n: &Self::Node) -> dot::Id<'_> {
" cellpadding=\"3\"",
" sides=\"rb\"",
);
- write!(w, r#"<table{fmt}>"#, fmt = table_fmt)?;
+ write!(w, r#"<table{table_fmt}>"#)?;
// A + B: Block header
match self.style {
write!(w, concat!("<tr>", r#"<td colspan="2" {fmt}>MIR</td>"#,), fmt = fmt,)?;
for name in state_column_names {
- write!(w, "<td {fmt}>{name}</td>", fmt = fmt, name = name)?;
+ write!(w, "<td {fmt}>{name}</td>")?;
}
write!(w, "</tr>")
};
for (i, statement) in body[block].statements.iter().enumerate() {
- let statement_str = format!("{:?}", statement);
- let index_str = format!("{}", i);
+ let statement_str = format!("{statement:?}");
+ let index_str = format!("{i}");
let after = next_in_dataflow_order(&mut afters);
let before = befores.as_mut().map(next_in_dataflow_order);
self.write_row(w, &index_str, &statement_str, |_this, w, fmt| {
if let Some(before) = before {
- write!(w, r#"<td {fmt} align="left">{diff}</td>"#, fmt = fmt, diff = before)?;
+ write!(w, r#"<td {fmt} align="left">{before}</td>"#)?;
}
- write!(w, r#"<td {fmt} align="left">{diff}</td>"#, fmt = fmt, diff = after)
+ write!(w, r#"<td {fmt} align="left">{after}</td>"#)
})?;
}
self.write_row(w, "T", &terminator_str, |_this, w, fmt| {
if let Some(before) = before {
- write!(w, r#"<td {fmt} align="left">{diff}</td>"#, fmt = fmt, diff = before)?;
+ write!(w, r#"<td {fmt} align="left">{before}</td>"#)?;
}
- write!(w, r#"<td {fmt} align="left">{diff}</td>"#, fmt = fmt, diff = after)
+ write!(w, r#"<td {fmt} align="left">{after}</td>"#)
})
}
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(w, "MovePath {{")?;
if let Some(parent) = self.parent {
- write!(w, " parent: {:?},", parent)?;
+ write!(w, " parent: {parent:?},")?;
}
if let Some(first_child) = self.first_child {
- write!(w, " first_child: {:?},", first_child)?;
+ write!(w, " first_child: {first_child:?},")?;
}
if let Some(next_sibling) = self.next_sibling {
- write!(w, " next_sibling: {:?}", next_sibling)?;
+ write!(w, " next_sibling: {next_sibling:?}")?;
}
write!(w, " place: {:?} }}", self.place)
}
) -> std::fmt::Result {
for (local, place) in map.locals.iter_enumerated() {
if let Some(place) = place {
- debug_with_context_rec(*place, &format!("{:?}", local), new, old, map, f)?;
+ debug_with_context_rec(*place, &format!("{local:?}"), new, old, map, f)?;
}
}
Ok(())
return None;
}
- if self.tcx.sess.mir_opt_level() >= 4 {
- self.eval_rvalue_with_identities(rvalue, place)
- } else {
- self.use_ecx(|this| this.ecx.eval_rvalue_into_place(rvalue, place))
- }
+ self.eval_rvalue_with_identities(rvalue, place)
}
// Attempt to use algebraic identities to eliminate constant expressions
bbs[block].statements[statement_index].make_nop();
}
- crate::simplify::SimplifyLocals.run_pass(tcx, body)
+ crate::simplify::simplify_locals(body, tcx)
}
pub struct DeadStoreElimination;
//! Inlining pass for MIR functions
use crate::deref_separator::deref_finder;
use rustc_attr::InlineAttr;
+use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
const UNKNOWN_SIZE_COST: usize = 10;
+const TOP_DOWN_DEPTH_LIMIT: usize = 5;
+
pub struct Inline;
#[derive(Copy, Clone, Debug)]
let param_env = tcx.param_env_reveal_all_normalized(def_id);
- let mut this =
- Inliner { tcx, param_env, codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), changed: false };
+ let mut this = Inliner {
+ tcx,
+ param_env,
+ codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
+ history: Vec::new(),
+ changed: false,
+ };
let blocks = BasicBlock::new(0)..body.basic_blocks.next_index();
this.process_blocks(body, blocks);
this.changed
param_env: ParamEnv<'tcx>,
/// Caller codegen attributes.
codegen_fn_attrs: &'tcx CodegenFnAttrs,
+ /// Stack of inlined instances.
+ /// We only check the `DefId` and not the substs because we want to
+ /// avoid inlining cases of polymorphic recursion.
+ /// The number of `DefId`s is finite, so checking history is enough
+ /// to ensure that we do not loop endlessly while inlining.
+ history: Vec<DefId>,
/// Indicates that the caller body has been modified.
changed: bool,
}
impl<'tcx> Inliner<'tcx> {
fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBlock>) {
+ // How many callsites in this body are we allowed to inline? We need to limit this in order
+ // to prevent super-linear growth in MIR size
+ let inline_limit = match self.history.len() {
+ 0 => usize::MAX,
+ 1..=TOP_DOWN_DEPTH_LIMIT => 1,
+ _ => return,
+ };
+ let mut inlined_count = 0;
for bb in blocks {
let bb_data = &caller_body[bb];
if bb_data.is_cleanup {
debug!("not-inlined {} [{}]", callsite.callee, reason);
continue;
}
- Ok(_) => {
+ Ok(new_blocks) => {
debug!("inlined {}", callsite.callee);
self.changed = true;
- // We could process the blocks returned by `try_inlining` here. However, that
- // leads to exponential compile times due to the top-down nature of this kind
- // of inlining.
+ inlined_count += 1;
+ if inlined_count == inline_limit {
+ return;
+ }
+ self.history.push(callsite.callee.def_id());
+ self.process_blocks(caller_body, new_blocks);
+ self.history.pop();
}
}
}
) -> Option<CallSite<'tcx>> {
// Only consider direct calls to functions
let terminator = bb_data.terminator();
- if let TerminatorKind::Call { ref func, target, .. } = terminator.kind {
+ if let TerminatorKind::Call { ref func, target, fn_span, .. } = terminator.kind {
let func_ty = func.ty(caller_body, self.tcx);
if let ty::FnDef(def_id, substs) = *func_ty.kind() {
// To resolve an instance its substs have to be fully normalized.
return None;
}
+ if self.history.contains(&callee.def_id()) {
+ return None;
+ }
+
let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs);
+ let source_info = SourceInfo { span: fn_span, ..terminator.source_info };
- return Some(CallSite {
- callee,
- fn_sig,
- block: bb,
- target,
- source_info: terminator.source_info,
- });
+ return Some(CallSite { callee, fn_sig, block: bb, target, source_info });
}
}
/// Returns the sequence of passes that do the initial cleanup of runtime MIR.
fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let passes: &[&dyn MirPass<'tcx>] = &[
- &elaborate_box_derefs::ElaborateBoxDerefs,
- &lower_intrinsics::LowerIntrinsics,
- &simplify::SimplifyCfg::new("elaborate-drops"),
- ];
+ let passes: &[&dyn MirPass<'tcx>] =
+ &[&lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::new("elaborate-drops")];
pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup)));
}
&multiple_return_terminators::MultipleReturnTerminators,
&instcombine::InstCombine,
&separate_const_switch::SeparateConstSwitch,
+ &simplify::SimplifyLocals::new("before-const-prop"),
//
// FIXME(#70073): This pass is responsible for both optimization as well as some lints.
&const_prop::ConstProp,
&o1(remove_noop_landing_pads::RemoveNoopLandingPads),
&o1(simplify::SimplifyCfg::new("final")),
&nrvo::RenameReturnPlace,
- &simplify::SimplifyLocals,
+ &simplify::SimplifyLocals::new("final"),
&multiple_return_terminators::MultipleReturnTerminators,
&deduplicate_blocks::DeduplicateBlocks,
// Some cleanup necessary at least for LLVM and potentially other codegen backends.
));
}
-pub struct SimplifyLocals;
+pub struct SimplifyLocals {
+ label: String,
+}
+
+impl SimplifyLocals {
+ pub fn new(label: &str) -> SimplifyLocals {
+ SimplifyLocals { label: format!("SimplifyLocals-{}", label) }
+ }
+}
impl<'tcx> MirPass<'tcx> for SimplifyLocals {
+ fn name(&self) -> &str {
+ &self.label
+ }
+
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0
}
StatementKind::SetDiscriminant { ref place, .. }
| StatementKind::Deinit(ref place) => used_locals.is_used(place.local),
+ StatementKind::Nop => false,
_ => true,
};
[lib]
[dependencies]
+serde = "1"
+serde_json = "1"
smallvec = { version = "1.8.1", features = [ "union", "may_dangle" ] }
tracing = "0.1"
rustc_data_structures = { path = "../rustc_data_structures" }
let formatted_item = with_no_trimmed_paths!(starting_point.node.to_string());
tcx.sess.span_note_without_error(
starting_point.span,
- &format!("the above error was encountered while instantiating `{}`", formatted_item),
+ &format!("the above error was encountered while instantiating `{formatted_item}`"),
);
}
inlining_map.lock_mut().record_accesses(starting_point.node, &neighbors.items);
// FIXME: I can figure out how to do a label with a fluent string with a fixed message,
// or a label with a dynamic value in a hard-coded string, but I haven't figured out
// how to combine the two. 😢
- diag.span_label(span, format!("generic parameter `{}` is unused", name));
+ diag.span_label(span, format!("generic parameter `{name}` is unused"));
}
diag
}
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync;
-use rustc_hir::def_id::DefIdSet;
+use rustc_hir::def_id::{DefIdSet, LOCAL_CRATE};
use rustc_middle::mir;
use rustc_middle::mir::mono::MonoItem;
use rustc_middle::mir::mono::{CodegenUnit, Linkage};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
-use rustc_session::config::SwitchWithOptPath;
+use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath};
use rustc_span::symbol::Symbol;
use crate::collector::InliningMap;
use std::fmt::Write;
let s = &mut String::new();
- let _ = writeln!(s, "{}", label);
+ let _ = writeln!(s, "{label}");
for cgu in cgus {
let _ =
writeln!(s, "CodegenUnit {} estimated size {} :", cgu.name(), cgu.size_estimate());
} else {
if mode_string != "lazy" {
let message = format!(
- "Unknown codegen-item collection mode '{}'. \
- Falling back to 'lazy' mode.",
- mode_string
+ "Unknown codegen-item collection mode '{mode_string}'. \
+ Falling back to 'lazy' mode."
);
tcx.sess.warn(&message);
}
// Output monomorphization stats per def_id
if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats {
if let Err(err) =
- dump_mono_items_stats(tcx, &codegen_units, path, tcx.sess.opts.crate_name.as_deref())
+ dump_mono_items_stats(tcx, &codegen_units, path, tcx.crate_name(LOCAL_CRATE))
{
tcx.sess.emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
}
item_keys.sort();
for item in item_keys {
- println!("MONO_ITEM {}", item);
+ println!("MONO_ITEM {item}");
}
}
tcx: TyCtxt<'tcx>,
codegen_units: &[CodegenUnit<'tcx>],
output_directory: &Option<PathBuf>,
- crate_name: Option<&str>,
+ crate_name: Symbol,
) -> Result<(), Box<dyn std::error::Error>> {
let output_directory = if let Some(ref directory) = output_directory {
fs::create_dir_all(directory)?;
Path::new(".")
};
- let filename = format!("{}.mono_items.md", crate_name.unwrap_or("unknown-crate"));
+ let format = tcx.sess.opts.unstable_opts.dump_mono_stats_format;
+ let ext = format.extension();
+ let filename = format!("{crate_name}.mono_items.{ext}");
let output_path = output_directory.join(&filename);
- let file = File::create(output_path)?;
+ let file = File::create(&output_path)?;
let mut file = BufWriter::new(file);
// Gather instantiated mono items grouped by def_id
}
}
+ #[derive(serde::Serialize)]
+ struct MonoItem {
+ name: String,
+ instantiation_count: usize,
+ size_estimate: usize,
+ total_estimate: usize,
+ }
+
// Output stats sorted by total instantiated size, from heaviest to lightest
let mut stats: Vec<_> = items_per_def_id
.into_iter()
.map(|(def_id, items)| {
+ let name = with_no_trimmed_paths!(tcx.def_path_str(def_id));
let instantiation_count = items.len();
let size_estimate = items[0].size_estimate(tcx);
let total_estimate = instantiation_count * size_estimate;
- (def_id, instantiation_count, size_estimate, total_estimate)
+ MonoItem { name, instantiation_count, size_estimate, total_estimate }
})
.collect();
- stats.sort_unstable_by_key(|(_, _, _, total_estimate)| cmp::Reverse(*total_estimate));
+ stats.sort_unstable_by_key(|item| cmp::Reverse(item.total_estimate));
if !stats.is_empty() {
- writeln!(
- file,
- "| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
- )?;
- writeln!(file, "| --- | ---: | ---: | ---: |")?;
- for (def_id, instantiation_count, size_estimate, total_estimate) in stats {
- let item = with_no_trimmed_paths!(tcx.def_path_str(def_id));
- writeln!(
- file,
- "| {item} | {instantiation_count} | {size_estimate} | {total_estimate} |"
- )?;
+ match format {
+ DumpMonoStatsFormat::Json => serde_json::to_writer(file, &stats)?,
+ DumpMonoStatsFormat::Markdown => {
+ writeln!(
+ file,
+ "| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
+ )?;
+ writeln!(file, "| --- | ---: | ---: | ---: |")?;
+
+ for MonoItem { name, instantiation_count, size_estimate, total_estimate } in stats {
+ writeln!(
+ file,
+ "| `{name}` | {instantiation_count} | {size_estimate} | {total_estimate} |"
+ )?;
+ }
+ }
}
}
let (_, all) = tcx.collect_and_partition_mono_items(());
all.iter()
.find(|cgu| cgu.name() == name)
- .unwrap_or_else(|| panic!("failed to find cgu with name {:?}", name))
+ .unwrap_or_else(|| panic!("failed to find cgu with name {name:?}"))
};
}
let new_size = tcx
.layout_of(param_env.and(after_feature_tys))
.map(|l| format!("{:?}", l.size.bytes()))
- .unwrap_or_else(|e| format!("Failed {:?}", e));
+ .unwrap_or_else(|e| format!("Failed {e:?}"));
let old_size = tcx
.layout_of(param_env.and(before_feature_tys))
.map(|l| format!("{:?}", l.size.bytes()))
- .unwrap_or_else(|e| format!("Failed {:?}", e));
+ .unwrap_or_else(|e| format!("Failed {e:?}"));
let closure_span = tcx.def_span(closure_def_id);
let src_file = tcx.sess.source_map().span_to_filename(closure_span);
.source_map()
.span_to_lines(closure_span)
.map(|l| format!("{:?} {:?}", l.lines.first(), l.lines.last()))
- .unwrap_or_else(|e| format!("{:?}", e));
+ .unwrap_or_else(|e| format!("{e:?}"));
if let Err(e) = writeln!(
file,
src_file.prefer_local(),
line_nos
) {
- eprintln!("Error writing to file {}", e)
+ eprintln!("Error writing to file {e}")
}
}
}
#[suggestion(applicability = "maybe-incorrect", code = "impl", style = "verbose")]
pub fn_span: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(parse_expected_fn_path_found_fn_keyword)]
+pub(crate) struct ExpectedFnPathFoundFnKeyword {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = "Fn", style = "verbose")]
+ pub fn_token_span: Span,
+}
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{
- fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult,
+ fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, FatalError, Handler, MultiSpan,
+ PResult,
};
use rustc_errors::{pluralize, Diagnostic, ErrorGuaranteed, IntoDiagnostic};
use rustc_session::errors::ExprParenthesesNeeded;
use std::mem::take;
use std::ops::{Deref, DerefMut};
use thin_vec::{thin_vec, ThinVec};
-use tracing::{debug, trace};
/// Creates a placeholder argument.
pub(super) fn dummy_arg(ident: Ident) -> Param {
return if token::ModSep == self.token.kind {
// We have some certainty that this was a bad turbofish at this point.
// `foo< bar >::`
- err.suggest_turbofish = Some(op.span.shrink_to_lo());
+ if let ExprKind::Binary(o, ..) = inner_op.kind && o.node == BinOpKind::Lt {
+ err.suggest_turbofish = Some(op.span.shrink_to_lo());
+ } else {
+ err.help_turbofish = Some(());
+ }
let snapshot = self.create_snapshot_for_diagnostic();
self.bump(); // `::`
} else if token::OpenDelim(Delimiter::Parenthesis) == self.token.kind {
// We have high certainty that this was a bad turbofish at this point.
// `foo< bar >(`
- err.suggest_turbofish = Some(op.span.shrink_to_lo());
+ if let ExprKind::Binary(o, ..) = inner_op.kind && o.node == BinOpKind::Lt {
+ err.suggest_turbofish = Some(op.span.shrink_to_lo());
+ } else {
+ err.help_turbofish = Some(());
+ }
// Consume the fn call arguments.
match self.consume_fn_args() {
Err(()) => Err(err.into_diagnostic(&self.sess.span_diagnostic)),
let sum_span = ty.span.to(self.prev_token.span);
let sub = match &ty.kind {
- TyKind::Rptr(lifetime, mut_ty) => {
+ TyKind::Ref(lifetime, mut_ty) => {
let sum_with_parens = pprust::to_string(|s| {
s.s.word("&");
s.print_opt_lifetime(lifetime);
Ok(())
}
+ pub fn is_diff_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> bool {
+ (0..3).all(|i| self.look_ahead(i, |tok| tok == long_kind))
+ && self.look_ahead(3, |tok| tok == short_kind)
+ }
+
+ fn diff_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> Option<Span> {
+ if self.is_diff_marker(long_kind, short_kind) {
+ let lo = self.token.span;
+ for _ in 0..4 {
+ self.bump();
+ }
+ return Some(lo.to(self.prev_token.span));
+ }
+ None
+ }
+
+ pub fn recover_diff_marker(&mut self) {
+ let Some(start) = self.diff_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) else {
+ return;
+ };
+ let mut spans = Vec::with_capacity(3);
+ spans.push(start);
+ let mut middlediff3 = None;
+ let mut middle = None;
+ let mut end = None;
+ loop {
+ if self.token.kind == TokenKind::Eof {
+ break;
+ }
+ if let Some(span) = self.diff_marker(&TokenKind::OrOr, &TokenKind::BinOp(token::Or)) {
+ middlediff3 = Some(span);
+ }
+ if let Some(span) = self.diff_marker(&TokenKind::EqEq, &TokenKind::Eq) {
+ middle = Some(span);
+ }
+ if let Some(span) = self.diff_marker(&TokenKind::BinOp(token::Shr), &TokenKind::Gt) {
+ spans.push(span);
+ end = Some(span);
+ break;
+ }
+ self.bump();
+ }
+ let mut err = self.struct_span_err(spans, "encountered diff marker");
+ err.span_label(start, "after this is the code before the merge");
+ if let Some(middle) = middlediff3 {
+ err.span_label(middle, "");
+ }
+ if let Some(middle) = middle {
+ err.span_label(middle, "");
+ }
+ if let Some(end) = end {
+ err.span_label(end, "above this are the incoming code changes");
+ }
+ err.help(
+ "if you're having merge conflicts after pulling new code, the top section is the code \
+ you already had and the bottom section is the remote code",
+ );
+ err.help(
+ "if you're in the middle of a rebase, the top section is the code being rebased onto \
+ and the bottom section is the code coming from the current commit being rebased",
+ );
+ err.note(
+ "for an explanation on these markers from the `git` documentation, visit \
+ <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>",
+ );
+ err.emit();
+ FatalError.raise()
+ }
+
/// Parse and throw away a parenthesized comma separated
/// sequence of patterns until `)` is reached.
fn skip_pat_list(&mut self) -> PResult<'a, ()> {
prior_type_ascription: self.last_type_ascription,
});
(lo.to(self.prev_token.span), ExprKind::MacCall(mac))
- } else if self.check(&token::OpenDelim(Delimiter::Brace)) &&
- let Some(expr) = self.maybe_parse_struct_expr(&qself, &path) {
- if qself.is_some() {
- self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
- }
- return expr;
+ } else if self.check(&token::OpenDelim(Delimiter::Brace))
+ && let Some(expr) = self.maybe_parse_struct_expr(&qself, &path)
+ {
+ if qself.is_some() {
+ self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
+ }
+ return expr;
} else {
(path.span, ExprKind::Path(qself, path))
};
/// Parses `ident (COLON expr)?`.
fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
let attrs = self.parse_outer_attributes()?;
+ self.recover_diff_marker();
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
let lo = this.token.span;
use rustc_span::DUMMY_SP;
use std::mem;
use thin_vec::ThinVec;
-use tracing::debug;
impl<'a> Parser<'a> {
/// Parses a source module as a crate. This is the main entry point for the parser.
fn_parse_mode: FnParseMode,
force_collect: ForceCollect,
) -> PResult<'a, Option<Item>> {
+ self.recover_diff_marker();
let attrs = self.parse_outer_attributes()?;
+ self.recover_diff_marker();
self.parse_item_common(attrs, true, false, fn_parse_mode, force_collect)
}
if self.recover_doc_comment_before_brace() {
continue;
}
+ self.recover_diff_marker();
match parse_item(self) {
Ok(None) => {
let mut is_unnecessary_semicolon = !items.is_empty()
/// USE_TREE_LIST = Ø | (USE_TREE `,`)* USE_TREE [`,`]
/// ```
fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> {
- self.parse_delim_comma_seq(Delimiter::Brace, |p| Ok((p.parse_use_tree()?, DUMMY_NODE_ID)))
- .map(|(r, _)| r)
+ self.parse_delim_comma_seq(Delimiter::Brace, |p| {
+ p.recover_diff_marker();
+ Ok((p.parse_use_tree()?, DUMMY_NODE_ID))
+ })
+ .map(|(r, _)| r)
}
fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
}
fn parse_enum_variant(&mut self) -> PResult<'a, Option<Variant>> {
+ self.recover_diff_marker();
let variant_attrs = self.parse_outer_attributes()?;
+ self.recover_diff_marker();
self.collect_tokens_trailing_token(
variant_attrs,
ForceCollect::No,
self.parse_paren_comma_seq(|p| {
let attrs = p.parse_outer_attributes()?;
p.collect_tokens_trailing_token(attrs, ForceCollect::No, |p, attrs| {
+ let mut snapshot = None;
+ if p.is_diff_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) {
+ // Account for `<<<<<<<` diff markers. We can't proactively error here because
+ // that can be a valid type start, so we snapshot and reparse only we've
+ // encountered another parse error.
+ snapshot = Some(p.create_snapshot_for_diagnostic());
+ }
let lo = p.token.span;
- let vis = p.parse_visibility(FollowedByType::Yes)?;
- let ty = p.parse_ty()?;
+ let vis = match p.parse_visibility(FollowedByType::Yes) {
+ Ok(vis) => vis,
+ Err(err) => {
+ if let Some(ref mut snapshot) = snapshot {
+ snapshot.recover_diff_marker();
+ }
+ return Err(err);
+ }
+ };
+ let ty = match p.parse_ty() {
+ Ok(ty) => ty,
+ Err(err) => {
+ if let Some(ref mut snapshot) = snapshot {
+ snapshot.recover_diff_marker();
+ }
+ return Err(err);
+ }
+ };
Ok((
FieldDef {
/// Parses an element of a struct declaration.
fn parse_field_def(&mut self, adt_ty: &str) -> PResult<'a, FieldDef> {
+ self.recover_diff_marker();
let attrs = self.parse_outer_attributes()?;
+ self.recover_diff_marker();
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
let lo = this.token.span;
let vis = this.parse_visibility(FollowedByType::No)?;
}
/// Parses the parameter list of a function, including the `(` and `)` delimiters.
- fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, Vec<Param>> {
+ pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, Vec<Param>> {
let mut first_param = true;
// Parse the arguments, starting out with `self` being allowed...
let (mut params, _) = self.parse_paren_comma_seq(|p| {
+ p.recover_diff_marker();
let param = p.parse_param_general(req_name, first_param).or_else(|mut e| {
e.emit();
let lo = p.prev_token.span;
};
let (pat, ty) = if is_name_required || this.is_named_param() {
debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
-
let (pat, colon) = this.parse_fn_param_pat_colon()?;
if !colon {
let mut err = this.unexpected::<()>().unwrap_err();
// required to wrap the text. E.g.
// - `abc d` is wrapped as `r"abc d"` (num_of_hashes = 0)
// - `abc "d"` is wrapped as `r#"abc "d""#` (num_of_hashes = 1)
- // - `abc "##d##"` is wrapped as `r###"abc "d""###` (num_of_hashes = 3)
+ // - `abc "##d##"` is wrapped as `r###"abc ##"d"##"###` (num_of_hashes = 3)
let mut num_of_hashes = 0;
let mut count = 0;
for ch in data.as_str().chars() {
pub fn clear_expected_tokens(&mut self) {
self.expected_tokens.clear();
}
+
+ pub fn approx_token_stream_pos(&self) -> usize {
+ self.token_cursor.num_next_calls
+ }
}
pub(crate) fn make_unclosed_delims_error(
if let PatKind::Ident(_, _, sub @ None) = &mut rhs.kind {
// The user inverted the order, so help them fix that.
- let mut applicability = Applicability::MachineApplicable;
- // FIXME(bindings_after_at): Remove this code when stabilizing the feature.
- lhs.walk(&mut |p| match p.kind {
- // `check_match` is unhappy if the subpattern has a binding anywhere.
- PatKind::Ident(..) => {
- applicability = Applicability::MaybeIncorrect;
- false // Short-circuit.
- }
- _ => true,
- });
-
let lhs_span = lhs.span;
// Move the LHS into the RHS as a subpattern.
// The RHS is now the full pattern.
self.struct_span_err(sp, "pattern on wrong side of `@`")
.span_label(lhs_span, "pattern on the left, should be on the right")
.span_label(rhs.span, "binding on the right, should be on the left")
- .span_suggestion(sp, "switch the order", pprust::pat_to_string(&rhs), applicability)
+ .span_suggestion(
+ sp,
+ "switch the order",
+ pprust::pat_to_string(&rhs),
+ Applicability::MachineApplicable,
+ )
.emit();
} else {
// The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`.
recover: AttemptLocalParseRecovery,
) -> PResult<'a, P<Block>> {
let mut stmts = vec![];
+ let mut snapshot = None;
while !self.eat(&token::CloseDelim(Delimiter::Brace)) {
if self.token == token::Eof {
break;
}
+ if self.is_diff_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) {
+ // Account for `<<<<<<<` diff markers. We can't proactively error here because
+ // that can be a valid path start, so we snapshot and reparse only we've
+ // encountered another parse error.
+ snapshot = Some(self.create_snapshot_for_diagnostic());
+ }
let stmt = match self.parse_full_stmt(recover) {
Err(mut err) if recover.yes() => {
self.maybe_annotate_with_ascription(&mut err, false);
+ if let Some(ref mut snapshot) = snapshot {
+ snapshot.recover_diff_marker();
+ }
err.emit();
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
Some(self.mk_stmt_err(self.token.span))
use super::{Parser, PathStyle, TokenType};
-use crate::errors::{FnPtrWithGenerics, FnPtrWithGenericsSugg};
+use crate::errors::{ExpectedFnPathFoundFnKeyword, FnPtrWithGenerics, FnPtrWithGenericsSugg};
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
+use ast::DUMMY_NODE_ID;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::util::case::Case;
};
use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
use rustc_span::source_map::Span;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::Symbol;
+use thin_vec::thin_vec;
/// Any `?` or `~const` modifiers that appear at the start of a bound.
struct BoundModifiers {
self.bump_with((dyn_tok, dyn_tok_sp));
}
let ty = self.parse_ty_no_plus()?;
- Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl }))
+ Ok(TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }))
}
// Parses the `typeof(EXPR)`.
/// Parses an `impl B0 + ... + Bn` type.
fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {
// Always parse bounds greedily for better error recovery.
+ if self.token.is_lifetime() {
+ self.look_ahead(1, |t| {
+ if let token::Ident(symname, _) = t.kind {
+ // parse pattern with "'a Sized" we're supposed to give suggestion like
+ // "'a + Sized"
+ self.struct_span_err(
+ self.token.span,
+ &format!("expected `+` between lifetime and {}", symname),
+ )
+ .span_suggestion_verbose(
+ self.token.span.shrink_to_hi(),
+ "add `+`",
+ " +",
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ }
+ })
+ }
let bounds = self.parse_generic_bounds(None)?;
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
has_parens: bool,
modifiers: BoundModifiers,
) -> PResult<'a, GenericBound> {
- let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
- let path = self.parse_path(PathStyle::Type)?;
+ let mut lifetime_defs = self.parse_late_bound_lifetime_defs()?;
+ let mut path = if self.token.is_keyword(kw::Fn)
+ && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
+ && let Some(path) = self.recover_path_from_fn()
+ {
+ path
+ } else {
+ self.parse_path(PathStyle::Type)?
+ };
+
+ if self.may_recover() && self.token == TokenKind::OpenDelim(Delimiter::Parenthesis) {
+ self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?;
+ }
+
if has_parens {
if self.token.is_like_plus() {
// Someone has written something like `&dyn (Trait + Other)`. The correct code
Ok(GenericBound::Trait(poly_trait, modifier))
}
+ // recovers a `Fn(..)` parenthesized-style path from `fn(..)`
+ fn recover_path_from_fn(&mut self) -> Option<ast::Path> {
+ let fn_token_span = self.token.span;
+ self.bump();
+ let args_lo = self.token.span;
+ let snapshot = self.create_snapshot_for_diagnostic();
+ match self.parse_fn_decl(|_| false, AllowPlus::No, RecoverReturnSign::OnlyFatArrow) {
+ Ok(decl) => {
+ self.sess.emit_err(ExpectedFnPathFoundFnKeyword { fn_token_span });
+ Some(ast::Path {
+ span: fn_token_span.to(self.prev_token.span),
+ segments: thin_vec![ast::PathSegment {
+ ident: Ident::new(Symbol::intern("Fn"), fn_token_span),
+ id: DUMMY_NODE_ID,
+ args: Some(P(ast::GenericArgs::Parenthesized(ast::ParenthesizedArgs {
+ span: args_lo.to(self.prev_token.span),
+ inputs: decl.inputs.iter().map(|a| a.ty.clone()).collect(),
+ inputs_span: args_lo.until(decl.output.span()),
+ output: decl.output.clone(),
+ }))),
+ }],
+ tokens: None,
+ })
+ }
+ Err(diag) => {
+ diag.cancel();
+ self.restore_snapshot(snapshot);
+ None
+ }
+ }
+ }
+
/// Optionally parses `for<$generic_params>`.
pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<GenericParam>> {
if self.eat_keyword(kw::For) {
}
}
+ /// Recover from `Fn`-family traits (Fn, FnMut, FnOnce) with lifetime arguments
+ /// (e.g. `FnOnce<'a>(&'a str) -> bool`). Up to generic arguments have already
+ /// been eaten.
+ fn recover_fn_trait_with_lifetime_params(
+ &mut self,
+ fn_path: &mut ast::Path,
+ lifetime_defs: &mut Vec<GenericParam>,
+ ) -> PResult<'a, ()> {
+ let fn_path_segment = fn_path.segments.last_mut().unwrap();
+ let generic_args = if let Some(p_args) = &fn_path_segment.args {
+ p_args.clone().into_inner()
+ } else {
+ // Normally it wouldn't come here because the upstream should have parsed
+ // generic parameters (otherwise it's impossible to call this function).
+ return Ok(());
+ };
+ let lifetimes =
+ if let ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { span: _, args }) =
+ &generic_args
+ {
+ args.into_iter()
+ .filter_map(|arg| {
+ if let ast::AngleBracketedArg::Arg(generic_arg) = arg
+ && let ast::GenericArg::Lifetime(lifetime) = generic_arg {
+ Some(lifetime)
+ } else {
+ None
+ }
+ })
+ .collect()
+ } else {
+ Vec::new()
+ };
+ // Only try to recover if the trait has lifetime params.
+ if lifetimes.is_empty() {
+ return Ok(());
+ }
+
+ // Parse `(T, U) -> R`.
+ let inputs_lo = self.token.span;
+ let inputs: Vec<_> =
+ self.parse_fn_params(|_| false)?.into_iter().map(|input| input.ty).collect();
+ let inputs_span = inputs_lo.to(self.prev_token.span);
+ let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?;
+ let args = ast::ParenthesizedArgs {
+ span: fn_path_segment.span().to(self.prev_token.span),
+ inputs,
+ inputs_span,
+ output,
+ }
+ .into();
+ *fn_path_segment =
+ ast::PathSegment { ident: fn_path_segment.ident, args, id: ast::DUMMY_NODE_ID };
+
+ // Convert parsed `<'a>` in `Fn<'a>` into `for<'a>`.
+ let mut generic_params = lifetimes
+ .iter()
+ .map(|lt| GenericParam {
+ id: lt.id,
+ ident: lt.ident,
+ attrs: ast::AttrVec::new(),
+ bounds: Vec::new(),
+ is_placeholder: false,
+ kind: ast::GenericParamKind::Lifetime,
+ colon_span: None,
+ })
+ .collect::<Vec<GenericParam>>();
+ lifetime_defs.append(&mut generic_params);
+
+ let generic_args_span = generic_args.span();
+ let mut err =
+ self.struct_span_err(generic_args_span, "`Fn` traits cannot take lifetime parameters");
+ let snippet = format!(
+ "for<{}> ",
+ lifetimes.iter().map(|lt| lt.ident.as_str()).intersperse(", ").collect::<String>(),
+ );
+ let before_fn_path = fn_path.span.shrink_to_lo();
+ err.multipart_suggestion(
+ "consider using a higher-ranked trait bound instead",
+ vec![(generic_args_span, "".to_owned()), (before_fn_path, snippet)],
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ Ok(())
+ }
+
pub(super) fn check_lifetime(&mut self) -> bool {
self.expected_tokens.push(TokenType::Lifetime);
self.token.is_lifetime()
pub use Piece::*;
pub use Position::*;
+use rustc_lexer::unescape;
use std::iter;
use std::str;
use std::string;
}
}
+/// Whether the input string is a literal. If yes, it contains the inner width mappings.
+#[derive(Clone, PartialEq, Eq)]
+enum InputStringKind {
+ NotALiteral,
+ Literal { width_mappings: Vec<InnerWidthMapping> },
+}
+
/// The type of format string that we are parsing.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ParseMode {
append_newline: bool,
mode: ParseMode,
) -> Parser<'a> {
- let (width_map, is_literal) = find_width_map_from_snippet(snippet, style);
+ let input_string_kind = find_width_map_from_snippet(s, snippet, style);
+ let (width_map, is_literal) = match input_string_kind {
+ InputStringKind::Literal { width_mappings } => (width_mappings, true),
+ InputStringKind::NotALiteral => (Vec::new(), false),
+ };
Parser {
mode,
input: s,
Some(pos)
} else {
let pos = self.to_span_index(pos);
- let description = format!("expected `'}}'`, found `{:?}`", maybe);
+ let description = format!("expected `'}}'`, found `{maybe:?}`");
let label = "expected `}`".to_owned();
let (note, secondary_label) = if c == '}' {
(
None
}
} else {
- let description = format!("expected `{:?}` but string was terminated", c);
+ let description = format!("expected `{c:?}` but string was terminated");
// point at closing `"`
let pos = self.input.len() - if self.append_newline { 1 } else { 0 };
let pos = self.to_span_index(pos);
if c == '}' {
- let label = format!("expected `{:?}`", c);
+ let label = format!("expected `{c:?}`");
let (note, secondary_label) = if c == '}' {
(
Some(
should_be_replaced_with_positional_argument: false,
});
} else {
- self.err(description, format!("expected `{:?}`", c), pos.to(pos));
+ self.err(description, format!("expected `{c:?}`"), pos.to(pos));
}
None
}
/// written code (code snippet) and the `InternedString` that gets processed in the `Parser`
/// in order to properly synthesise the intra-string `Span`s for error diagnostics.
fn find_width_map_from_snippet(
+ input: &str,
snippet: Option<string::String>,
str_style: Option<usize>,
-) -> (Vec<InnerWidthMapping>, bool) {
+) -> InputStringKind {
let snippet = match snippet {
Some(ref s) if s.starts_with('"') || s.starts_with("r\"") || s.starts_with("r#") => s,
- _ => return (vec![], false),
+ _ => return InputStringKind::NotALiteral,
};
if str_style.is_some() {
- return (vec![], true);
+ return InputStringKind::Literal { width_mappings: Vec::new() };
}
+ // Strip quotes.
let snippet = &snippet[1..snippet.len() - 1];
+ // Macros like `println` add a newline at the end. That technically doens't make them "literals" anymore, but it's fine
+ // since we will never need to point our spans there, so we lie about it here by ignoring it.
+ // Since there might actually be newlines in the source code, we need to normalize away all trailing newlines.
+ // If we only trimmed it off the input, `format!("\n")` would cause a mismatch as here we they actually match up.
+ // Alternatively, we could just count the trailing newlines and only trim one from the input if they don't match up.
+ let input_no_nl = input.trim_end_matches('\n');
+ let Ok(unescaped) = unescape_string(snippet) else {
+ return InputStringKind::NotALiteral;
+ };
+
+ let unescaped_no_nl = unescaped.trim_end_matches('\n');
+
+ if unescaped_no_nl != input_no_nl {
+ // The source string that we're pointing at isn't our input, so spans pointing at it will be incorrect.
+ // This can for example happen with proc macros that respan generated literals.
+ return InputStringKind::NotALiteral;
+ }
+
let mut s = snippet.char_indices();
let mut width_mappings = vec![];
while let Some((pos, c)) = s.next() {
_ => {}
}
}
- (width_mappings, true)
+
+ InputStringKind::Literal { width_mappings }
+}
+
+fn unescape_string(string: &str) -> Result<string::String, unescape::EscapeError> {
+ let mut buf = string::String::new();
+ let mut error = Ok(());
+ unescape::unescape_literal(string, unescape::Mode::Str, &mut |_, unescaped_char| {
+ match unescaped_char {
+ Ok(c) => buf.push(c),
+ Err(err) => error = Err(err),
+ }
+ });
+
+ error.map(|_| buf)
}
// Assert a reasonable size for `Piece`
Slice,
Array,
Ptr,
- Rptr,
+ Ref,
BareFn,
Never,
Tup,
Slice,
Array,
Ptr,
- Rptr,
+ Ref,
BareFn,
Never,
Tup,
if level != Level::Direct {
error_msg.push_str(", ");
}
- error_msg.push_str(&format!("{:?}: {}", level, vis_str));
+ error_msg.push_str(&format!("{level:?}: {vis_str}"));
}
} else {
error_msg.push_str("not in the table");
self.tcx.types.never,
);
- for (trait_predicate, _, _) in bounds.trait_bounds {
- if self.visit_trait(trait_predicate.skip_binder()).is_break() {
- return;
- }
- }
-
- for (poly_predicate, _) in bounds.projection_bounds {
- let pred = poly_predicate.skip_binder();
- let poly_pred_term = self.visit(pred.term);
- if poly_pred_term.is_break()
- || self.visit_projection_ty(pred.projection_ty).is_break()
- {
- return;
+ for (pred, _) in bounds.predicates() {
+ match pred.kind().skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
+ if self.visit_trait(trait_predicate.trait_ref).is_break() {
+ return;
+ }
+ }
+ ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) => {
+ let term = self.visit(proj_predicate.term);
+ if term.is_break()
+ || self.visit_projection_ty(proj_predicate.projection_ty).is_break()
+ {
+ return;
+ }
+ }
+ _ => {}
}
}
}
if !old_error_set_ancestry.insert(id) {
break;
}
- let parent = tcx.hir().get_parent_node(id);
+ let parent = tcx.hir().parent_id(id);
if parent == id {
break;
}
edition = "2021"
[lib]
-doctest = false
+
[dependencies]
measureme = "10.0.0"
pub use rustc_query_system::query::{deadlock, QueryContext};
pub use rustc_query_system::query::QueryConfig;
-pub(crate) use rustc_query_system::query::QueryVTable;
mod on_disk_cache;
pub use on_disk_cache::OnDiskCache;
// which means that the definition with this hash is guaranteed to
// still exist in the current compilation session.
d.tcx.def_path_hash_to_def_id(def_path_hash, &mut || {
- panic!("Failed to convert DefPathHash {:?}", def_path_hash)
+ panic!("Failed to convert DefPathHash {def_path_hash:?}")
})
}
}
ty::print::with_forced_impl_filename_line!(do_describe(tcx.tcx, key))
);
let description =
- if tcx.sess.verbose() { format!("{} [{:?}]", description, name) } else { description };
+ if tcx.sess.verbose() { format!("{description} [{name:?}]") } else { description };
let span = if kind == dep_graph::DepKind::def_span {
// The `def_span` query is used to calculate `default_span`,
// so exit to avoid infinite recursion.
&tcx.query_caches.$name
}
+ fn execute_query(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Stored {
+ tcx.$name(key)
+ }
+
#[inline]
- fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
- QueryVTable<QueryCtxt<'tcx>, Self::Key, Self::Value>
- {
- let compute = get_provider!([$($modifiers)*][tcx, $name, key]);
- let cache_on_disk = Self::cache_on_disk(tcx.tcx, key);
- QueryVTable {
- anon: is_anon!([$($modifiers)*]),
- eval_always: is_eval_always!([$($modifiers)*]),
- depth_limit: depth_limit!([$($modifiers)*]),
- feedable: feedable!([$($modifiers)*]),
- dep_kind: dep_graph::DepKind::$name,
- hash_result: hash_result!([$($modifiers)*]),
- handle_cycle_error: handle_cycle_error!([$($modifiers)*]),
- compute,
- try_load_from_disk: if cache_on_disk { should_ever_cache_on_disk!([$($modifiers)*]) } else { None },
- }
+ // key is only sometimes used
+ #[allow(unused_variables)]
+ fn compute(qcx: QueryCtxt<'tcx>, key: &Self::Key) -> fn(TyCtxt<'tcx>, Self::Key) -> Self::Value {
+ get_provider!([$($modifiers)*][qcx, $name, key])
}
- fn execute_query(tcx: TyCtxt<'tcx>, k: Self::Key) -> Self::Stored {
- tcx.$name(k)
+ #[inline]
+ fn try_load_from_disk(qcx: QueryCtxt<'tcx>, key: &Self::Key) -> rustc_query_system::query::TryLoadFromDisk<QueryCtxt<'tcx>, Self> {
+ let cache_on_disk = Self::cache_on_disk(qcx.tcx, key);
+ if cache_on_disk { should_ever_cache_on_disk!([$($modifiers)*]) } else { None }
}
+
+ const ANON: bool = is_anon!([$($modifiers)*]);
+ const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
+ const DEPTH_LIMIT: bool = depth_limit!([$($modifiers)*]);
+ const FEEDABLE: bool = feedable!([$($modifiers)*]);
+
+ const DEP_KIND: rustc_middle::dep_graph::DepKind = dep_graph::DepKind::$name;
+ const HANDLE_CYCLE_ERROR: rustc_query_system::HandleCycleError = handle_cycle_error!([$($modifiers)*]);
+
+ const HASH_RESULT: rustc_query_system::query::HashResult<QueryCtxt<'tcx>, Self> = hash_result!([$($modifiers)*]);
})*
#[allow(nonstandard_style)]
&self,
builder: &mut QueryKeyStringBuilder<'_, '_>,
) -> StringId {
- let s = format!("{:?}", self);
+ let s = format!("{self:?}");
builder.profiler.alloc_string(&s[..])
}
}
/// Tests whether `node` meets the filter, returning true if so.
pub fn test<K: DepKind>(&self, node: &DepNode<K>) -> bool {
- let debug_str = format!("{:?}", node);
+ let debug_str = format!("{node:?}");
self.text.split('&').map(|s| s.trim()).all(|f| debug_str.contains(f))
}
}
pub fn new(test: &str) -> Result<EdgeFilter<K>, Box<dyn Error>> {
let parts: Vec<_> = test.split("->").collect();
if parts.len() != 2 {
- Err(format!("expected a filter like `a&b -> c&d`, not `{}`", test).into())
+ Err(format!("expected a filter like `a&b -> c&d`, not `{test}`").into())
} else {
Ok(EdgeFilter {
source: DepNodeFilter::new(parts[0]),
}
fn to_debug_str(&self, _: Tcx) -> String {
- format!("{:?}", self)
+ format!("{self:?}")
}
/// This method tries to recover the query key from the given `DepNode`,
assert!(
!self.dep_node_exists(&key),
"forcing query with already existing `DepNode`\n\
- - query-key: {:?}\n\
- - dep-node: {:?}",
- arg,
- key
+ - query-key: {arg:?}\n\
+ - dep-node: {key:?}"
);
let task_deps = if cx.dep_context().is_eval_always(key.kind) {
debug_assert!(
data.colors.get(prev_index).is_none(),
"DepGraph::with_task() - Duplicate DepNodeColor \
- insertion for {:?}",
- key
+ insertion for {key:?}"
);
data.colors.insert(prev_index, color);
TaskDepsRef::Allow(deps) => deps.lock(),
TaskDepsRef::Ignore => return,
TaskDepsRef::Forbid => {
- panic!("Illegal read of: {:?}", dep_node_index)
+ panic!("Illegal read of: {dep_node_index:?}")
}
};
let task_deps = &mut *task_deps;
if dep_node_debug.borrow().contains_key(&dep_node) {
return;
}
- let debug_str = debug_str_gen();
+ let debug_str = self.with_ignore(debug_str_gen);
dep_node_debug.borrow_mut().insert(dep_node, debug_str);
}
debug_assert!(
data.colors.get(prev_dep_node_index).is_none(),
"DepGraph::try_mark_previous_green() - Duplicate DepNodeColor \
- insertion for {:?}",
- dep_node
+ insertion for {dep_node:?}"
);
if !side_effects.is_empty() {
- self.emit_side_effects(qcx, data, dep_node_index, side_effects);
+ self.with_query_deserialization(|| {
+ self.emit_side_effects(qcx, data, dep_node_index, side_effects)
+ });
}
// ... and finally storing a "Green" entry in the color map.
if let Some(fingerprint) = fingerprint {
if fingerprint == prev_graph.fingerprint_by_index(prev_index) {
if print_status {
- eprintln!("[task::green] {:?}", key);
+ eprintln!("[task::green] {key:?}");
}
// This is a green node: it existed in the previous compilation,
(dep_node_index, Some((prev_index, DepNodeColor::Green(dep_node_index))))
} else {
if print_status {
- eprintln!("[task::red] {:?}", key);
+ eprintln!("[task::red] {key:?}");
}
// This is a red node: it existed in the previous compilation, its query
}
} else {
if print_status {
- eprintln!("[task::unknown] {:?}", key);
+ eprintln!("[task::unknown] {key:?}");
}
// This is a red node, effectively: it existed in the previous compilation
}
} else {
if print_status {
- eprintln!("[task::new] {:?}", key);
+ eprintln!("[task::new] {key:?}");
}
let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO);
eprintln!("[incremental]");
eprintln!("[incremental] DepGraph Statistics");
- eprintln!("{}", SEPARATOR);
+ eprintln!("{SEPARATOR}");
eprintln!("[incremental]");
eprintln!("[incremental] Total Node Count: {}", status.total_node_count);
eprintln!("[incremental] Total Edge Count: {}", status.total_edge_count);
if cfg!(debug_assertions) {
- eprintln!("[incremental] Total Edge Reads: {}", total_read_count);
- eprintln!(
- "[incremental] Total Duplicate Edge Reads: {}",
- total_duplicate_read_count
- );
+ eprintln!("[incremental] Total Edge Reads: {total_read_count}");
+ eprintln!("[incremental] Total Duplicate Edge Reads: {total_duplicate_read_count}");
}
eprintln!("[incremental]");
"[incremental] {:<36}| {:<17}| {:<12}| {:<17}|",
"Node Kind", "Node Frequency", "Node Count", "Avg. Edge Count"
);
- eprintln!("{}", SEPARATOR);
+ eprintln!("{SEPARATOR}");
for stat in stats {
let node_kind_ratio =
);
}
- eprintln!("{}", SEPARATOR);
+ eprintln!("{SEPARATOR}");
eprintln!("[incremental]");
}
}
//! Query configuration and description traits.
-use crate::dep_graph::DepNode;
-use crate::dep_graph::SerializedDepNodeIndex;
+use crate::dep_graph::{DepNode, DepNodeParams, SerializedDepNodeIndex};
use crate::error::HandleCycleError;
use crate::ich::StableHashingContext;
use crate::query::caches::QueryCache;
use std::fmt::Debug;
use std::hash::Hash;
+pub type HashResult<Qcx, Q> =
+ Option<fn(&mut StableHashingContext<'_>, &<Q as QueryConfig<Qcx>>::Value) -> Fingerprint>;
+
+pub type TryLoadFromDisk<Qcx, Q> =
+ Option<fn(Qcx, SerializedDepNodeIndex) -> Option<<Q as QueryConfig<Qcx>>::Value>>;
+
pub trait QueryConfig<Qcx: QueryContext> {
const NAME: &'static str;
- type Key: Eq + Hash + Clone + Debug;
+ type Key: DepNodeParams<Qcx::DepContext> + Eq + Hash + Clone + Debug;
type Value: Debug;
type Stored: Debug + Clone + std::borrow::Borrow<Self::Value>;
where
Qcx: 'a;
- // Don't use this method to compute query results, instead use the methods on TyCtxt
- fn make_vtable(tcx: Qcx, key: &Self::Key) -> QueryVTable<Qcx, Self::Key, Self::Value>;
-
fn cache_on_disk(tcx: Qcx::DepContext, key: &Self::Key) -> bool;
// Don't use this method to compute query results, instead use the methods on TyCtxt
fn execute_query(tcx: Qcx::DepContext, k: Self::Key) -> Self::Stored;
-}
-#[derive(Copy, Clone)]
-pub struct QueryVTable<Qcx: QueryContext, K, V> {
- pub anon: bool,
- pub dep_kind: Qcx::DepKind,
- pub eval_always: bool,
- pub depth_limit: bool,
- pub feedable: bool,
-
- pub compute: fn(Qcx::DepContext, K) -> V,
- pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
- pub handle_cycle_error: HandleCycleError,
- // NOTE: this is also `None` if `cache_on_disk()` returns false, not just if it's unsupported by the query
- pub try_load_from_disk: Option<fn(Qcx, SerializedDepNodeIndex) -> Option<V>>,
-}
+ fn compute(tcx: Qcx, key: &Self::Key) -> fn(Qcx::DepContext, Self::Key) -> Self::Value;
-impl<Qcx: QueryContext, K, V> QueryVTable<Qcx, K, V> {
- pub(crate) fn to_dep_node(&self, tcx: Qcx::DepContext, key: &K) -> DepNode<Qcx::DepKind>
- where
- K: crate::dep_graph::DepNodeParams<Qcx::DepContext>,
- {
- DepNode::construct(tcx, self.dep_kind, key)
- }
+ fn try_load_from_disk(qcx: Qcx, idx: &Self::Key) -> TryLoadFromDisk<Qcx, Self>;
+
+ const ANON: bool;
+ const EVAL_ALWAYS: bool;
+ const DEPTH_LIMIT: bool;
+ const FEEDABLE: bool;
+
+ const DEP_KIND: Qcx::DepKind;
+ const HANDLE_CYCLE_ERROR: HandleCycleError;
+
+ const HASH_RESULT: HashResult<Qcx, Self>;
- pub(crate) fn compute(&self, tcx: Qcx::DepContext, key: K) -> V {
- (self.compute)(tcx, key)
+ // Just here for convernience and checking that the key matches the kind, don't override this.
+ fn construct_dep_node(tcx: Qcx::DepContext, key: &Self::Key) -> DepNode<Qcx::DepKind> {
+ DepNode::construct(tcx, Self::DEP_KIND, key)
}
}
};
mod config;
-pub use self::config::{QueryConfig, QueryVTable};
+pub use self::config::{HashResult, QueryConfig, TryLoadFromDisk};
use crate::dep_graph::DepKind;
use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
//! generate the actual methods on tcx which find and execute the provider,
//! manage the caches, and so forth.
-use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams};
+use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex};
use crate::ich::StableHashingContext;
use crate::query::caches::QueryCache;
-use crate::query::config::QueryVTable;
use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo};
use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
use crate::values::Value;
})
}
-fn try_execute_query<Qcx, C>(
+fn try_execute_query<Q, Qcx>(
qcx: Qcx,
- state: &QueryState<C::Key, Qcx::DepKind>,
- cache: &C,
+ state: &QueryState<Q::Key, Qcx::DepKind>,
+ cache: &Q::Cache,
span: Span,
- key: C::Key,
+ key: Q::Key,
dep_node: Option<DepNode<Qcx::DepKind>>,
- query: &QueryVTable<Qcx, C::Key, C::Value>,
-) -> (C::Stored, Option<DepNodeIndex>)
+) -> (Q::Stored, Option<DepNodeIndex>)
where
- C: QueryCache,
- C::Key: Clone + DepNodeParams<Qcx::DepContext>,
- C::Value: Value<Qcx::DepContext, Qcx::DepKind>,
- C::Stored: Debug + std::borrow::Borrow<C::Value>,
+ Q: QueryConfig<Qcx>,
Qcx: QueryContext,
{
- match JobOwner::<'_, C::Key, Qcx::DepKind>::try_start(&qcx, state, span, key.clone()) {
+ match JobOwner::<'_, Q::Key, Qcx::DepKind>::try_start(&qcx, state, span, key.clone()) {
TryGetJob::NotYetStarted(job) => {
- let (result, dep_node_index) = execute_job(qcx, key.clone(), dep_node, query, job.id);
- if query.feedable {
+ let (result, dep_node_index) =
+ execute_job::<Q, Qcx>(qcx, key.clone(), dep_node, job.id);
+ if Q::FEEDABLE {
// We may have put a value inside the cache from inside the execution.
// Verify that it has the same hash as what we have now, to ensure consistency.
let _ = cache.lookup(&key, |cached_result, _| {
- let hasher = query.hash_result.expect("feedable forbids no_hash");
+ let hasher = Q::HASH_RESULT.expect("feedable forbids no_hash");
+
let old_hash = qcx.dep_context().with_stable_hashing_context(|mut hcx| hasher(&mut hcx, cached_result.borrow()));
let new_hash = qcx.dep_context().with_stable_hashing_context(|mut hcx| hasher(&mut hcx, &result));
debug_assert_eq!(
old_hash, new_hash,
"Computed query value for {:?}({:?}) is inconsistent with fed value,\ncomputed={:#?}\nfed={:#?}",
- query.dep_kind, key, result, cached_result,
+ Q::DEP_KIND, key, result, cached_result,
);
});
}
(result, Some(dep_node_index))
}
TryGetJob::Cycle(error) => {
- let result = mk_cycle(qcx, error, query.handle_cycle_error, cache);
+ let result = mk_cycle(qcx, error, Q::HANDLE_CYCLE_ERROR, cache);
(result, None)
}
#[cfg(parallel_compiler)]
}
}
-fn execute_job<Qcx, K, V>(
+fn execute_job<Q, Qcx>(
qcx: Qcx,
- key: K,
+ key: Q::Key,
mut dep_node_opt: Option<DepNode<Qcx::DepKind>>,
- query: &QueryVTable<Qcx, K, V>,
job_id: QueryJobId,
-) -> (V, DepNodeIndex)
+) -> (Q::Value, DepNodeIndex)
where
- K: Clone + DepNodeParams<Qcx::DepContext>,
- V: Debug,
+ Q: QueryConfig<Qcx>,
Qcx: QueryContext,
{
let dep_graph = qcx.dep_context().dep_graph();
// Fast path for when incr. comp. is off.
if !dep_graph.is_fully_enabled() {
let prof_timer = qcx.dep_context().profiler().query_provider();
- let result = qcx.start_query(job_id, query.depth_limit, None, || {
- query.compute(*qcx.dep_context(), key)
+ let result = qcx.start_query(job_id, Q::DEPTH_LIMIT, None, || {
+ Q::compute(qcx, &key)(*qcx.dep_context(), key)
});
let dep_node_index = dep_graph.next_virtual_depnode_index();
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
return (result, dep_node_index);
}
- if !query.anon && !query.eval_always {
+ if !Q::ANON && !Q::EVAL_ALWAYS {
// `to_dep_node` is expensive for some `DepKind`s.
let dep_node =
- dep_node_opt.get_or_insert_with(|| query.to_dep_node(*qcx.dep_context(), &key));
+ dep_node_opt.get_or_insert_with(|| Q::construct_dep_node(*qcx.dep_context(), &key));
// The diagnostics for this query will be promoted to the current session during
// `try_mark_green()`, so we can ignore them here.
if let Some(ret) = qcx.start_query(job_id, false, None, || {
- try_load_from_disk_and_cache_in_memory(qcx, &key, &dep_node, query)
+ try_load_from_disk_and_cache_in_memory::<Q, Qcx>(qcx, &key, &dep_node)
}) {
return ret;
}
let diagnostics = Lock::new(ThinVec::new());
let (result, dep_node_index) =
- qcx.start_query(job_id, query.depth_limit, Some(&diagnostics), || {
- if query.anon {
- return dep_graph.with_anon_task(*qcx.dep_context(), query.dep_kind, || {
- query.compute(*qcx.dep_context(), key)
+ qcx.start_query(job_id, Q::DEPTH_LIMIT, Some(&diagnostics), || {
+ if Q::ANON {
+ return dep_graph.with_anon_task(*qcx.dep_context(), Q::DEP_KIND, || {
+ Q::compute(qcx, &key)(*qcx.dep_context(), key)
});
}
// `to_dep_node` is expensive for some `DepKind`s.
let dep_node =
- dep_node_opt.unwrap_or_else(|| query.to_dep_node(*qcx.dep_context(), &key));
+ dep_node_opt.unwrap_or_else(|| Q::construct_dep_node(*qcx.dep_context(), &key));
- dep_graph.with_task(dep_node, *qcx.dep_context(), key, query.compute, query.hash_result)
+ let task = Q::compute(qcx, &key);
+ dep_graph.with_task(dep_node, *qcx.dep_context(), key, task, Q::HASH_RESULT)
});
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
let side_effects = QuerySideEffects { diagnostics };
if std::intrinsics::unlikely(!side_effects.is_empty()) {
- if query.anon {
+ if Q::ANON {
qcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
} else {
qcx.store_side_effects(dep_node_index, side_effects);
(result, dep_node_index)
}
-fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
+fn try_load_from_disk_and_cache_in_memory<Q, Qcx>(
qcx: Qcx,
- key: &K,
+ key: &Q::Key,
dep_node: &DepNode<Qcx::DepKind>,
- query: &QueryVTable<Qcx, K, V>,
-) -> Option<(V, DepNodeIndex)>
+) -> Option<(Q::Value, DepNodeIndex)>
where
- K: Clone,
+ Q: QueryConfig<Qcx>,
Qcx: QueryContext,
- V: Debug,
{
// Note this function can be called concurrently from the same query
// We must ensure that this is handled correctly.
// First we try to load the result from the on-disk cache.
// Some things are never cached on disk.
- if let Some(try_load_from_disk) = query.try_load_from_disk {
+ if let Some(try_load_from_disk) = Q::try_load_from_disk(qcx, &key) {
let prof_timer = qcx.dep_context().profiler().incr_cache_loading();
// The call to `with_query_deserialization` enforces that no new `DepNodes`
if std::intrinsics::unlikely(
try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich,
) {
- incremental_verify_ich(*qcx.dep_context(), &result, dep_node, query.hash_result);
+ incremental_verify_ich(*qcx.dep_context(), &result, dep_node, Q::HASH_RESULT);
}
return Some((result, dep_node_index));
// can be forced from `DepNode`.
debug_assert!(
!qcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(),
- "missing on-disk cache entry for {:?}",
- dep_node
+ "missing on-disk cache entry for {dep_node:?}"
);
}
let prof_timer = qcx.dep_context().profiler().query_provider();
// The dep-graph for this computation is already in-place.
- let result = dep_graph.with_ignore(|| query.compute(*qcx.dep_context(), key.clone()));
+ let result = dep_graph.with_ignore(|| Q::compute(qcx, key)(*qcx.dep_context(), key.clone()));
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
//
// See issue #82920 for an example of a miscompilation that would get turned into
// an ICE by this check
- incremental_verify_ich(*qcx.dep_context(), &result, dep_node, query.hash_result);
+ incremental_verify_ich(*qcx.dep_context(), &result, dep_node, Q::HASH_RESULT);
Some((result, dep_node_index))
}
{
assert!(
tcx.dep_graph().is_green(dep_node),
- "fingerprint for green query instance not loaded from cache: {:?}",
- dep_node,
+ "fingerprint for green query instance not loaded from cache: {dep_node:?}",
);
let new_hash = hash_result.map_or(Fingerprint::ZERO, |f| {
sess.emit_err(crate::error::Reentrant);
} else {
let run_cmd = if let Some(crate_name) = &sess.opts.crate_name {
- format!("`cargo clean -p {}` or `cargo clean`", crate_name)
+ format!("`cargo clean -p {crate_name}` or `cargo clean`")
} else {
"`cargo clean`".to_string()
};
sess.emit_err(crate::error::IncrementCompilation {
run_cmd,
- dep_node: format!("{:?}", dep_node),
+ dep_node: format!("{dep_node:?}"),
});
- panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result);
+ panic!("Found unstable fingerprints for {dep_node:?}: {result:?}");
}
INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.set(old_in_panic));
///
/// Note: The optimization is only available during incr. comp.
#[inline(never)]
-fn ensure_must_run<Qcx, K, V>(
- qcx: Qcx,
- key: &K,
- query: &QueryVTable<Qcx, K, V>,
-) -> (bool, Option<DepNode<Qcx::DepKind>>)
+fn ensure_must_run<Q, Qcx>(qcx: Qcx, key: &Q::Key) -> (bool, Option<DepNode<Qcx::DepKind>>)
where
- K: crate::dep_graph::DepNodeParams<Qcx::DepContext>,
+ Q: QueryConfig<Qcx>,
Qcx: QueryContext,
{
- if query.eval_always {
+ if Q::EVAL_ALWAYS {
return (true, None);
}
// Ensuring an anonymous query makes no sense
- assert!(!query.anon);
+ assert!(!Q::ANON);
- let dep_node = query.to_dep_node(*qcx.dep_context(), key);
+ let dep_node = Q::construct_dep_node(*qcx.dep_context(), key);
let dep_graph = qcx.dep_context().dep_graph();
match dep_graph.try_mark_green(qcx, &dep_node) {
where
D: DepKind,
Q: QueryConfig<Qcx>,
- Q::Key: DepNodeParams<Qcx::DepContext>,
Q::Value: Value<Qcx::DepContext, D>,
Qcx: QueryContext,
{
- let query = Q::make_vtable(qcx, &key);
let dep_node = if let QueryMode::Ensure = mode {
- let (must_run, dep_node) = ensure_must_run(qcx, &key, &query);
+ let (must_run, dep_node) = ensure_must_run::<Q, _>(qcx, &key);
if !must_run {
return None;
}
None
};
- let (result, dep_node_index) = try_execute_query(
+ let (result, dep_node_index) = try_execute_query::<Q, Qcx>(
qcx,
Q::query_state(qcx),
Q::query_cache(qcx),
span,
key,
dep_node,
- &query,
);
if let Some(dep_node_index) = dep_node_index {
qcx.dep_context().dep_graph().read_index(dep_node_index)
where
D: DepKind,
Q: QueryConfig<Qcx>,
- Q::Key: DepNodeParams<Qcx::DepContext>,
Q::Value: Value<Qcx::DepContext, D>,
Qcx: QueryContext,
{
Err(()) => {}
}
- let query = Q::make_vtable(qcx, &key);
let state = Q::query_state(qcx);
- debug_assert!(!query.anon);
+ debug_assert!(!Q::ANON);
- try_execute_query(qcx, state, cache, DUMMY_SP, key, Some(dep_node), &query);
+ try_execute_query::<Q, _>(qcx, state, cache, DUMMY_SP, key, Some(dep_node));
}
// binding if it exists. What we really want here is having two separate scopes in
// a module - one for non-globs and one for globs, but until that's done use this
// hack to avoid inconsistent resolution ICEs during import validation.
- let binding = [resolution.binding, resolution.shadowed_glob]
- .into_iter()
- .filter_map(|binding| match (binding, ignore_binding) {
+ let binding = [resolution.binding, resolution.shadowed_glob].into_iter().find_map(
+ |binding| match (binding, ignore_binding) {
(Some(binding), Some(ignored)) if ptr::eq(binding, ignored) => None,
_ => binding,
- })
- .next();
+ },
+ );
let Some(binding) = binding else {
return Err((Determined, Weak::No));
};
use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
use rustc_ast::*;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_errors::{DiagnosticArgValue, DiagnosticId, IntoDiagnosticArg};
+use rustc_errors::{Applicability, DiagnosticArgValue, DiagnosticId, IntoDiagnosticArg};
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
in_assignment: Option<&'ast Expr>,
is_assign_rhs: bool,
+ /// Used to detect possible `.` -> `..` typo when calling methods.
+ in_range: Option<(&'ast Expr, &'ast Expr)>,
+
/// If we are currently in a trait object definition. Used to point at the bounds when
/// encountering a struct or enum.
current_trait_object: Option<&'ast [ast::GenericBound]>,
let prev = self.diagnostic_metadata.current_trait_object;
let prev_ty = self.diagnostic_metadata.current_type_path;
match ty.kind {
- TyKind::Rptr(None, _) => {
+ TyKind::Ref(None, _) => {
// Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
// NodeId `ty.id`.
// This span will be used in case of elision failure.
count: 1,
};
let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
- for rib in self.lifetime_ribs.iter().rev() {
+ for (i, rib) in self.lifetime_ribs.iter().enumerate().rev() {
debug!(?rib.kind);
match rib.kind {
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
} else {
("`'_` cannot be used here", "`'_` is a reserved lifetime name")
};
- rustc_errors::struct_span_err!(
+ let mut diag = rustc_errors::struct_span_err!(
self.r.session,
lifetime.ident.span,
E0637,
"{}",
msg,
- )
- .span_label(lifetime.ident.span, note)
- .emit();
-
+ );
+ diag.span_label(lifetime.ident.span, note);
+ if elided {
+ for rib in self.lifetime_ribs[i..].iter().rev() {
+ if let LifetimeRibKind::Generics {
+ span,
+ kind: LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound,
+ ..
+ } = &rib.kind
+ {
+ diag.span_help(
+ *span,
+ "consider introducing a higher-ranked lifetime here with `for<'a>`",
+ );
+ break;
+ }
+ }
+ }
+ diag.emit();
self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
return;
}
impl<'a> Visitor<'a> for SelfVisitor<'_, '_> {
fn visit_ty(&mut self, ty: &'a Ty) {
trace!("SelfVisitor considering ty={:?}", ty);
- if let TyKind::Rptr(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) {
+ if let TyKind::Ref(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) {
let lt_id = if let Some(lt) = lt {
lt.id
} else {
);
}
+ #[instrument(level = "debug", skip(self))]
fn smart_resolve_path_fragment(
&mut self,
qself: &Option<P<QSelf>>,
source: PathSource<'ast>,
finalize: Finalize,
) -> PartialRes {
- debug!(
- "smart_resolve_path_fragment(qself={:?}, path={:?}, finalize={:?})",
- qself, path, finalize,
- );
let ns = source.namespace();
let Finalize { node_id, path_span, .. } = finalize;
let def_id = this.parent_scope.module.nearest_parent_mod();
let instead = res.is_some();
- let suggestion =
- if res.is_none() { this.report_missing_type_error(path) } else { None };
+ let suggestion = if let Some((start, end)) = this.diagnostic_metadata.in_range
+ && path[0].ident.span.lo() == end.span.lo()
+ {
+ let mut sugg = ".";
+ let mut span = start.span.between(end.span);
+ if span.lo() + BytePos(2) == span.hi() {
+ // There's no space between the start, the range op and the end, suggest
+ // removal which will look better.
+ span = span.with_lo(span.lo() + BytePos(1));
+ sugg = "";
+ }
+ Some((
+ span,
+ "you might have meant to write `.` instead of `..`",
+ sugg.to_string(),
+ Applicability::MaybeIncorrect,
+ ))
+ } else if res.is_none() {
+ this.report_missing_type_error(path)
+ } else {
+ None
+ };
this.r.use_injections.push(UseError {
err,
self.visit_expr(rhs);
self.diagnostic_metadata.is_assign_rhs = false;
}
+ ExprKind::Range(Some(ref start), Some(ref end), RangeLimits::HalfOpen) => {
+ self.diagnostic_metadata.in_range = Some((start, end));
+ self.resolve_expr(start, Some(expr));
+ self.resolve_expr(end, Some(expr));
+ self.diagnostic_metadata.in_range = None;
+ }
_ => {
visit::walk_expr(self, expr);
}
fn extract_node_id(t: &Ty) -> Option<NodeId> {
match t.kind {
TyKind::Path(None, _) => Some(t.id),
- TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
+ TyKind::Ref(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
// This doesn't handle the remaining `Ty` variants as they are not
// that commonly the self_type, it might be interesting to provide
// support for those in future.
Some(LifetimeUseSet::One { use_span, use_ctxt }) => {
debug!(?param.ident, ?param.ident.span, ?use_span);
- let elidable = matches!(use_ctxt, LifetimeCtxt::Rptr);
+ let elidable = matches!(use_ctxt, LifetimeCtxt::Ref);
let deletion_span = deletion_span();
self.r.lint_buffer.buffer_lint_with_diagnostic(
if seg.res != Res::Err {
seg.res
} else {
- let parent_node = self.tcx.hir().get_parent_node(hir_id);
+ let parent_node = self.tcx.hir().parent_id(hir_id);
self.get_path_res(parent_node)
}
}
let text = format!("{}{}", prefix, nested.text);
Ok(replace_text(nested, text))
}
- hir::TyKind::Rptr(ref lifetime, ref mt) => {
+ hir::TyKind::Ref(ref lifetime, ref mt) => {
let mut prefix = "&".to_owned();
prefix.push_str(&lifetime.ident.to_string());
prefix.push(' ');
use std::iter;
use std::path::{Path, PathBuf};
use std::str::{self, FromStr};
+use std::sync::LazyLock;
pub mod sigpipe;
SplitDebuginfo,
}
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub enum TraitSolver {
+ /// Classic trait solver in `rustc_trait_selection::traits::select`
+ Classic,
+ /// Chalk trait solver
+ Chalk,
+ /// Experimental trait solver in `rustc_trait_selection::solve`
+ Next,
+}
+
pub enum Input {
/// Load source code from a file.
File(PathBuf),
pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
}
+
+ #[allow(rustc::bad_opt_access)]
+ pub fn incremental_relative_spans(&self) -> bool {
+ self.unstable_opts.incremental_relative_spans
+ || (self.unstable_features.is_nightly_build() && self.incremental.is_some())
+ }
}
impl UnstableOptions {
unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
}
}
-
+static EDITION_STRING: LazyLock<String> = LazyLock::new(|| {
+ format!(
+ "Specify which edition of the compiler to use when compiling code. \
+The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE_EDITION}."
+ )
+});
/// Returns the "short" subset of the rustc command line options,
/// including metadata for each option, such as whether the option is
/// part of the stable long-term interface for rustc.
opt::opt_s(
"",
"edition",
- "Specify which edition of the compiler to use when compiling code.",
+ &*EDITION_STRING,
EDITION_NAME_LIST,
),
opt::multi_s(
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
- SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
+ SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
};
use crate::lint;
use crate::options::WasiExecModel;
BranchProtection,
OomStrategy,
LanguageIdentifier,
+ TraitSolver,
);
impl<T1, T2> DepTrackingHash for (T1, T2)
/// Run the proc-macro code on a different thread.
CrossThread,
}
+
+/// Which format to use for `-Z dump-mono-stats`
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum DumpMonoStatsFormat {
+ /// Pretty-print a markdown table
+ Markdown,
+ /// Emit structured JSON
+ Json,
+}
+
+impl DumpMonoStatsFormat {
+ pub fn extension(self) -> &'static str {
+ match self {
+ Self::Markdown => "md",
+ Self::Json => "json",
+ }
+ }
+}
#[derive(Diagnostic)]
#[diag(session_int_literal_too_large)]
+#[note]
pub(crate) struct IntLiteralTooLarge {
#[primary_span]
pub span: Span,
+ pub limit: String,
}
#[derive(Diagnostic)]
_ => unreachable!(),
};
}
- LitError::IntTooLarge => {
- sess.emit_err(IntLiteralTooLarge { span });
+ LitError::IntTooLarge(base) => {
+ let max = u128::MAX;
+ let limit = match base {
+ 2 => format!("{max:#b}"),
+ 8 => format!("{max:#o}"),
+ 16 => format!("{max:#x}"),
+ _ => format!("{max}"),
+ };
+ sess.emit_err(IntLiteralTooLarge { span, limit });
}
}
}
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
pub const parse_optimization_fuel: &str = "crate=integer";
pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
+ pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
pub const parse_instrument_coverage: &str =
"`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
pub const parse_unpretty: &str = "`string` or `string=string`";
pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0";
+ pub const parse_trait_solver: &str =
+ "one of the supported solver modes (`classic`, `chalk`, or `next`)";
pub const parse_lto: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
pub const parse_linker_plugin_lto: &str =
true
}
+ pub(crate) fn parse_dump_mono_stats(slot: &mut DumpMonoStatsFormat, v: Option<&str>) -> bool {
+ match v {
+ None => true,
+ Some("json") => {
+ *slot = DumpMonoStatsFormat::Json;
+ true
+ }
+ Some("markdown") => {
+ *slot = DumpMonoStatsFormat::Markdown;
+ true
+ }
+ Some(_) => false,
+ }
+ }
+
pub(crate) fn parse_instrument_coverage(
slot: &mut Option<InstrumentCoverage>,
v: Option<&str>,
}
}
+ pub(crate) fn parse_trait_solver(slot: &mut TraitSolver, v: Option<&str>) -> bool {
+ match v {
+ Some("classic") => *slot = TraitSolver::Classic,
+ Some("chalk") => *slot = TraitSolver::Chalk,
+ Some("next") => *slot = TraitSolver::Next,
+ // default trait solver is subject to change..
+ Some("default") => *slot = TraitSolver::Classic,
+ _ => return false,
+ }
+ true
+ }
+
pub(crate) fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
if v.is_some() {
let mut bool_arg = None;
"instrument control-flow architecture protection"),
cgu_partitioning_strategy: Option<String> = (None, parse_opt_string, [TRACKED],
"the codegen unit partitioning strategy to use"),
- chalk: bool = (false, parse_bool, [TRACKED],
- "enable the experimental Chalk-based trait solving engine"),
codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
"the backend to use"),
combine_cgu: bool = (false, parse_bool, [TRACKED],
an additional `.html` file showing the computed coverage spans."),
dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
parse_switch_with_opt_path, [UNTRACKED],
- "output statistics about monomorphization collection (format: markdown)"),
+ "output statistics about monomorphization collection"),
+ dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED],
+ "the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"),
dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
dylib_lto: bool = (false, parse_bool, [UNTRACKED],
"generate human-readable, predictable names for codegen units (default: no)"),
identify_regions: bool = (false, parse_bool, [UNTRACKED],
"display unnamed regions as `'<id>`, using a non-ident unique id (default: no)"),
- incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
+ incremental_ignore_spans: bool = (false, parse_bool, [TRACKED],
"ignore spans during ICH computation -- used for testing (default: no)"),
incremental_info: bool = (false, parse_bool, [UNTRACKED],
"print high-level information about incremental reuse (or the lack thereof) \
(default: no)"),
+ #[rustc_lint_opt_deny_field_access("use `Session::incremental_relative_spans` instead of this field")]
incremental_relative_spans: bool = (false, parse_bool, [TRACKED],
"hash spans relative to their parent item for incr. comp. (default: no)"),
incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
"for every macro invocation, print its name and arguments (default: no)"),
track_diagnostics: bool = (false, parse_bool, [UNTRACKED],
"tracks where in rustc a diagnostic was emitted"),
+ trait_solver: TraitSolver = (TraitSolver::Classic, parse_trait_solver, [TRACKED],
+ "specify the trait solver mode used by rustc (default: classic)"),
// Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved
// alongside query results and changes to translation options can affect diagnostics - so
// translation options should be tracked.
pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
self.diagnostic().warn(msg)
}
- /// Delay a span_bug() call until abort_if_errors()
+
+ /// Ensures that compilation cannot succeed.
+ ///
+ /// If this function has been called but no errors have been emitted and
+ /// compilation succeeds, it will cause an internal compiler error (ICE).
+ ///
+ /// This can be used in code paths that should never run on successful compilations.
+ /// For example, it can be used to create an [`ErrorGuaranteed`]
+ /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission directly).
+ ///
+ /// If no span is available, use [`DUMMY_SP`].
+ ///
+ /// [`DUMMY_SP`]: rustc_span::DUMMY_SP
#[track_caller]
pub fn delay_span_bug<S: Into<MultiSpan>>(
&self,
// i.e. don't use closures.
match self.as_local() {
Some(local_def_id) => local_def_id,
- None => panic!("DefId::expect_local: `{:?}` isn't local", self),
+ None => panic!("DefId::expect_local: `{self:?}` isn't local"),
}
}
Edition::Edition2021 => "2021",
Edition::Edition2024 => "2024",
};
- write!(f, "{}", s)
+ write!(f, "{s}")
}
}
// `-Z incremental-ignore-spans` option. Normally, this option is disabled,
// which will cause us to require that this method always be called with `Span` hashing
// enabled.
+ //
+ // Span hashing can also be disabled without `-Z incremental-ignore-spans`.
+ // This is the case for instance when building a hash for name mangling.
+ // Such configuration must not be used for metadata.
HashingControls { hash_spans }
if hash_spans == !ctx.unstable_opts_incremental_ignore_spans() => {}
- other => panic!("Attempted hashing of {msg} with non-default HashingControls: {:?}", other),
+ other => panic!("Attempted hashing of {msg} with non-default HashingControls: {other:?}"),
}
}
// Stop going up the backtrace once include! is encountered
if expn_data.is_root()
|| expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include)
+ || expn_data.kind == ExpnKind::Inlined
{
break;
}
pub fn debug_hygiene_data(verbose: bool) -> String {
HygieneData::with(|data| {
if verbose {
- format!("{:#?}", data)
+ format!("{data:#?}")
} else {
let mut s = String::from("Expansions:");
let mut debug_expn_data = |(id, expn_data): (&ExpnId, &ExpnData)| {
match *self {
ExpnKind::Root => kw::PathRoot.to_string(),
ExpnKind::Macro(macro_kind, name) => match macro_kind {
- MacroKind::Bang => format!("{}!", name),
- MacroKind::Attr => format!("#[{}]", name),
- MacroKind::Derive => format!("#[derive({})]", name),
+ MacroKind::Bang => format!("{name}!"),
+ MacroKind::Attr => format!("#[{name}]"),
+ MacroKind::Derive => format!("#[derive({name})]"),
},
ExpnKind::AstPass(kind) => kind.descr().to_string(),
ExpnKind::Desugaring(kind) => format!("desugaring of {}", kind.descr()),
/// collisions are only possible between `ExpnId`s within the same crate.
fn update_disambiguator(expn_data: &mut ExpnData, mut ctx: impl HashStableContext) -> ExpnHash {
// This disambiguator should not have been set yet.
- assert_eq!(
- expn_data.disambiguator, 0,
- "Already set disambiguator for ExpnData: {:?}",
- expn_data
- );
+ assert_eq!(expn_data.disambiguator, 0, "Already set disambiguator for ExpnData: {expn_data:?}");
assert_default_hashing_controls(&ctx, "ExpnData (disambiguator)");
let mut expn_hash = expn_data.hash_expn(&mut ctx);
ProcMacroSourceCode(_) => write!(fmt, "<proc-macro source code>"),
CfgSpec(_) => write!(fmt, "<cfgspec>"),
CliCrateAttr(_) => write!(fmt, "<crate attribute>"),
- Custom(ref s) => write!(fmt, "<{}>", s),
+ Custom(ref s) => write!(fmt, "<{s}>"),
DocTest(ref path, _) => write!(fmt, "{}", path.display()),
InlineAsm(_) => write!(fmt, "<inline asm>"),
}
/// Returns a `Span` that would enclose both `self` and `end`.
///
+ /// Note that this can also be used to extend the span "backwards":
+ /// `start.to(end)` and `end.to(start)` return the same `Span`.
+ ///
/// ```text
/// ____ ___
/// self lorem ipsum end
0 => NonNarrowChar::ZeroWidth(pos),
2 => NonNarrowChar::Wide(pos),
4 => NonNarrowChar::Tab(pos),
- _ => panic!("width {} given for non-narrow character", width),
+ _ => panic!("width {width} given for non-narrow character"),
}
}
if let Some(source_map) = &*session_globals.source_map.borrow() {
source_map.span_to_embeddable_string(span)
} else {
- format!("{:?}", span)
+ format!("{span:?}")
}
});
self.record_arg(span_arg);
/// Finds the width of the character, either before or after the end of provided span,
/// depending on the `forwards` parameter.
+ #[instrument(skip(self, sp))]
fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
let sp = sp.data();
if sp.lo == sp.hi && !forwards {
- debug!("find_width_of_character_at_span: early return empty span");
+ debug!("early return empty span");
return 1;
}
let local_begin = self.lookup_byte_offset(sp.lo);
let local_end = self.lookup_byte_offset(sp.hi);
- debug!(
- "find_width_of_character_at_span: local_begin=`{:?}`, local_end=`{:?}`",
- local_begin, local_end
- );
+ debug!("local_begin=`{:?}`, local_end=`{:?}`", local_begin, local_end);
if local_begin.sf.start_pos != local_end.sf.start_pos {
- debug!("find_width_of_character_at_span: begin and end are in different files");
+ debug!("begin and end are in different files");
return 1;
}
let start_index = local_begin.pos.to_usize();
let end_index = local_end.pos.to_usize();
- debug!(
- "find_width_of_character_at_span: start_index=`{:?}`, end_index=`{:?}`",
- start_index, end_index
- );
+ debug!("start_index=`{:?}`, end_index=`{:?}`", start_index, end_index);
// Disregard indexes that are at the start or end of their spans, they can't fit bigger
// characters.
if (!forwards && end_index == usize::MIN) || (forwards && start_index == usize::MAX) {
- debug!("find_width_of_character_at_span: start or end of span, cannot be multibyte");
+ debug!("start or end of span, cannot be multibyte");
return 1;
}
let source_len = (local_begin.sf.end_pos - local_begin.sf.start_pos).to_usize();
- debug!("find_width_of_character_at_span: source_len=`{:?}`", source_len);
+ debug!("source_len=`{:?}`", source_len);
// Ensure indexes are also not malformed.
if start_index > end_index || end_index > source_len - 1 {
- debug!("find_width_of_character_at_span: source indexes are malformed");
+ debug!("source indexes are malformed");
return 1;
}
} else {
return 1;
};
- debug!("find_width_of_character_at_span: snippet=`{:?}`", snippet);
+ debug!("snippet=`{:?}`", snippet);
let mut target = if forwards { end_index + 1 } else { end_index - 1 };
- debug!("find_width_of_character_at_span: initial target=`{:?}`", target);
+ debug!("initial target=`{:?}`", target);
while !snippet.is_char_boundary(target - start_index) && target < source_len {
target = if forwards {
}
}
};
- debug!("find_width_of_character_at_span: target=`{:?}`", target);
+ debug!("target=`{:?}`", target);
}
- debug!("find_width_of_character_at_span: final target=`{:?}`", target);
+ debug!("final target=`{:?}`", target);
if forwards { (target - end_index) as u32 } else { (end_index - target) as u32 }
}
// The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
// See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28
-use crate::def_id::LocalDefId;
+use crate::def_id::{DefIndex, LocalDefId};
use crate::hygiene::SyntaxContext;
use crate::SPAN_TRACK;
use crate::{BytePos, SpanData};
/// A compressed span.
///
-/// Whereas [`SpanData`] is 12 bytes, which is a bit too big to stick everywhere, `Span`
-/// is a form that only takes up 8 bytes, with less space for the length and
+/// Whereas [`SpanData`] is 16 bytes, which is a bit too big to stick everywhere, `Span`
+/// is a form that only takes up 8 bytes, with less space for the length, parent and
/// context. The vast majority (99.9%+) of `SpanData` instances will fit within
/// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are
/// stored in a separate interner table, and the `Span` will index into that
/// slower because only 80--90% of spans could be stored inline (even less in
/// very large crates) and so the interner was used a lot more.
///
-/// Inline (compressed) format:
+/// Inline (compressed) format with no parent:
/// - `span.base_or_index == span_data.lo`
/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
///
+/// Inline (compressed) format with root context:
+/// - `span.base_or_index == span_data.lo`
+/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
+/// - `span.len_or_tag` has top bit (`PARENT_MASK`) set
+/// - `span.ctxt == span_data.parent` (must be `<= MAX_CTXT`)
+///
/// Interned format:
/// - `span.base_or_index == index` (indexes into the interner table)
/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
ctxt_or_tag: u16,
}
-const LEN_TAG: u16 = 0b1000_0000_0000_0000;
+const LEN_TAG: u16 = 0b1111_1111_1111_1111;
+const PARENT_MASK: u16 = 0b1000_0000_0000_0000;
const MAX_LEN: u32 = 0b0111_1111_1111_1111;
const CTXT_TAG: u32 = 0b1111_1111_1111_1111;
const MAX_CTXT: u32 = CTXT_TAG - 1;
let (base, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32());
- if len <= MAX_LEN && ctxt2 <= MAX_CTXT && parent.is_none() {
- // Inline format.
- Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_tag: ctxt2 as u16 }
- } else {
- // Interned format.
- let index =
- with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
- let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
- Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
+ if len <= MAX_LEN && ctxt2 <= MAX_CTXT {
+ let len_or_tag = len as u16;
+ debug_assert_eq!(len_or_tag & PARENT_MASK, 0);
+
+ if let Some(parent) = parent {
+ // Inline format with parent.
+ let len_or_tag = len_or_tag | PARENT_MASK;
+ let parent2 = parent.local_def_index.as_u32();
+ if ctxt2 == SyntaxContext::root().as_u32() && parent2 <= MAX_CTXT {
+ return Span { base_or_index: base, len_or_tag, ctxt_or_tag: parent2 as u16 };
+ }
+ } else {
+ // Inline format with ctxt.
+ return Span {
+ base_or_index: base,
+ len_or_tag: len as u16,
+ ctxt_or_tag: ctxt2 as u16,
+ };
+ }
}
+
+ // Interned format.
+ let index =
+ with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
+ let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
+ Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
}
#[inline]
pub fn data_untracked(self) -> SpanData {
if self.len_or_tag != LEN_TAG {
// Inline format.
- debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
- SpanData {
- lo: BytePos(self.base_or_index),
- hi: BytePos(self.base_or_index + self.len_or_tag as u32),
- ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
- parent: None,
+ if self.len_or_tag & PARENT_MASK == 0 {
+ debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
+ SpanData {
+ lo: BytePos(self.base_or_index),
+ hi: BytePos(self.base_or_index + self.len_or_tag as u32),
+ ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
+ parent: None,
+ }
+ } else {
+ let len = self.len_or_tag & !PARENT_MASK;
+ debug_assert!(len as u32 <= MAX_LEN);
+ let parent =
+ LocalDefId { local_def_index: DefIndex::from_u32(self.ctxt_or_tag as u32) };
+ SpanData {
+ lo: BytePos(self.base_or_index),
+ hi: BytePos(self.base_or_index + len as u32),
+ ctxt: SyntaxContext::root(),
+ parent: Some(parent),
+ }
}
} else {
// Interned format.
pub fn ctxt(self) -> SyntaxContext {
let ctxt_or_tag = self.ctxt_or_tag as u32;
if ctxt_or_tag <= MAX_CTXT {
- // Inline format or interned format with inline ctxt.
- SyntaxContext::from_u32(ctxt_or_tag)
+ if self.len_or_tag == LEN_TAG || self.len_or_tag & PARENT_MASK == 0 {
+ // Inline format or interned format with inline ctxt.
+ SyntaxContext::from_u32(ctxt_or_tag)
+ } else {
+ // Inline format or interned format with inline parent.
+ // We know that the SyntaxContext is root.
+ SyntaxContext::root()
+ }
} else {
// Interned format.
let index = self.base_or_index;
FromIterator,
FromResidual,
Future,
+ FutureOutput,
FxHashMap,
FxHashSet,
GlobalAlloc,
Is,
ItemContext,
Iterator,
+ IteratorItem,
Layout,
Left,
LinkedList,
fn finish(mut self, hash: u64) -> String {
self.finalize_pending_component();
// E = end name-sequence
- let _ = write!(self.result, "17h{:016x}E", hash);
+ let _ = write!(self.result, "17h{hash:016x}E");
self.result
}
}
self = self.print_type(ty)?;
self.write_str("; ")?;
if let Some(size) = size.kind().try_to_bits(self.tcx().data_layout.pointer_size) {
- write!(self, "{}", size)?
+ write!(self, "{size}")?
} else if let ty::ConstKind::Param(param) = size.kind() {
self = param.print(self)?
} else {
debug_assert!(
rustc_demangle::try_demangle(&symbol).is_ok(),
- "compute_symbol_name: `{}` cannot be demangled",
- symbol
+ "compute_symbol_name: `{symbol}` cannot be demangled"
);
symbol
tcx.sess.emit_err(TestOutput {
span: attr.span,
kind: Kind::DemanglingAlt,
- content: format!("{:#}", demangling),
+ content: format!("{demangling:#}"),
});
}
}
if value < zero {
s.push('n')
};
- let _ = write!(s, "{}", value);
+ let _ = write!(s, "{value}");
}
fn push_unsigned_value<T: Display>(s: &mut String, value: T) {
- let _ = write!(s, "{}", value);
+ let _ = write!(s, "{value}");
}
if let Some(scalar_int) = c.kind().try_to_scalar_int() {
/// Encodes a FnSig using the Itanium C++ ABI with vendor extended type qualifiers and types for
/// Rust types that are not used at the FFI boundary.
+#[instrument(level = "trace", skip(tcx, dict))]
fn encode_fnsig<'tcx>(
tcx: TyCtxt<'tcx>,
fn_sig: &FnSig<'tcx>,
// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all
// c_void types into unit types unconditionally, and generalizes all pointers if
// TransformTyOptions::GENERALIZE_POINTERS option is set.
+#[instrument(level = "trace", skip(tcx))]
fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptions) -> Ty<'tcx> {
let mut ty = ty;
!is_zst
});
if let Some(field) = field {
- let ty0 = tcx.type_of(field.did);
+ let ty0 = tcx.bound_type_of(field.did).subst(tcx, substs);
// Generalize any repr(transparent) user-defined type that is either a pointer
// or reference, and either references itself or any other type that contains or
// references itself, to avoid a reference cycle.
/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
/// extended type qualifiers and types for Rust types that are not used at the FFI boundary.
+#[instrument(level = "trace", skip(tcx))]
pub fn typeid_for_fnabi<'tcx>(
tcx: TyCtxt<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
where
T: TypeVisitable<'tcx>,
{
+ // FIXME(non-lifetime-binders): What to do here?
let regions = if value.has_late_bound_regions() {
self.tcx.collect_referenced_late_bound_regions(value)
} else {
bits = val.unsigned_abs();
}
- let _ = write!(self.out, "{:x}_", bits);
+ let _ = write!(self.out, "{bits:x}_");
}
// FIXME(valtrees): Remove the special case for `str`
// FIXME(eddyb) use a specialized hex-encoding loop.
for byte in s.bytes() {
- let _ = write!(self.out, "{:02x}", byte);
+ let _ = write!(self.out, "{byte:02x}");
}
self.push("_");
const NonNull = 1 << 3;
const ReadOnly = 1 << 4;
const InReg = 1 << 5;
- // Due to past miscompiles in LLVM, we use a separate attribute for
- // &mut arguments, so that the codegen backend can decide whether
- // or not to actually emit the attribute. It can also be controlled
- // with the `-Zmutable-noalias` debugging option.
- const NoAliasMutRef = 1 << 6;
- const NoUndef = 1 << 7;
+ const NoUndef = 1 << 6;
}
}
}
17..=32 => dl.i32_align.abi,
33..=64 => dl.i64_align.abi,
65..=128 => dl.i128_align.abi,
- _ => panic!("unsupported integer: {:?}", self),
+ _ => panic!("unsupported integer: {self:?}"),
},
RegKind::Float => match self.size.bits() {
32 => dl.f32_align.abi,
64 => dl.f64_align.abi,
- _ => panic!("unsupported float: {:?}", self),
+ _ => panic!("unsupported float: {self:?}"),
},
RegKind::Vector => dl.vector_align(self.size).abi,
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Unsupported { arch, abi } => {
- write!(f, "target architecture {:?} does not support `extern {}` ABI", arch, abi)
+ write!(f, "target architecture {arch:?} does not support `extern {abi}` ABI")
}
}
}
"AmdGpuKernel" => Ok(Conv::AmdGpuKernel),
"AvrInterrupt" => Ok(Conv::AvrInterrupt),
"AvrNonBlockingInterrupt" => Ok(Conv::AvrNonBlockingInterrupt),
- _ => Err(format!("'{}' is not a valid value for entry function call convetion.", s)),
+ _ => Err(format!("'{s}' is not a valid value for entry function call convetion.")),
}
}
}
(modifier.unwrap_or('v'), self as u32 - Self::v0 as u32)
};
assert!(index < 32);
- write!(out, "{}{}", prefix, index)
+ write!(out, "{prefix}{index}")
}
}
let index = self as u32 - Self::q0 as u32;
assert!(index < 16);
let index = index * 2 + (modifier == 'f') as u32;
- write!(out, "d{}", index)
+ write!(out, "d{index}")
} else {
out.write_str(self.name())
}
Self::I128 => f.write_str("i128"),
Self::F32 => f.write_str("f32"),
Self::F64 => f.write_str("f64"),
- Self::VecI8(n) => write!(f, "i8x{}", n),
- Self::VecI16(n) => write!(f, "i16x{}", n),
- Self::VecI32(n) => write!(f, "i32x{}", n),
- Self::VecI64(n) => write!(f, "i64x{}", n),
- Self::VecI128(n) => write!(f, "i128x{}", n),
- Self::VecF32(n) => write!(f, "f32x{}", n),
- Self::VecF64(n) => write!(f, "f64x{}", n),
+ Self::VecI8(n) => write!(f, "i8x{n}"),
+ Self::VecI16(n) => write!(f, "i16x{n}"),
+ Self::VecI32(n) => write!(f, "i32x{n}"),
+ Self::VecI64(n) => write!(f, "i64x{n}"),
+ Self::VecI128(n) => write!(f, "i128x{n}"),
+ Self::VecF32(n) => write!(f, "f32x{n}"),
+ Self::VecF64(n) => write!(f, "f64x{n}"),
}
}
}
if self as u32 <= Self::dx as u32 {
let root = ['a', 'b', 'c', 'd'][self as usize - Self::ax as usize];
match modifier.unwrap_or(reg_default_modifier) {
- 'l' => write!(out, "{}l", root),
- 'h' => write!(out, "{}h", root),
- 'x' => write!(out, "{}x", root),
- 'e' => write!(out, "e{}x", root),
- 'r' => write!(out, "r{}x", root),
+ 'l' => write!(out, "{root}l"),
+ 'h' => write!(out, "{root}h"),
+ 'x' => write!(out, "{root}x"),
+ 'e' => write!(out, "e{root}x"),
+ 'r' => write!(out, "r{root}x"),
_ => unreachable!(),
}
} else if self as u32 <= Self::di as u32 {
let root = self.name();
match modifier.unwrap_or(reg_default_modifier) {
- 'l' => write!(out, "{}l", root),
- 'x' => write!(out, "{}", root),
- 'e' => write!(out, "e{}", root),
- 'r' => write!(out, "r{}", root),
+ 'l' => write!(out, "{root}l"),
+ 'x' => write!(out, "{root}"),
+ 'e' => write!(out, "e{root}"),
+ 'r' => write!(out, "r{root}"),
_ => unreachable!(),
}
} else if self as u32 <= Self::r15 as u32 {
let root = self.name();
match modifier.unwrap_or(reg_default_modifier) {
- 'l' => write!(out, "{}b", root),
- 'x' => write!(out, "{}w", root),
- 'e' => write!(out, "{}d", root),
+ 'l' => write!(out, "{root}b"),
+ 'x' => write!(out, "{root}w"),
+ 'e' => write!(out, "{root}d"),
'r' => out.write_str(root),
_ => unreachable!(),
}
} else if self as u32 <= Self::xmm15 as u32 {
let prefix = modifier.unwrap_or('x');
let index = self as u32 - Self::xmm0 as u32;
- write!(out, "{}{}", prefix, index)
+ write!(out, "{prefix}{index}")
} else if self as u32 <= Self::ymm15 as u32 {
let prefix = modifier.unwrap_or('y');
let index = self as u32 - Self::ymm0 as u32;
- write!(out, "{}{}", prefix, index)
+ write!(out, "{prefix}{index}")
} else if self as u32 <= Self::zmm31 as u32 {
let prefix = modifier.unwrap_or('z');
let index = self as u32 - Self::zmm0 as u32;
- write!(out, "{}{}", prefix, index)
+ write!(out, "{prefix}{index}")
} else {
out.write_str(self.name())
}
+++ /dev/null
-use crate::spec::{SanitizerSet, Target, TargetOptions};
-
-pub fn target() -> Target {
- Target {
- llvm_target: "aarch64-fuchsia".into(),
- pointer_width: 64,
- data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
- arch: "aarch64".into(),
- options: TargetOptions {
- max_atomic_width: Some(128),
- supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI,
- ..super::fuchsia_base::opts()
- },
- }
-}
--- /dev/null
+use crate::spec::{SanitizerSet, Target, TargetOptions};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "aarch64-unknown-fuchsia".into(),
+ pointer_width: 64,
+ data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
+ arch: "aarch64".into(),
+ options: TargetOptions {
+ max_atomic_width: Some(128),
+ supported_sanitizers: SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
+ | SanitizerSet::SHADOWCALLSTACK,
+ ..super::fuchsia_base::opts()
+ },
+ }
+}
fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs {
let platform_name: StaticCow<str> = match abi {
- "sim" => format!("{}-simulator", os).into(),
+ "sim" => format!("{os}-simulator").into(),
"macabi" => "mac-catalyst".into(),
_ => os.into(),
};
fn macos_lld_platform_version(arch: Arch) -> String {
let (major, minor) = macos_deployment_target(arch);
- format!("{}.{}", major, minor)
+ format!("{major}.{minor}")
}
pub fn macos_llvm_target(arch: Arch) -> String {
fn ios_lld_platform_version() -> String {
let (major, minor) = ios_deployment_target();
- format!("{}.{}", major, minor)
+ format!("{major}.{minor}")
}
pub fn ios_sim_llvm_target(arch: Arch) -> String {
fn tvos_lld_platform_version() -> String {
let (major, minor) = tvos_deployment_target();
- format!("{}.{}", major, minor)
+ format!("{major}.{minor}")
}
fn watchos_deployment_target() -> (u32, u32) {
fn watchos_lld_platform_version() -> String {
let (major, minor) = watchos_deployment_target();
- format!("{}.{}", major, minor)
+ format!("{major}.{minor}")
}
pub fn watchos_sim_llvm_target(arch: Arch) -> String {
--- /dev/null
+use crate::abi::Endian;
+use crate::spec::{cvs, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+/// A base target for PlayStation Vita devices using the VITASDK toolchain (using newlib).
+///
+/// Requires the VITASDK toolchain on the host system.
+
+pub fn target() -> Target {
+ let pre_link_args = TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-Wl,-q"]);
+
+ Target {
+ llvm_target: "armv7a-vita-newlibeabihf".into(),
+ pointer_width: 32,
+ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
+ arch: "arm".into(),
+
+ options: TargetOptions {
+ os: "vita".into(),
+ endian: Endian::Little,
+ c_int_width: "32".into(),
+ dynamic_linking: false,
+ env: "newlib".into(),
+ vendor: "sony".into(),
+ abi: "eabihf".into(),
+ linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
+ no_default_libraries: false,
+ cpu: "cortex-a9".into(),
+ executables: true,
+ families: cvs!["unix"],
+ linker: Some("arm-vita-eabi-gcc".into()),
+ relocation_model: RelocModel::Static,
+ features: "+v7,+neon".into(),
+ pre_link_args,
+ exe_suffix: ".elf".into(),
+ panic_strategy: PanicStrategy::Abort,
+ max_atomic_width: Some(32),
+ ..Default::default()
+ },
+ }
+}
allow_asm: true,
endian,
linker_flavor: LinkerFlavor::Bpf,
- atomic_cas: false,
+ atomic_cas: true,
dynamic_linking: true,
no_builtins: true,
panic_strategy: PanicStrategy::Abort,
obj_is_bitcode: true,
requires_lto: false,
singlethread: true,
+ // When targeting the `v3` cpu in llvm, 32-bit atomics are also supported.
+ // But making this value change based on the target cpu can be mostly confusing
+ // and would require a bit of a refactor.
+ min_atomic_width: Some(64),
max_atomic_width: Some(64),
..Default::default()
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut first = true;
for s in *self {
- let name = s.as_str().unwrap_or_else(|| panic!("unrecognized sanitizer {:?}", s));
+ let name = s.as_str().unwrap_or_else(|| panic!("unrecognized sanitizer {s:?}"));
if !first {
f.write_str(", ")?;
}
("x86_64-apple-darwin", x86_64_apple_darwin),
("i686-apple-darwin", i686_apple_darwin),
- ("aarch64-fuchsia", aarch64_fuchsia),
- ("x86_64-fuchsia", x86_64_fuchsia),
+ ("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia),
+ ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia),
("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328),
("aarch64-nintendo-switch-freestanding", aarch64_nintendo_switch_freestanding),
+ ("armv7-sony-vita-newlibeabihf", armv7_sony_vita_newlibeabihf),
+
("armv7-unknown-linux-uclibceabi", armv7_unknown_linux_uclibceabi),
("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf),
let mut get_req_field = |name: &str| {
obj.remove(name)
.and_then(|j| j.as_str().map(str::to_string))
- .ok_or_else(|| format!("Field {} in target specification is required", name))
+ .ok_or_else(|| format!("Field {name} in target specification is required"))
};
let mut base = Target {
if let Some(s) = fp.as_str() {
base.frame_pointer = s
.parse()
- .map_err(|()| format!("'{}' is not a valid value for frame-pointer", s))?;
+ .map_err(|()| format!("'{s}' is not a valid value for frame-pointer"))?;
} else {
incorrect_type.push("frame-pointer".into())
}
return load_file(&p);
}
- Err(format!("Could not find specification for target {:?}", target_triple))
+ Err(format!("Could not find specification for target {target_triple:?}"))
}
TargetTriple::TargetJson { ref contents, .. } => {
let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?;
let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| {
io::Error::new(
io::ErrorKind::InvalidInput,
- format!("target path {:?} is not a valid file: {}", canonicalized_path, err),
+ format!("target path {canonicalized_path:?} is not a valid file: {err}"),
)
})?;
let triple = canonicalized_path
let mut hasher = DefaultHasher::new();
content.hash(&mut hasher);
let hash = hasher.finish();
- format!("{}-{}", triple, hash)
+ format!("{triple}-{hash}")
}
}
}
pub fn opts(kernel: &str) -> TargetOptions {
TargetOptions {
- os: format!("solid_{}", kernel).into(),
+ os: format!("solid_{kernel}").into(),
vendor: "kmc".into(),
executables: false,
frame_pointer: FramePointer::NonLeaf,
+++ /dev/null
-use crate::spec::{SanitizerSet, StackProbeType, Target};
-
-pub fn target() -> Target {
- let mut base = super::fuchsia_base::opts();
- base.cpu = "x86-64".into();
- base.max_atomic_width = Some(64);
- base.stack_probes = StackProbeType::X86;
- base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
-
- Target {
- llvm_target: "x86_64-fuchsia".into(),
- pointer_width: 64,
- data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
- .into(),
- arch: "x86_64".into(),
- options: base,
- }
-}
--- /dev/null
+use crate::spec::{SanitizerSet, StackProbeType, Target};
+
+pub fn target() -> Target {
+ let mut base = super::fuchsia_base::opts();
+ base.cpu = "x86-64".into();
+ base.max_atomic_width = Some(64);
+ base.stack_probes = StackProbeType::X86;
+ base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
+
+ Target {
+ llvm_target: "x86_64-unknown-fuchsia".into(),
+ pointer_width: 64,
+ data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+ .into(),
+ arch: "x86_64".into(),
+ options: base,
+ }
+}
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_middle::arena::ArenaAllocatable;
-use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, QueryResponse};
+use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse};
use rustc_middle::traits::query::Fallible;
use rustc_middle::ty::{self, Ty, TypeFoldable, TypeVisitable};
use rustc_middle::ty::{GenericArg, ToPredicate};
&mut self,
canonical_key: &Canonical<'tcx, K>,
operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
+ ) -> Fallible<CanonicalQueryResponse<'tcx, R>>
where
K: TypeFoldable<'tcx>,
R: Debug + TypeFoldable<'tcx>,
&mut self,
canonical_key: &Canonical<'tcx, K>,
operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
+ ) -> Fallible<CanonicalQueryResponse<'tcx, R>>
where
K: TypeFoldable<'tcx>,
R: Debug + TypeFoldable<'tcx>,
#[inline]
pub(super) fn has_overflow(&self, depth: usize) -> bool {
- self.current_limit.value_within_limit(depth + self.additional_depth)
+ !self.current_limit.value_within_limit(depth + self.additional_depth)
}
/// Updating the current limit when hitting overflow.
param_env: ty::ParamEnv<'tcx>,
infcx: &'a InferCtxt<'tcx>,
+ single_match: Option<Result<ty::Const<'tcx>, ()>>,
}
+
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
type BreakTy = ();
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("is_const_evaluatable: candidate={:?}", c);
- if let Ok(()) = self.infcx.commit_if_ok(|_| {
+ if self.infcx.probe(|_| {
let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
- if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty())
- && let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct)
+ ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty()).is_ok()
+ && ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct).is_ok()
&& ocx.select_all_or_error().is_empty()
- {
- Ok(())
- } else {
- Err(())
- }
}) {
- ControlFlow::BREAK
- } else if let ty::ConstKind::Expr(e) = c.kind() {
+ self.single_match = match self.single_match {
+ None => Some(Ok(c)),
+ Some(Ok(o)) if o == c => Some(Ok(c)),
+ Some(_) => Some(Err(())),
+ };
+ }
+
+ if let ty::ConstKind::Expr(e) = c.kind() {
e.visit_with(self)
} else {
// FIXME(generic_const_exprs): This doesn't recurse into `<T as Trait<U>>::ASSOC`'s substs.
}
}
+ let mut single_match: Option<Result<ty::Const<'tcx>, ()>> = None;
+
for pred in param_env.caller_bounds() {
match pred.kind().skip_binder() {
ty::PredicateKind::ConstEvaluatable(ce) => {
let b_ct = tcx.expand_abstract_consts(ce);
- let mut v = Visitor { ct, infcx, param_env };
- let result = b_ct.visit_with(&mut v);
+ let mut v = Visitor { ct, infcx, param_env, single_match };
+ let _ = b_ct.visit_with(&mut v);
- if let ControlFlow::Break(()) = result {
- debug!("is_const_evaluatable: yes");
- return true;
- }
+ single_match = v.single_match;
}
_ => {} // don't care
}
}
+ if let Some(Ok(c)) = single_match {
+ let ocx = ObligationCtxt::new(infcx);
+ assert!(ocx.eq(&ObligationCause::dummy(), param_env, c.ty(), ct.ty()).is_ok());
+ assert!(ocx.eq(&ObligationCause::dummy(), param_env, c, ct).is_ok());
+ assert!(ocx.select_all_or_error().is_empty());
+ return true;
+ }
+
debug!("is_const_evaluatable: no");
false
}
use super::TraitEngine;
use super::{ChalkFulfillmentContext, FulfillmentContext};
+use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
use crate::traits::NormalizeExt;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::infer::at::ToTrace;
use rustc_infer::infer::canonical::{
- Canonical, CanonicalVarValues, CanonicalizedQueryResponse, QueryResponse,
+ Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
};
use rustc_infer::infer::{InferCtxt, InferOk};
use rustc_infer::traits::query::Fallible;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::config::TraitSolver;
use rustc_span::Span;
pub trait TraitEngineExt<'tcx> {
impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
fn new(tcx: TyCtxt<'tcx>) -> Box<Self> {
- if tcx.sess.opts.unstable_opts.chalk {
- Box::new(ChalkFulfillmentContext::new())
- } else {
- Box::new(FulfillmentContext::new())
+ match tcx.sess.opts.unstable_opts.trait_solver {
+ TraitSolver::Classic => Box::new(FulfillmentContext::new()),
+ TraitSolver::Chalk => Box::new(ChalkFulfillmentContext::new()),
+ TraitSolver::Next => Box::new(NextFulfillmentCtxt::new()),
}
}
fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self> {
- if tcx.sess.opts.unstable_opts.chalk {
- Box::new(ChalkFulfillmentContext::new_in_snapshot())
- } else {
- Box::new(FulfillmentContext::new_in_snapshot())
+ match tcx.sess.opts.unstable_opts.trait_solver {
+ TraitSolver::Classic => Box::new(FulfillmentContext::new_in_snapshot()),
+ TraitSolver::Chalk => Box::new(ChalkFulfillmentContext::new_in_snapshot()),
+ TraitSolver::Next => Box::new(NextFulfillmentCtxt::new()),
}
}
}
&self,
inference_vars: CanonicalVarValues<'tcx>,
answer: T,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, T>>
+ ) -> Fallible<CanonicalQueryResponse<'tcx, T>>
where
T: Debug + TypeFoldable<'tcx>,
Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
use rustc_infer::infer::{InferOk, TypeTrace};
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
-use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
use rustc_middle::ty::{
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
TypeVisitable,
};
+use rustc_session::config::TraitSolver;
use rustc_session::Limit;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::symbol::sym;
),
}
};
-
+ self.check_for_binding_assigned_block_without_tail_expression(
+ &obligation,
+ &mut err,
+ trait_predicate,
+ );
if self.suggest_add_reference_to_arg(
&obligation,
&mut err,
);
}
+ if self.suggest_add_clone_to_arg(&obligation, &mut err, trait_predicate) {
+ err.emit();
+ return;
+ }
+
if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) {
err.emit();
return;
}
ty::PredicateKind::WellFormed(ty) => {
- if !self.tcx.sess.opts.unstable_opts.chalk {
+ if self.tcx.sess.opts.unstable_opts.trait_solver == TraitSolver::Classic {
// WF predicates cannot themselves make
// errors. They can only block due to
// ambiguity; otherwise, they always
// which bounds actually failed to hold.
self.tcx.sess.struct_span_err(
span,
- &format!("the type `{}` is not well-formed (chalk)", ty),
+ &format!("the type `{}` is not well-formed", ty),
)
}
}
}
}
+ OutputTypeParameterMismatch(
+ found_trait_ref,
+ expected_trait_ref,
+ terr @ TypeError::CyclicTy(_),
+ ) => {
+ let self_ty = found_trait_ref.self_ty().skip_binder();
+ let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() {
+ (
+ ObligationCause::dummy_with_span(tcx.def_span(def_id)),
+ TypeError::CyclicTy(self_ty),
+ )
+ } else {
+ (obligation.cause.clone(), terr)
+ };
+ self.report_and_explain_type_error(
+ TypeTrace::poly_trait_refs(&cause, true, expected_trait_ref, found_trait_ref),
+ terr,
+ )
+ }
OutputTypeParameterMismatch(found_trait_ref, expected_trait_ref, _) => {
let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref);
let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
-
err.emit();
}
}
if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) =
(body_id, subst.map(|subst| subst.unpack()))
{
- struct FindExprBySpan<'hir> {
- span: Span,
- result: Option<&'hir hir::Expr<'hir>>,
- }
-
- impl<'v> hir::intravisit::Visitor<'v> for FindExprBySpan<'v> {
- fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
- if self.span == ex.span {
- self.result = Some(ex);
- } else {
- hir::intravisit::walk_expr(self, ex);
- }
- }
- }
-
- let mut expr_finder = FindExprBySpan { span, result: None };
-
+ let mut expr_finder = FindExprBySpan::new(span);
expr_finder.visit_expr(&self.tcx.hir().body(body_id).value);
if let Some(hir::Expr {
}
}
+/// Crude way of getting back an `Expr` from a `Span`.
+pub struct FindExprBySpan<'hir> {
+ pub span: Span,
+ pub result: Option<&'hir hir::Expr<'hir>>,
+ pub ty_result: Option<&'hir hir::Ty<'hir>>,
+}
+
+impl<'hir> FindExprBySpan<'hir> {
+ fn new(span: Span) -> Self {
+ Self { span, result: None, ty_result: None }
+ }
+}
+
+impl<'v> Visitor<'v> for FindExprBySpan<'v> {
+ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+ if self.span == ex.span {
+ self.result = Some(ex);
+ } else {
+ hir::intravisit::walk_expr(self, ex);
+ }
+ }
+ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+ if self.span == ty.span {
+ self.ty_result = Some(ty);
+ } else {
+ hir::intravisit::walk_ty(self, ty);
+ }
+ }
+}
+
/// 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 {
// 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::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
hir::TyKind::Path(hir::QPath::Resolved(None, path))
if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
{
Some(if movability.is_some() { "an async closure" } else { "a closure" })
}),
hir::Node::Expr(hir::Expr { .. }) => {
- let parent_hid = hir.get_parent_node(hir_id);
+ let parent_hid = hir.parent_id(hir_id);
if parent_hid != hir_id { self.describe_enclosure(parent_hid) } else { None }
}
_ => None,
// ignore-tidy-filelength
-use super::{DefIdOrName, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation};
+use super::{
+ DefIdOrName, FindExprBySpan, Obligation, ObligationCause, ObligationCauseCode,
+ PredicateObligation,
+};
use crate::autoderef::Autoderef;
use crate::infer::InferCtxt;
use crate::traits::{NormalizeExt, ObligationCtxt};
use hir::def::CtorOf;
-use hir::HirId;
+use hir::{Expr, HirId};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool;
+ fn check_for_binding_assigned_block_without_tail_expression(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ );
+
+ fn suggest_add_clone_to_arg(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool;
+
fn suggest_add_reference_to_arg(
&self,
obligation: &PredicateObligation<'tcx>,
fn point_at_returns_when_relevant(
&self,
- err: &mut Diagnostic,
+ err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
obligation: &PredicateObligation<'tcx>,
);
let hir = self.tcx.hir();
let hir_id = hir.local_def_id_to_hir_id(def_id.as_local()?);
- let parent_node = hir.get_parent_node(hir_id);
- match hir.find(parent_node) {
+ match hir.find_parent(hir_id) {
Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => {
get_name(err, &local.pat.kind)
}
true
}
+ fn check_for_binding_assigned_block_without_tail_expression(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) {
+ let mut span = obligation.cause.span;
+ while span.from_expansion() {
+ // Remove all the desugaring and macro contexts.
+ span.remove_mark();
+ }
+ let mut expr_finder = FindExprBySpan::new(span);
+ let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else { return; };
+ expr_finder.visit_expr(&body);
+ let Some(expr) = expr_finder.result else { return; };
+ let Some(typeck) = &self.typeck_results else { return; };
+ let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else { return; };
+ if !ty.is_unit() {
+ return;
+ };
+ let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; };
+ let hir::def::Res::Local(hir_id) = path.res else { return; };
+ let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else {
+ return;
+ };
+ let Some(hir::Node::Local(hir::Local {
+ ty: None,
+ init: Some(init),
+ ..
+ })) = self.tcx.hir().find_parent(pat.hir_id) else { return; };
+ let hir::ExprKind::Block(block, None) = init.kind else { return; };
+ if block.expr.is_some() {
+ return;
+ }
+ let [.., stmt] = block.stmts else {
+ err.span_label(block.span, "this empty block is missing a tail expression");
+ return;
+ };
+ let hir::StmtKind::Semi(tail_expr) = stmt.kind else { return; };
+ let Some(ty) = typeck.expr_ty_opt(tail_expr) else {
+ err.span_label(block.span, "this block is missing a tail expression");
+ return;
+ };
+ let ty = self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(ty));
+ let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, ty));
+
+ let new_obligation =
+ self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
+ if self.predicate_must_hold_modulo_regions(&new_obligation) {
+ err.span_suggestion_short(
+ stmt.span.with_lo(tail_expr.span.hi()),
+ "remove this semicolon",
+ "",
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.span_label(block.span, "this block is missing a tail expression");
+ }
+ }
+
+ fn suggest_add_clone_to_arg(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool {
+ let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
+ let ty = self.tcx.erase_late_bound_regions(self_ty);
+ let owner = self.tcx.hir().get_parent_item(obligation.cause.body_id);
+ let Some(generics) = self.tcx.hir().get_generics(owner.def_id) else { return false };
+ let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false };
+ let ty::Param(param) = inner_ty.kind() else { return false };
+ let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() else { return false };
+ let arg_node = self.tcx.hir().get(*arg_hir_id);
+ let Node::Expr(Expr { kind: hir::ExprKind::Path(_), ..}) = arg_node else { return false };
+
+ let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None);
+ let has_clone = |ty| {
+ self.type_implements_trait(clone_trait, [ty], obligation.param_env)
+ .must_apply_modulo_regions()
+ };
+
+ let new_obligation = self.mk_trait_obligation_with_new_self_ty(
+ obligation.param_env,
+ trait_pred.map_bound(|trait_pred| (trait_pred, *inner_ty)),
+ );
+
+ if self.predicate_may_hold(&new_obligation) && has_clone(ty) {
+ if !has_clone(param.to_ty(self.tcx)) {
+ suggest_constraining_type_param(
+ self.tcx,
+ generics,
+ err,
+ param.name.as_str(),
+ "Clone",
+ Some(clone_trait),
+ );
+ }
+ err.span_suggestion_verbose(
+ obligation.cause.span.shrink_to_hi(),
+ "consider using clone here",
+ ".clone()".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ return true;
+ }
+ false
+ }
+
fn suggest_add_reference_to_arg(
&self,
obligation: &PredicateObligation<'tcx>,
.source_map()
.span_take_while(span, |c| c.is_whitespace() || *c == '&');
if points_at_arg && mutability.is_not() && refs_number > 0 {
+ // If we have a call like foo(&mut buf), then don't suggest foo(&mut mut buf)
+ if snippet
+ .trim_start_matches(|c: char| c.is_whitespace() || c == '&')
+ .starts_with("mut")
+ {
+ return;
+ }
err.span_suggestion_verbose(
sp,
"consider changing this borrow's mutability",
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
let hir = self.tcx.hir();
- let parent_node = hir.get_parent_node(obligation.cause.body_id);
+ let parent_node = hir.parent_id(obligation.cause.body_id);
let node = hir.find(parent_node);
if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node
&& let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind
fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> {
let hir = self.tcx.hir();
- let parent_node = hir.get_parent_node(obligation.cause.body_id);
+ let parent_node = hir.parent_id(obligation.cause.body_id);
let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) = hir.find(parent_node) else {
return None;
};
}
let hir = self.tcx.hir();
- let fn_hir_id = hir.get_parent_node(obligation.cause.body_id);
+ let fn_hir_id = hir.parent_id(obligation.cause.body_id);
let node = hir.find(fn_hir_id);
let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(sig, _, body_id),
fn point_at_returns_when_relevant(
&self,
- err: &mut Diagnostic,
+ err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
obligation: &PredicateObligation<'tcx>,
) {
match obligation.cause.code().peel_derives() {
}
let hir = self.tcx.hir();
- let parent_node = hir.get_parent_node(obligation.cause.body_id);
+ let parent_node = hir.parent_id(obligation.cause.body_id);
let node = hir.find(parent_node);
if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) =
node
for expr in &visitor.returns {
if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) {
let ty = self.resolve_vars_if_possible(returned_ty);
- err.span_label(expr.span, &format!("this returned value is of type `{}`", ty));
+ if ty.references_error() {
+ // don't print out the [type error] here
+ err.delay_as_bug();
+ } else {
+ err.span_label(
+ expr.span,
+ &format!("this returned value is of type `{}`", ty),
+ );
+ }
}
}
}
let expr = hir.expect_expr(expr_id);
debug!("target_ty evaluated from {:?}", expr);
- let parent = hir.get_parent_node(expr_id);
+ let parent = hir.parent_id(expr_id);
if let Some(hir::Node::Expr(e)) = hir.find(parent) {
let parent_span = hir.span(parent);
let parent_did = parent.owner.to_def_id();
}
}
ObligationCauseCode::VariableType(hir_id) => {
- let parent_node = self.tcx.hir().get_parent_node(hir_id);
+ let parent_node = self.tcx.hir().parent_id(hir_id);
match self.tcx.hir().find(parent_node) {
+ Some(Node::Local(hir::Local { ty: Some(ty), .. })) => {
+ err.span_suggestion_verbose(
+ ty.span.shrink_to_lo(),
+ "consider borrowing here",
+ "&",
+ Applicability::MachineApplicable,
+ );
+ err.note("all local variables must have a statically known size");
+ }
Some(Node::Local(hir::Local {
init: Some(hir::Expr { kind: hir::ExprKind::Index(_, _), span, .. }),
..
// Don't print the tuple of capture types
'print: {
if !is_upvar_tys_infer_tuple {
- let msg = format!("required because it appears within the type `{}`", ty);
+ let msg = with_forced_trimmed_paths!(format!(
+ "required because it appears within the type `{ty}`",
+ ));
match ty.kind() {
ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) {
Some(ident) => err.span_note(ident.span, &msg),
let mut msg =
"required because it captures the following types: ".to_owned();
for ty in bound_tys.skip_binder() {
- write!(msg, "`{}`, ", ty).unwrap();
+ with_forced_trimmed_paths!(write!(msg, "`{}`, ", ty).unwrap());
}
err.note(msg.trim_end_matches(", "))
}
let kind = tcx.generator_kind(def_id).unwrap().descr();
err.span_note(
sp,
- &format!("required because it's used within this {}", kind),
+ with_forced_trimmed_paths!(&format!(
+ "required because it's used within this {kind}",
+ )),
)
}
ty::Closure(def_id, _) => err.span_note(
let expr_ty = with_forced_trimmed_paths!(self.ty_to_string(expr_ty));
err.span_label(
expr_span,
- format!("return type was inferred to be `{expr_ty}` here"),
+ with_forced_trimmed_paths!(format!(
+ "return type was inferred to be `{expr_ty}` here",
+ )),
);
}
}
span: Span,
) {
let body_hir_id = obligation.cause.body_id;
- let item_id = self.tcx.hir().get_parent_node(body_hir_id);
+ let item_id = self.tcx.hir().parent_id(body_hir_id);
if let Some(body_id) =
self.tcx.hir().maybe_body_owned_by(self.tcx.hir().local_def_id(item_id))
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
&& let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id)
- && let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
+ && let parent_hir_id = self.tcx.hir().parent_id(binding.hir_id)
&& let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id)
&& let Some(binding_expr) = local.init
{
})) = call_node
{
if Some(rcvr.span) == err.span.primary_span() {
- err.replace_span_with(path.ident.span);
+ err.replace_span_with(path.ident.span, true);
}
}
if let Some(Node::Expr(hir::Expr {
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
&& let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id)
- && let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
- && let Some(parent) = self.tcx.hir().find(parent_hir_id)
+ && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id)
{
// We've reached the root of the method call chain...
if let hir::Node::Local(local) = parent
/// spans etc. passed in and hence can do reasonable
/// error reporting on their own.
Standard,
- /// Canonicalized queries get dummy spans and hence
+ /// Canonical queries get dummy spans and hence
/// must generally propagate errors to
/// pre-canonicalization callsites.
Canonical,
obligation.param_env,
cause.clone(),
obligation.recursion_depth + 1,
- tcx.bound_trait_impl_trait_tys(impl_fn_def_id)
+ tcx.bound_return_position_impl_trait_in_trait_tys(impl_fn_def_id)
.map_bound(|tys| {
tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.def_id])
})
-use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
use crate::traits::query::Fallible;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
fn perform_query(
tcx: TyCtxt<'tcx>,
- canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
+ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
tcx.type_op_ascribe_user_type(canonicalized)
}
}
-use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
use crate::traits::query::Fallible;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
fn perform_query(
tcx: TyCtxt<'tcx>,
- canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
+ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
tcx.type_op_eq(canonicalized)
}
}
-use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
use crate::traits::query::Fallible;
use rustc_infer::traits::query::OutlivesBound;
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt};
fn perform_query(
tcx: TyCtxt<'tcx>,
- canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> {
+ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> {
// FIXME this `unchecked_map` is only necessary because the
// query is defined as taking a `ParamEnvAnd<Ty>`; it should
// take an `ImpliedOutlivesBounds` instead
use crate::infer::canonical::{
- Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues, QueryRegionConstraints,
+ Canonical, CanonicalQueryResponse, OriginalQueryValues, QueryRegionConstraints,
};
use crate::infer::{InferCtxt, InferOk};
use crate::traits::query::Fallible;
use crate::traits::ObligationCause;
-use rustc_infer::infer::canonical::{Canonical, Certainty};
+use rustc_infer::infer::canonical::Certainty;
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::PredicateObligations;
use rustc_middle::ty::fold::TypeFoldable;
/// not captured in the return value.
fn perform_query(
tcx: TyCtxt<'tcx>,
- canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>>;
+ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>>;
fn fully_perform_into(
query_key: ParamEnvAnd<'tcx, Self>,
-use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
use crate::traits::query::Fallible;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt};
fn perform_query(
tcx: TyCtxt<'tcx>,
- canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> {
+ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> {
T::type_op_method(tcx, canonicalized)
}
}
pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'tcx> + Copy {
fn type_op_method(
tcx: TyCtxt<'tcx>,
- canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>>;
+ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+ ) -> Fallible<CanonicalQueryResponse<'tcx, Self>>;
}
impl<'tcx> Normalizable<'tcx> for Ty<'tcx> {
fn type_op_method(
tcx: TyCtxt<'tcx>,
- canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
+ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+ ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
tcx.type_op_normalize_ty(canonicalized)
}
}
impl<'tcx> Normalizable<'tcx> for ty::Predicate<'tcx> {
fn type_op_method(
tcx: TyCtxt<'tcx>,
- canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
+ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+ ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
tcx.type_op_normalize_predicate(canonicalized)
}
}
impl<'tcx> Normalizable<'tcx> for ty::PolyFnSig<'tcx> {
fn type_op_method(
tcx: TyCtxt<'tcx>,
- canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
+ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+ ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
tcx.type_op_normalize_poly_fn_sig(canonicalized)
}
}
impl<'tcx> Normalizable<'tcx> for ty::FnSig<'tcx> {
fn type_op_method(
tcx: TyCtxt<'tcx>,
- canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
+ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+ ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
tcx.type_op_normalize_fn_sig(canonicalized)
}
}
-use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutlivesResult};
use crate::traits::query::Fallible;
use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
fn perform_query(
tcx: TyCtxt<'tcx>,
- canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> {
+ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> {
// Subtle: note that we are not invoking
// `infcx.at(...).dropck_outlives(...)` here, but rather the
// underlying `dropck_outlives` query. This same underlying
-use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
use crate::traits::query::Fallible;
use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt};
fn perform_query(
tcx: TyCtxt<'tcx>,
- mut canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
+ mut canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
match canonicalized.value.value.predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
canonicalized.value.param_env.remap_constness_with(pred.constness);
-use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
use crate::traits::query::Fallible;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
fn perform_query(
tcx: TyCtxt<'tcx>,
- canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
+ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
tcx.type_op_subtype(canonicalized)
}
}
use rustc_infer::infer::InferOk;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
use rustc_middle::ty::{
- self, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef,
- ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
+ self, Binder, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef,
+ ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt,
};
+use rustc_session::config::TraitSolver;
use rustc_span::def_id::DefId;
use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
ImplSource::Future(vtable_future)
}
- FnPointerCandidate { .. } => {
- let data = self.confirm_fn_pointer_candidate(obligation)?;
+ FnPointerCandidate { is_const } => {
+ let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
ImplSource::FnPointer(data)
}
fn confirm_fn_pointer_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
+ is_const: bool,
) -> Result<ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
{
debug!(?obligation, "confirm_fn_pointer_candidate");
+ let tcx = self.tcx();
let self_ty = self
.infcx
.shallow_resolve(obligation.self_ty().no_bound_vars())
.expect("fn pointer should not capture bound vars from predicate");
- let sig = self_ty.fn_sig(self.tcx());
+ let sig = self_ty.fn_sig(tcx);
let trait_ref = closure_trait_ref_and_return_type(
- self.tcx(),
+ tcx,
obligation.predicate.def_id(),
self_ty,
sig,
.map_bound(|(trait_ref, _)| trait_ref);
let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+ let cause = obligation.derived_cause(BuiltinDerivedObligation);
+
+ if obligation.is_const() && !is_const {
+ // function is a trait method
+ if let ty::FnDef(def_id, substs) = self_ty.kind() && let Some(trait_id) = tcx.trait_of_item(*def_id) {
+ let trait_ref = TraitRef::from_method(tcx, trait_id, *substs);
+ let poly_trait_pred = Binder::dummy(trait_ref).with_constness(ty::BoundConstness::ConstIfConst);
+ let obligation = Obligation::new(tcx, cause.clone(), obligation.param_env, poly_trait_pred);
+ nested.push(obligation);
+ }
+ }
// Confirm the `type Output: Sized;` bound that is present on `FnOnce`
- let cause = obligation.derived_cause(BuiltinDerivedObligation);
let output_ty = self.infcx.replace_bound_vars_with_placeholders(sig.output());
let output_ty = normalize_with_depth_to(
self,
debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations");
// FIXME: Chalk
-
- if !self.tcx().sess.opts.unstable_opts.chalk {
+ if self.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Chalk {
nested.push(obligation.with(
self.tcx(),
ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)),
// contain the "'static" lifetime (any other lifetime
// would either be late-bound or local), so it is guaranteed
// to outlive any other lifetime
- if pred.0.is_global() && !pred.0.has_late_bound_regions() {
+ if pred.0.is_global() && !pred.0.has_late_bound_vars() {
Ok(EvaluatedToOk)
} else {
Ok(EvaluatedToOkModuloRegions)
FutureCandidate => {}
// FnDef where the function is const
FnPointerCandidate { is_const: true } => {}
+ FnPointerCandidate { is_const: false } => {
+ if let ty::FnDef(def_id, _) = obligation.self_ty().skip_binder().kind() && tcx.trait_of_item(*def_id).is_some() {
+ // Trait methods are not seen as const unless the trait is implemented as const.
+ // We do not filter that out in here, but nested obligations will be needed to confirm this.
+ } else {
+ continue
+ }
+ }
ConstDestructCandidate(_) => {}
_ => {
// reject all other types of candidates
// Check if a bound would previously have been removed when normalizing
// the param_env so that it can be given the lowest priority. See
// #50825 for the motivation for this.
- let is_global = |cand: &ty::PolyTraitPredicate<'tcx>| {
- cand.is_global() && !cand.has_late_bound_regions()
- };
+ let is_global =
+ |cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_late_bound_vars();
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
// `DiscriminantKindCandidate`, `ConstDestructCandidate`
use rustc_errors::Diagnostic;
use rustc_span::Span;
-use smallvec::smallvec;
use smallvec::SmallVec;
use rustc_data_structures::fx::FxHashSet;
tcx.sess.delay_span_bug(
span,
- &format!("upvar_tys for closure not found. Expected capture information for closure {}", ty,),
+ &format!("upvar_tys for closure not found. Expected capture information for closure {ty}",),
);
return Err(NoSolution);
}
// be fully resolved.
tcx.sess.delay_span_bug(
span,
- &format!("upvar_tys for generator not found. Expected capture information for generator {}", ty,),
+ &format!("upvar_tys for generator not found. Expected capture information for generator {ty}",),
);
return Err(NoSolution);
}
// us a test case.
debug_assert_eq!(normalized_value, resolved_value);
let erased = infcx.tcx.erase_regions(resolved_value);
- debug_assert!(!erased.needs_infer(), "{:?}", erased);
+ debug_assert!(!erased.needs_infer(), "{erased:?}");
Ok(erased)
}
Err(NoSolution) => Err(NoSolution),
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable};
-use rustc_middle::ty::{ParamEnvAnd, Predicate, ToPredicate};
-use rustc_middle::ty::{UserSelfTy, UserSubsts};
+use rustc_middle::ty::{ParamEnvAnd, Predicate};
+use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType};
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtBuilderExt;
use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
span: Option<Span>,
) -> Result<(), NoSolution> {
- let (param_env, AscribeUserType { mir_ty, def_id, user_substs }) = key.into_parts();
- debug!(
- "type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
- mir_ty, def_id, user_substs
- );
+ let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts();
+ debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty);
let span = span.unwrap_or(DUMMY_SP);
+ match user_ty {
+ UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?,
+ UserType::TypeOf(def_id, user_substs) => {
+ relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)?
+ }
+ };
+ Ok(())
+}
+
+#[instrument(level = "debug", skip(ocx, param_env, span))]
+fn relate_mir_and_user_ty<'tcx>(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ span: Span,
+ mir_ty: Ty<'tcx>,
+ user_ty: Ty<'tcx>,
+) -> Result<(), NoSolution> {
+ let cause = ObligationCause::dummy_with_span(span);
+ let user_ty = ocx.normalize(&cause, param_env, user_ty);
+ ocx.eq(&cause, param_env, mir_ty, user_ty)?;
+ // FIXME(#104764): We should check well-formedness before normalization.
+ let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into()));
+ ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate));
+
+ Ok(())
+}
+
+#[instrument(level = "debug", skip(ocx, param_env, span))]
+fn relate_mir_and_user_substs<'tcx>(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ span: Span,
+ mir_ty: Ty<'tcx>,
+ def_id: hir::def_id::DefId,
+ user_substs: UserSubsts<'tcx>,
+) -> Result<(), NoSolution> {
let UserSubsts { user_self_ty, substs } = user_substs;
let tcx = ocx.infcx.tcx;
let cause = ObligationCause::dummy_with_span(span);
}
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
+ let self_ty = ocx.normalize(&cause, param_env, self_ty);
let impl_self_ty = tcx.bound_type_of(impl_def_id).subst(tcx, substs);
let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty);
ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
- let predicate: Predicate<'tcx> =
- ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())).to_predicate(tcx);
+ let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()));
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
}
// them? This would only be relevant if some input
// type were ill-formed but did not appear in `ty`,
// which...could happen with normalization...
- let predicate: Predicate<'tcx> =
- ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(tcx);
+ let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()));
ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate));
Ok(())
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
Self::Uninit => f.write_str("??u8"),
- Self::Init(b) => write!(f, "{:#04x}u8", b),
+ Self::Init(b) => write!(f, "{b:#04x}u8"),
}
}
}
// See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
let noalias_for_box = cx.tcx.sess.opts.unstable_opts.box_noalias.unwrap_or(true);
+ // LLVM prior to version 12 had known miscompiles in the presence of noalias attributes
+ // (see #54878), so it was conditionally disabled, but we don't support earlier
+ // versions at all anymore. We still support turning it off using -Zmutable-noalias.
+ let noalias_mut_ref = cx.tcx.sess.opts.unstable_opts.mutable_noalias.unwrap_or(true);
+
// `&mut` pointer parameters never alias other parameters,
// or mutable global data
//
// and can be marked as both `readonly` and `noalias`, as
// LLVM's definition of `noalias` is based solely on memory
// dependencies rather than pointer equality
- //
- // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute
- // for UniqueBorrowed arguments, so that the codegen backend can decide whether
- // or not to actually emit the attribute. It can also be controlled with the
- // `-Zmutable-noalias` debugging option.
let no_alias = match kind {
- PointerKind::SharedMutable
- | PointerKind::UniqueBorrowed
- | PointerKind::UniqueBorrowedPinned => false,
+ PointerKind::SharedMutable | PointerKind::UniqueBorrowedPinned => false,
+ PointerKind::UniqueBorrowed => noalias_mut_ref,
PointerKind::UniqueOwned => noalias_for_box,
- PointerKind::Frozen => !is_return,
+ PointerKind::Frozen => true,
};
- if no_alias {
+ // We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics
+ // (see <https://github.com/rust-lang/unsafe-code-guidelines/issues/385#issuecomment-1368055745>).
+ if no_alias && !is_return {
attrs.set(ArgAttribute::NoAlias);
}
if kind == PointerKind::Frozen && !is_return {
attrs.set(ArgAttribute::ReadOnly);
}
-
- if kind == PointerKind::UniqueBorrowed && !is_return {
- attrs.set(ArgAttribute::NoAliasMutRef);
- }
}
}
}
&& trait_item_id != leaf_def.item.def_id
&& let Some(leaf_def_item) = leaf_def.item.def_id.as_local()
{
- tcx.compare_assoc_const_impl_item_with_trait_item((
+ tcx.compare_impl_const((
leaf_def_item,
trait_item_id,
))?;
}
let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
- let metadata = match unsized_part.kind() {
- ty::Foreign(..) => {
+
+ let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
+ let metadata_ty = tcx.normalize_erasing_regions(
+ param_env,
+ tcx.mk_projection(metadata_def_id, [pointee]),
+ );
+ let metadata_layout = cx.layout_of(metadata_ty)?;
+ // If the metadata is a 1-zst, then the pointer is thin.
+ if metadata_layout.is_zst() && metadata_layout.align.abi.bytes() == 1 {
return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
}
- ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
- ty::Dynamic(..) => {
- let mut vtable = scalar_unit(Pointer);
- vtable.valid_range_mut().start = 1;
- vtable
+
+ let Abi::Scalar(metadata) = metadata_layout.abi else {
+ return Err(LayoutError::Unknown(unsized_part));
+ };
+ metadata
+ } else {
+ match unsized_part.kind() {
+ ty::Foreign(..) => {
+ return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
+ }
+ ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
+ ty::Dynamic(..) => {
+ let mut vtable = scalar_unit(Pointer);
+ vtable.valid_range_mut().start = 1;
+ vtable
+ }
+ _ => {
+ return Err(LayoutError::Unknown(unsized_part));
+ }
}
- _ => return Err(LayoutError::Unknown(unsized_part)),
};
// Effectively a (ptr, meta) tuple.
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
+use rustc_session::config::TraitSolver;
use rustc_trait_selection::traits;
fn sized_constraint_for_ty<'tcx>(
// are any errors at that point, so outside of type inference you can be
// sure that this will succeed without errors anyway.
- if tcx.sess.opts.unstable_opts.chalk {
+ if tcx.sess.opts.unstable_opts.trait_solver == TraitSolver::Chalk {
let environment = well_formed_types_in_env(tcx, def_id);
predicates.extend(environment);
}
kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..),
..
}) => {
- let parent_hir_id = tcx.hir().get_parent_node(hir_id);
+ let parent_hir_id = tcx.hir().parent_id(hir_id);
match tcx.hir().get(parent_hir_id) {
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
/// Basically anything but `ReLateBound` and `ReErased`.
const HAS_FREE_REGIONS = 1 << 14;
- /// Does this have any `ReLateBound` regions? Used to check
- /// if a global bound is safe to evaluate.
+ /// Does this have any `ReLateBound` regions?
const HAS_RE_LATE_BOUND = 1 << 15;
+ /// Does this have any `Bound` types?
+ const HAS_TY_LATE_BOUND = 1 << 16;
+ /// Does this have any `ConstKind::Bound` consts?
+ const HAS_CT_LATE_BOUND = 1 << 17;
+ /// Does this have any bound variables?
+ /// Used to check if a global bound is safe to evaluate.
+ const HAS_LATE_BOUND = TypeFlags::HAS_RE_LATE_BOUND.bits
+ | TypeFlags::HAS_TY_LATE_BOUND.bits
+ | TypeFlags::HAS_CT_LATE_BOUND.bits;
/// Does this have any `ReErased` regions?
- const HAS_RE_ERASED = 1 << 16;
+ const HAS_RE_ERASED = 1 << 18;
/// Does this value have parameters/placeholders/inference variables which could be
/// replaced later, in a way that would change the results of `impl` specialization?
- const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
+ const STILL_FURTHER_SPECIALIZABLE = 1 << 19;
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
- const HAS_TY_FRESH = 1 << 18;
+ const HAS_TY_FRESH = 1 << 20;
/// Does this value have `InferConst::Fresh`?
- const HAS_CT_FRESH = 1 << 19;
+ const HAS_CT_FRESH = 1 << 21;
}
}
TyVar(ref v) => v.fmt(f),
IntVar(ref v) => v.fmt(f),
FloatVar(ref v) => v.fmt(f),
- FreshTy(v) => write!(f, "FreshTy({:?})", v),
- FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
- FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v),
+ FreshTy(v) => write!(f, "FreshTy({v:?})"),
+ FreshIntTy(v) => write!(f, "FreshIntTy({v:?})"),
+ FreshFloatTy(v) => write!(f, "FreshFloatTy({v:?})"),
}
}
}
TyVar(_) => write!(f, "_"),
IntVar(_) => write!(f, "{}", "{integer}"),
FloatVar(_) => write!(f, "{}", "{float}"),
- FreshTy(v) => write!(f, "FreshTy({})", v),
- FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
- FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v),
+ FreshTy(v) => write!(f, "FreshTy({v})"),
+ FreshIntTy(v) => write!(f, "FreshIntTy({v})"),
+ FreshFloatTy(v) => write!(f, "FreshFloatTy({v})"),
}
}
}
impl<I: Interner> fmt::Debug for RegionKind<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
- ReEarlyBound(data) => write!(f, "ReEarlyBound({:?})", data),
+ ReEarlyBound(data) => write!(f, "ReEarlyBound({data:?})"),
ReLateBound(binder_id, bound_region) => {
- write!(f, "ReLateBound({:?}, {:?})", binder_id, bound_region)
+ write!(f, "ReLateBound({binder_id:?}, {bound_region:?})")
}
ReFree(fr) => fr.fmt(f),
ReVar(vid) => vid.fmt(f),
- RePlaceholder(placeholder) => write!(f, "RePlaceholder({:?})", placeholder),
+ RePlaceholder(placeholder) => write!(f, "RePlaceholder({placeholder:?})"),
ReErased => f.write_str("ReErased"),
}
compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std'] }
[dev-dependencies]
-rand = "0.7"
-rand_xorshift = "0.2"
+rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
+rand_xorshift = "0.3.0"
[[test]]
name = "collectionstests"
use std::{mem, ptr};
-use rand::distributions::{Alphanumeric, Standard};
+use rand::distributions::{Alphanumeric, DistString, Standard};
use rand::Rng;
use test::{black_box, Bencher};
let mut v = vec![];
for _ in 0..len {
let n = rng.gen::<usize>() % 20 + 1;
- v.push((&mut rng).sample_iter(&Alphanumeric).take(n).collect());
+ v.push(Alphanumeric.sample_string(&mut rng, n));
}
v
}
// These are the magic symbols to call the global allocator. rustc generates
// them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
// (the code expanding that attribute macro generates those functions), or to call
- // the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
+ // the default implementations in std (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
// otherwise.
// The rustc fork of LLVM 14 and earlier also special-cases these function names to be able to optimize them
// like `malloc`, `realloc`, and `free`, respectively.
// `#[alloc_error_handler]`.
#[rustc_std_internal_symbol]
pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
- panic!("memory allocation of {size} bytes failed")
- }
-
- #[cfg(bootstrap)]
- #[rustc_std_internal_symbol]
- pub unsafe fn __rg_oom(size: usize, align: usize) -> ! {
- use crate::alloc::Layout;
-
- let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
extern "Rust" {
- #[lang = "oom"]
- fn oom_impl(layout: Layout) -> !;
+ // This symbol is emitted by rustc next to __rust_alloc_error_handler.
+ // Its value depends on the -Zoom={panic,abort} compiler option.
+ static __rust_alloc_error_handler_should_panic: u8;
+ }
+
+ #[allow(unused_unsafe)]
+ if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
+ panic!("memory allocation of {size} bytes failed")
+ } else {
+ core::panicking::panic_nounwind_fmt(format_args!(
+ "memory allocation of {size} bytes failed"
+ ))
}
- unsafe { oom_impl(layout) }
}
}
#[cfg(not(no_global_oom_handling))]
use core::iter::FromIterator;
use core::iter::{FusedIterator, Iterator};
-#[cfg(not(bootstrap))]
use core::marker::Tuple;
use core::marker::{Destruct, Unpin, Unsize};
use core::mem;
/// [`Layout`]: crate::Layout
#[stable(feature = "box_raw", since = "1.4.0")]
#[inline]
- #[must_use = "call `drop(from_raw(ptr))` if you intend to drop the `Box`"]
+ #[must_use = "call `drop(Box::from_raw(ptr))` if you intend to drop the `Box`"]
pub unsafe fn from_raw(raw: *mut T) -> Self {
unsafe { Self::from_raw_in(raw, Global) }
}
#[stable(feature = "fused", since = "1.26.0")]
impl<I: FusedIterator + ?Sized, A: Allocator> FusedIterator for Box<I, A> {}
-#[cfg(bootstrap)]
-#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
-impl<Args, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
- type Output = <F as FnOnce<Args>>::Output;
-
- extern "rust-call" fn call_once(self, args: Args) -> Self::Output {
- <F as FnOnce<Args>>::call_once(*self, args)
- }
-}
-
-#[cfg(not(bootstrap))]
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
impl<Args: Tuple, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
type Output = <F as FnOnce<Args>>::Output;
}
}
-#[cfg(bootstrap)]
-#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
-impl<Args, F: FnMut<Args> + ?Sized, A: Allocator> FnMut<Args> for Box<F, A> {
- extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
- <F as FnMut<Args>>::call_mut(self, args)
- }
-}
-
-#[cfg(not(bootstrap))]
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
impl<Args: Tuple, F: FnMut<Args> + ?Sized, A: Allocator> FnMut<Args> for Box<F, A> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
}
}
-#[cfg(bootstrap)]
-#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
-impl<Args, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> {
- extern "rust-call" fn call(&self, args: Args) -> Self::Output {
- <F as Fn<Args>>::call(self, args)
- }
-}
-
-#[cfg(not(bootstrap))]
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
impl<Args: Tuple, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> {
extern "rust-call" fn call(&self, args: Args) -> Self::Output {
// - Assumes that either `value` can be dereferenced, or is the
// `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
unsafe fn drop<T: ?Sized>(&self, value: *mut T) {
+ struct DropGuard<H> {
+ ptr: NonNull<u8>,
+ value_layout: Layout,
+ _marker: PhantomData<H>,
+ }
+
+ impl<H> Drop for DropGuard<H> {
+ fn drop(&mut self) {
+ unsafe {
+ // SAFETY: Layout must have been computable if we're in drop
+ let (layout, value_offset) =
+ WithHeader::<H>::alloc_layout(self.value_layout).unwrap_unchecked();
+
+ // Note: Don't deallocate if the layout size is zero, because the pointer
+ // didn't come from the allocator.
+ if layout.size() != 0 {
+ alloc::dealloc(self.ptr.as_ptr().sub(value_offset), layout);
+ } else {
+ debug_assert!(
+ value_offset == 0
+ && mem::size_of::<H>() == 0
+ && self.value_layout.size() == 0
+ );
+ }
+ }
+ }
+ }
+
unsafe {
- let value_layout = Layout::for_value_raw(value);
- // SAFETY: Layout must have been computable if we're in drop
- let (layout, value_offset) = Self::alloc_layout(value_layout).unwrap_unchecked();
+ // `_guard` will deallocate the memory when dropped, even if `drop_in_place` unwinds.
+ let _guard = DropGuard {
+ ptr: self.0,
+ value_layout: Layout::for_value_raw(value),
+ _marker: PhantomData::<H>,
+ };
// We only drop the value because the Pointee trait requires that the metadata is copy
// aka trivially droppable.
ptr::drop_in_place::<T>(value);
-
- // Note: Don't deallocate if the layout size is zero, because the pointer
- // didn't come from the allocator.
- if layout.size() != 0 {
- alloc::dealloc(self.0.as_ptr().sub(value_offset), layout);
- } else {
- debug_assert!(
- value_offset == 0 && mem::size_of::<H>() == 0 && value_layout.size() == 0
- );
- }
}
}
use super::*;
use crate::boxed::Box;
+use crate::testing::crash_test::{CrashTestDummy, Panic};
use std::iter::TrustedLen;
use std::panic::{catch_unwind, AssertUnwindSafe};
-use std::sync::atomic::{AtomicU32, Ordering};
#[test]
fn test_iterator() {
#[test]
fn test_drain_sorted_leak() {
- static DROPS: AtomicU32 = AtomicU32::new(0);
-
- #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
- struct D(u32, bool);
-
- impl Drop for D {
- fn drop(&mut self) {
- DROPS.fetch_add(1, Ordering::SeqCst);
-
- if self.1 {
- panic!("panic in `drop`");
- }
- }
- }
-
+ let d0 = CrashTestDummy::new(0);
+ let d1 = CrashTestDummy::new(1);
+ let d2 = CrashTestDummy::new(2);
+ let d3 = CrashTestDummy::new(3);
+ let d4 = CrashTestDummy::new(4);
+ let d5 = CrashTestDummy::new(5);
let mut q = BinaryHeap::from(vec![
- D(0, false),
- D(1, false),
- D(2, false),
- D(3, true),
- D(4, false),
- D(5, false),
+ d0.spawn(Panic::Never),
+ d1.spawn(Panic::Never),
+ d2.spawn(Panic::Never),
+ d3.spawn(Panic::InDrop),
+ d4.spawn(Panic::Never),
+ d5.spawn(Panic::Never),
]);
- catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).ok();
+ catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).unwrap_err();
+
+ assert_eq!(d0.dropped(), 1);
+ assert_eq!(d1.dropped(), 1);
+ assert_eq!(d2.dropped(), 1);
+ assert_eq!(d3.dropped(), 1);
+ assert_eq!(d4.dropped(), 1);
+ assert_eq!(d5.dropped(), 1);
+ assert!(q.is_empty());
+}
- assert_eq!(DROPS.load(Ordering::SeqCst), 6);
+#[test]
+fn test_drain_forget() {
+ let a = CrashTestDummy::new(0);
+ let b = CrashTestDummy::new(1);
+ let c = CrashTestDummy::new(2);
+ let mut q =
+ BinaryHeap::from(vec![a.spawn(Panic::Never), b.spawn(Panic::Never), c.spawn(Panic::Never)]);
+
+ catch_unwind(AssertUnwindSafe(|| {
+ let mut it = q.drain();
+ it.next();
+ mem::forget(it);
+ }))
+ .unwrap();
+ // Behaviour after leaking is explicitly unspecified and order is arbitrary,
+ // so it's fine if these start failing, but probably worth knowing.
+ assert!(q.is_empty());
+ assert_eq!(a.dropped() + b.dropped() + c.dropped(), 1);
+ assert_eq!(a.dropped(), 0);
+ assert_eq!(b.dropped(), 0);
+ assert_eq!(c.dropped(), 1);
+ drop(q);
+ assert_eq!(a.dropped(), 0);
+ assert_eq!(b.dropped(), 0);
+ assert_eq!(c.dropped(), 1);
+}
+
+#[test]
+fn test_drain_sorted_forget() {
+ let a = CrashTestDummy::new(0);
+ let b = CrashTestDummy::new(1);
+ let c = CrashTestDummy::new(2);
+ let mut q =
+ BinaryHeap::from(vec![a.spawn(Panic::Never), b.spawn(Panic::Never), c.spawn(Panic::Never)]);
+
+ catch_unwind(AssertUnwindSafe(|| {
+ let mut it = q.drain_sorted();
+ it.next();
+ mem::forget(it);
+ }))
+ .unwrap();
+ // Behaviour after leaking is explicitly unspecified,
+ // so it's fine if these start failing, but probably worth knowing.
+ assert_eq!(q.len(), 2);
+ assert_eq!(a.dropped(), 0);
+ assert_eq!(b.dropped(), 0);
+ assert_eq!(c.dropped(), 1);
+ drop(q);
+ assert_eq!(a.dropped(), 1);
+ assert_eq!(b.dropped(), 1);
+ assert_eq!(c.dropped(), 1);
}
#[test]
#[test]
#[cfg(not(target_os = "emscripten"))]
fn panic_safe() {
- use rand::{seq::SliceRandom, thread_rng};
+ use rand::seq::SliceRandom;
use std::cmp;
use std::panic::{self, AssertUnwindSafe};
use std::sync::atomic::{AtomicUsize, Ordering};
self.0.partial_cmp(&other.0)
}
}
- let mut rng = thread_rng();
+ let mut rng = crate::test_helpers::test_rng();
const DATASZ: usize = 32;
// Miri is too slow
let ntest = if cfg!(miri) { 1 } else { 10 };
-use super::super::testing::crash_test::{CrashTestDummy, Panic};
-use super::super::testing::ord_chaos::{Cyclic3, Governed, Governor};
-use super::super::testing::rng::DeterministicRng;
use super::Entry::{Occupied, Vacant};
use super::*;
use crate::boxed::Box;
use crate::fmt::Debug;
use crate::rc::Rc;
use crate::string::{String, ToString};
+use crate::testing::crash_test::{CrashTestDummy, Panic};
+use crate::testing::ord_chaos::{Cyclic3, Governed, Governor};
+use crate::testing::rng::DeterministicRng;
use crate::vec::Vec;
use std::cmp::Ordering;
use std::convert::TryFrom;
fn take(&mut self, key: &Q) -> Option<Self::Key>;
fn replace(&mut self, key: Self::Key) -> Option<Self::Key>;
}
-
-#[cfg(test)]
-mod testing;
pub fn ascend(
self,
) -> Result<Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::Edge>, Self> {
- let _ = BorrowType::TRAVERSAL_PERMIT;
+ const {
+ assert!(BorrowType::TRAVERSAL_PERMIT);
+ }
+
// We need to use raw pointers to nodes because, if BorrowType is marker::ValMut,
// there might be outstanding mutable references to values that we must not invalidate.
let leaf_ptr: *const _ = Self::as_leaf_ptr(&self);
/// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should
/// both, upon success, do nothing.
pub fn descend(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
- let _ = BorrowType::TRAVERSAL_PERMIT;
+ const {
+ assert!(BorrowType::TRAVERSAL_PERMIT);
+ }
+
// We need to use raw pointers to nodes because, if BorrowType is
// marker::ValMut, there might be outstanding mutable references to
// values that we must not invalidate. There's no worry accessing the
pub struct ValMut<'a>(PhantomData<&'a mut ()>);
pub trait BorrowType {
- // If node references of this borrow type allow traversing to other
- // nodes in the tree, this constant can be evaluated. Thus reading it
- // serves as a compile-time assertion.
- const TRAVERSAL_PERMIT: () = ();
+ /// If node references of this borrow type allow traversing to other
+ /// nodes in the tree, this constant is set to `true`. It can be used
+ /// for a compile-time assertion.
+ const TRAVERSAL_PERMIT: bool = true;
}
impl BorrowType for Owned {
- // Reject evaluation, because traversal isn't needed. Instead traversal
- // happens using the result of `borrow_mut`.
- // By disabling traversal, and only creating new references to roots,
- // we know that every reference of the `Owned` type is to a root node.
- const TRAVERSAL_PERMIT: () = panic!();
+ /// Reject traversal, because it isn't needed. Instead traversal
+ /// happens using the result of `borrow_mut`.
+ /// By disabling traversal, and only creating new references to roots,
+ /// we know that every reference of the `Owned` type is to a root node.
+ const TRAVERSAL_PERMIT: bool = false;
}
impl BorrowType for Dying {}
impl<'a> BorrowType for Immut<'a> {}
-use super::super::testing::crash_test::{CrashTestDummy, Panic};
-use super::super::testing::rng::DeterministicRng;
use super::*;
+use crate::testing::crash_test::{CrashTestDummy, Panic};
+use crate::testing::rng::DeterministicRng;
use crate::vec::Vec;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
+++ /dev/null
-// We avoid relying on anything else in the crate, apart from the `Debug` trait.
-use crate::fmt::Debug;
-use std::cmp::Ordering;
-use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-
-/// A blueprint for crash test dummy instances that monitor particular events.
-/// Some instances may be configured to panic at some point.
-/// Events are `clone`, `drop` or some anonymous `query`.
-///
-/// Crash test dummies are identified and ordered by an id, so they can be used
-/// as keys in a BTreeMap.
-#[derive(Debug)]
-pub struct CrashTestDummy {
- pub id: usize,
- cloned: AtomicUsize,
- dropped: AtomicUsize,
- queried: AtomicUsize,
-}
-
-impl CrashTestDummy {
- /// Creates a crash test dummy design. The `id` determines order and equality of instances.
- pub fn new(id: usize) -> CrashTestDummy {
- CrashTestDummy {
- id,
- cloned: AtomicUsize::new(0),
- dropped: AtomicUsize::new(0),
- queried: AtomicUsize::new(0),
- }
- }
-
- /// Creates an instance of a crash test dummy that records what events it experiences
- /// and optionally panics.
- pub fn spawn(&self, panic: Panic) -> Instance<'_> {
- Instance { origin: self, panic }
- }
-
- /// Returns how many times instances of the dummy have been cloned.
- pub fn cloned(&self) -> usize {
- self.cloned.load(SeqCst)
- }
-
- /// Returns how many times instances of the dummy have been dropped.
- pub fn dropped(&self) -> usize {
- self.dropped.load(SeqCst)
- }
-
- /// Returns how many times instances of the dummy have had their `query` member invoked.
- pub fn queried(&self) -> usize {
- self.queried.load(SeqCst)
- }
-}
-
-#[derive(Debug)]
-pub struct Instance<'a> {
- origin: &'a CrashTestDummy,
- panic: Panic,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum Panic {
- Never,
- InClone,
- InDrop,
- InQuery,
-}
-
-impl Instance<'_> {
- pub fn id(&self) -> usize {
- self.origin.id
- }
-
- /// Some anonymous query, the result of which is already given.
- pub fn query<R>(&self, result: R) -> R {
- self.origin.queried.fetch_add(1, SeqCst);
- if self.panic == Panic::InQuery {
- panic!("panic in `query`");
- }
- result
- }
-}
-
-impl Clone for Instance<'_> {
- fn clone(&self) -> Self {
- self.origin.cloned.fetch_add(1, SeqCst);
- if self.panic == Panic::InClone {
- panic!("panic in `clone`");
- }
- Self { origin: self.origin, panic: Panic::Never }
- }
-}
-
-impl Drop for Instance<'_> {
- fn drop(&mut self) {
- self.origin.dropped.fetch_add(1, SeqCst);
- if self.panic == Panic::InDrop {
- panic!("panic in `drop`");
- }
- }
-}
-
-impl PartialOrd for Instance<'_> {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- self.id().partial_cmp(&other.id())
- }
-}
-
-impl Ord for Instance<'_> {
- fn cmp(&self, other: &Self) -> Ordering {
- self.id().cmp(&other.id())
- }
-}
-
-impl PartialEq for Instance<'_> {
- fn eq(&self, other: &Self) -> bool {
- self.id().eq(&other.id())
- }
-}
-
-impl Eq for Instance<'_> {}
+++ /dev/null
-pub mod crash_test;
-pub mod ord_chaos;
-pub mod rng;
+++ /dev/null
-use std::cell::Cell;
-use std::cmp::Ordering::{self, *};
-use std::ptr;
-
-// Minimal type with an `Ord` implementation violating transitivity.
-#[derive(Debug)]
-pub enum Cyclic3 {
- A,
- B,
- C,
-}
-use Cyclic3::*;
-
-impl PartialOrd for Cyclic3 {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl Ord for Cyclic3 {
- fn cmp(&self, other: &Self) -> Ordering {
- match (self, other) {
- (A, A) | (B, B) | (C, C) => Equal,
- (A, B) | (B, C) | (C, A) => Less,
- (A, C) | (B, A) | (C, B) => Greater,
- }
- }
-}
-
-impl PartialEq for Cyclic3 {
- fn eq(&self, other: &Self) -> bool {
- self.cmp(&other) == Equal
- }
-}
-
-impl Eq for Cyclic3 {}
-
-// Controls the ordering of values wrapped by `Governed`.
-#[derive(Debug)]
-pub struct Governor {
- flipped: Cell<bool>,
-}
-
-impl Governor {
- pub fn new() -> Self {
- Governor { flipped: Cell::new(false) }
- }
-
- pub fn flip(&self) {
- self.flipped.set(!self.flipped.get());
- }
-}
-
-// Type with an `Ord` implementation that forms a total order at any moment
-// (assuming that `T` respects total order), but can suddenly be made to invert
-// that total order.
-#[derive(Debug)]
-pub struct Governed<'a, T>(pub T, pub &'a Governor);
-
-impl<T: Ord> PartialOrd for Governed<'_, T> {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl<T: Ord> Ord for Governed<'_, T> {
- fn cmp(&self, other: &Self) -> Ordering {
- assert!(ptr::eq(self.1, other.1));
- let ord = self.0.cmp(&other.0);
- if self.1.flipped.get() { ord.reverse() } else { ord }
- }
-}
-
-impl<T: PartialEq> PartialEq for Governed<'_, T> {
- fn eq(&self, other: &Self) -> bool {
- assert!(ptr::eq(self.1, other.1));
- self.0.eq(&other.0)
- }
-}
-
-impl<T: Eq> Eq for Governed<'_, T> {}
+++ /dev/null
-/// XorShiftRng
-pub struct DeterministicRng {
- count: usize,
- x: u32,
- y: u32,
- z: u32,
- w: u32,
-}
-
-impl DeterministicRng {
- pub fn new() -> Self {
- DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
- }
-
- /// Guarantees that each returned number is unique.
- pub fn next(&mut self) -> u32 {
- self.count += 1;
- assert!(self.count <= 70029);
- let x = self.x;
- let t = x ^ (x << 11);
- self.x = self.y;
- self.y = self.z;
- self.z = self.w;
- let w_ = self.w;
- self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
- self.w
- }
-}
use super::*;
+use crate::testing::crash_test::{CrashTestDummy, Panic};
use crate::vec::Vec;
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::thread;
-use rand::{thread_rng, RngCore};
+use rand::RngCore;
#[test]
fn test_basic() {
}
}
-fn fuzz_test(sz: i32) {
+fn fuzz_test(sz: i32, rng: &mut impl RngCore) {
let mut m: LinkedList<_> = LinkedList::new();
let mut v = vec![];
for i in 0..sz {
check_links(&m);
- let r: u8 = thread_rng().next_u32() as u8;
+ let r: u8 = rng.next_u32() as u8;
match r % 6 {
0 => {
m.pop_back();
#[test]
fn test_fuzz() {
+ let mut rng = crate::test_helpers::test_rng();
for _ in 0..25 {
- fuzz_test(3);
- fuzz_test(16);
+ fuzz_test(3, &mut rng);
+ fuzz_test(16, &mut rng);
#[cfg(not(miri))] // Miri is too slow
- fuzz_test(189);
+ fuzz_test(189, &mut rng);
}
}
#[test]
fn drain_filter_drop_panic_leak() {
- static mut DROPS: i32 = 0;
-
- struct D(bool);
-
- impl Drop for D {
- fn drop(&mut self) {
- unsafe {
- DROPS += 1;
- }
-
- if self.0 {
- panic!("panic in `drop`");
- }
- }
- }
-
+ let d0 = CrashTestDummy::new(0);
+ let d1 = CrashTestDummy::new(1);
+ let d2 = CrashTestDummy::new(2);
+ let d3 = CrashTestDummy::new(3);
+ let d4 = CrashTestDummy::new(4);
+ let d5 = CrashTestDummy::new(5);
+ let d6 = CrashTestDummy::new(6);
+ let d7 = CrashTestDummy::new(7);
let mut q = LinkedList::new();
- q.push_back(D(false));
- q.push_back(D(false));
- q.push_back(D(false));
- q.push_back(D(false));
- q.push_back(D(false));
- q.push_front(D(false));
- q.push_front(D(true));
- q.push_front(D(false));
-
- catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).ok();
-
- assert_eq!(unsafe { DROPS }, 8);
+ q.push_back(d3.spawn(Panic::Never));
+ q.push_back(d4.spawn(Panic::Never));
+ q.push_back(d5.spawn(Panic::Never));
+ q.push_back(d6.spawn(Panic::Never));
+ q.push_back(d7.spawn(Panic::Never));
+ q.push_front(d2.spawn(Panic::Never));
+ q.push_front(d1.spawn(Panic::InDrop));
+ q.push_front(d0.spawn(Panic::Never));
+
+ catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).unwrap_err();
+
+ assert_eq!(d0.dropped(), 1);
+ assert_eq!(d1.dropped(), 1);
+ assert_eq!(d2.dropped(), 1);
+ assert_eq!(d3.dropped(), 1);
+ assert_eq!(d4.dropped(), 1);
+ assert_eq!(d5.dropped(), 1);
+ assert_eq!(d6.dropped(), 1);
+ assert_eq!(d7.dropped(), 1);
assert!(q.is_empty());
}
/// buf.push_back(3);
/// buf.push_back(4);
/// buf.push_back(5);
+ /// buf.push_back(6);
/// assert_eq!(buf.get(1), Some(&4));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// buf.push_back(3);
/// buf.push_back(4);
/// buf.push_back(5);
+ /// buf.push_back(6);
+ /// assert_eq!(buf[1], 4);
/// if let Some(elem) = buf.get_mut(1) {
/// *elem = 7;
/// }
- ///
/// assert_eq!(buf[1], 7);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// [`Vec<T>`]: crate::vec::Vec
/// [`VecDeque<T>`]: crate::collections::VecDeque
///
- /// In its current implementation, this is a very cheap
- /// conversion. This isn't yet a guarantee though, and
- /// shouldn't be relied on.
+ /// This conversion is guaranteed to run in *O*(1) time
+ /// and to not re-allocate the `Vec`'s buffer or allocate
+ /// any additional memory.
#[inline]
fn from(other: Vec<T, A>) -> Self {
let (ptr, len, cap, alloc) = other.into_raw_parts_with_alloc();
//! This library provides smart pointers and collections for managing
//! heap-allocated values.
//!
-//! This library, like libcore, normally doesn’t need to be used directly
+//! This library, like core, normally doesn’t need to be used directly
//! since its contents are re-exported in the [`std` crate](../std/index.html).
//! Crates that use the `#![no_std]` attribute however will typically
//! not depend on `std`, so they’d use this crate instead.
))]
#![no_std]
#![needs_allocator]
-// To run liballoc tests without x.py without ending up with two copies of liballoc, Miri needs to be
+// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
// rustc itself never sets the feature, so this line has no affect there.
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_refs_to_cell)]
#![feature(core_intrinsics)]
+#![feature(core_panic)]
#![feature(const_eval_select)]
#![feature(const_pin)]
#![feature(const_waker)]
#![feature(fmt_internals)]
#![feature(fn_traits)]
#![feature(hasher_prefixfree_extras)]
+#![feature(inline_const)]
#![feature(inplace_iteration)]
#![feature(iter_advance_by)]
#![feature(iter_next_chunk)]
#![feature(trusted_len)]
#![feature(trusted_random_access)]
#![feature(try_trait_v2)]
-#![cfg_attr(not(bootstrap), feature(tuple_trait))]
+#![feature(tuple_trait)]
#![feature(unchecked_math)]
#![feature(unicode_internals)]
#![feature(unsize)]
#![feature(unsized_fn_params)]
#![feature(c_unwind)]
#![feature(with_negative_coherence)]
+#![cfg_attr(test, feature(panic_update_hook))]
//
// Rustdoc features:
#![feature(doc_cfg)]
extern crate std;
#[cfg(test)]
extern crate test;
+#[cfg(test)]
+mod testing;
// Module with internal macros used by other modules (needs to be included before other modules).
#[macro_use]
pub mod __export {
pub use core::format_args;
}
+
+#[cfg(test)]
+#[allow(dead_code)] // Not used in all configurations
+pub(crate) mod test_helpers {
+ /// Copied from `std::test_helpers::test_rng`, since these tests rely on the
+ /// seed not being the same for every RNG invocation too.
+ pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
+ use std::hash::{BuildHasher, Hash, Hasher};
+ let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
+ std::panic::Location::caller().hash(&mut hasher);
+ let hc64 = hasher.finish();
+ let seed_vec =
+ hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<crate::vec::Vec<u8>>();
+ let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
+ rand::SeedableRng::from_seed(seed)
+ }
+}
}
#[stable(feature = "rc_weak", since = "1.4.0")]
-impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
+impl<T: ?Sized> fmt::Debug for Weak<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(Weak)")
}
use crate::boxed::Box;
use crate::vec::Vec;
+#[cfg(test)]
+mod tests;
+
#[unstable(feature = "slice_range", issue = "76393")]
pub use core::slice::range;
#[unstable(feature = "array_chunks", issue = "74985")]
///
/// ```error
/// error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predica
-/// --> src/liballoc/slice.rs:608:6
+/// --> library/alloc/src/slice.rs:608:6
/// |
/// 608 | impl<T: Clone, V: Borrow<[T]>> Concat for [V] {
/// | ^ unconstrained type parameter
--- /dev/null
+use crate::borrow::ToOwned;
+use crate::rc::Rc;
+use crate::string::ToString;
+use crate::test_helpers::test_rng;
+use crate::vec::Vec;
+
+use core::cell::Cell;
+use core::cmp::Ordering::{self, Equal, Greater, Less};
+use core::convert::identity;
+use core::fmt;
+use core::mem;
+use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
+use rand::{distributions::Standard, prelude::*, Rng, RngCore};
+use std::panic;
+
+macro_rules! do_test {
+ ($input:ident, $func:ident) => {
+ let len = $input.len();
+
+ // Work out the total number of comparisons required to sort
+ // this array...
+ let mut count = 0usize;
+ $input.to_owned().$func(|a, b| {
+ count += 1;
+ a.cmp(b)
+ });
+
+ // ... and then panic on each and every single one.
+ for panic_countdown in 0..count {
+ // Refresh the counters.
+ VERSIONS.store(0, Relaxed);
+ for i in 0..len {
+ DROP_COUNTS[i].store(0, Relaxed);
+ }
+
+ let v = $input.to_owned();
+ let _ = std::panic::catch_unwind(move || {
+ let mut v = v;
+ let mut panic_countdown = panic_countdown;
+ v.$func(|a, b| {
+ if panic_countdown == 0 {
+ SILENCE_PANIC.with(|s| s.set(true));
+ panic!();
+ }
+ panic_countdown -= 1;
+ a.cmp(b)
+ })
+ });
+
+ // Check that the number of things dropped is exactly
+ // what we expect (i.e., the contents of `v`).
+ for (i, c) in DROP_COUNTS.iter().enumerate().take(len) {
+ let count = c.load(Relaxed);
+ assert!(count == 1, "found drop count == {} for i == {}, len == {}", count, i, len);
+ }
+
+ // Check that the most recent versions of values were dropped.
+ assert_eq!(VERSIONS.load(Relaxed), 0);
+ }
+ };
+}
+
+const MAX_LEN: usize = 80;
+
+static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [
+ // FIXME(RFC 1109): AtomicUsize is not Copy.
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+];
+
+static VERSIONS: AtomicUsize = AtomicUsize::new(0);
+
+#[derive(Clone, Eq)]
+struct DropCounter {
+ x: u32,
+ id: usize,
+ version: Cell<usize>,
+}
+
+impl PartialEq for DropCounter {
+ fn eq(&self, other: &Self) -> bool {
+ self.partial_cmp(other) == Some(Ordering::Equal)
+ }
+}
+
+impl PartialOrd for DropCounter {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.version.set(self.version.get() + 1);
+ other.version.set(other.version.get() + 1);
+ VERSIONS.fetch_add(2, Relaxed);
+ self.x.partial_cmp(&other.x)
+ }
+}
+
+impl Ord for DropCounter {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.partial_cmp(other).unwrap()
+ }
+}
+
+impl Drop for DropCounter {
+ fn drop(&mut self) {
+ DROP_COUNTS[self.id].fetch_add(1, Relaxed);
+ VERSIONS.fetch_sub(self.version.get(), Relaxed);
+ }
+}
+
+std::thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)] // no threads
+fn panic_safe() {
+ panic::update_hook(move |prev, info| {
+ if !SILENCE_PANIC.with(|s| s.get()) {
+ prev(info);
+ }
+ });
+
+ let mut rng = test_rng();
+
+ // Miri is too slow (but still need to `chain` to make the types match)
+ let lens = if cfg!(miri) { (1..10).chain(0..0) } else { (1..20).chain(70..MAX_LEN) };
+ let moduli: &[u32] = if cfg!(miri) { &[5] } else { &[5, 20, 50] };
+
+ for len in lens {
+ for &modulus in moduli {
+ for &has_runs in &[false, true] {
+ let mut input = (0..len)
+ .map(|id| DropCounter {
+ x: rng.next_u32() % modulus,
+ id: id,
+ version: Cell::new(0),
+ })
+ .collect::<Vec<_>>();
+
+ if has_runs {
+ for c in &mut input {
+ c.x = c.id as u32;
+ }
+
+ for _ in 0..5 {
+ let a = rng.gen::<usize>() % len;
+ let b = rng.gen::<usize>() % len;
+ if a < b {
+ input[a..b].reverse();
+ } else {
+ input.swap(a, b);
+ }
+ }
+ }
+
+ do_test!(input, sort_by);
+ do_test!(input, sort_unstable_by);
+ }
+ }
+ }
+
+ // Set default panic hook again.
+ drop(panic::take_hook());
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri is too slow
+fn test_sort() {
+ let mut rng = test_rng();
+
+ for len in (2..25).chain(500..510) {
+ for &modulus in &[5, 10, 100, 1000] {
+ for _ in 0..10 {
+ let orig: Vec<_> = (&mut rng)
+ .sample_iter::<i32, _>(&Standard)
+ .map(|x| x % modulus)
+ .take(len)
+ .collect();
+
+ // Sort in default order.
+ let mut v = orig.clone();
+ v.sort();
+ assert!(v.windows(2).all(|w| w[0] <= w[1]));
+
+ // Sort in ascending order.
+ let mut v = orig.clone();
+ v.sort_by(|a, b| a.cmp(b));
+ assert!(v.windows(2).all(|w| w[0] <= w[1]));
+
+ // Sort in descending order.
+ let mut v = orig.clone();
+ v.sort_by(|a, b| b.cmp(a));
+ assert!(v.windows(2).all(|w| w[0] >= w[1]));
+
+ // Sort in lexicographic order.
+ let mut v1 = orig.clone();
+ let mut v2 = orig.clone();
+ v1.sort_by_key(|x| x.to_string());
+ v2.sort_by_cached_key(|x| x.to_string());
+ assert!(v1.windows(2).all(|w| w[0].to_string() <= w[1].to_string()));
+ assert!(v1 == v2);
+
+ // Sort with many pre-sorted runs.
+ let mut v = orig.clone();
+ v.sort();
+ v.reverse();
+ for _ in 0..5 {
+ let a = rng.gen::<usize>() % len;
+ let b = rng.gen::<usize>() % len;
+ if a < b {
+ v[a..b].reverse();
+ } else {
+ v.swap(a, b);
+ }
+ }
+ v.sort();
+ assert!(v.windows(2).all(|w| w[0] <= w[1]));
+ }
+ }
+ }
+
+ // Sort using a completely random comparison function.
+ // This will reorder the elements *somehow*, but won't panic.
+ let mut v = [0; 500];
+ for i in 0..v.len() {
+ v[i] = i as i32;
+ }
+ v.sort_by(|_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap());
+ v.sort();
+ for i in 0..v.len() {
+ assert_eq!(v[i], i as i32);
+ }
+
+ // Should not panic.
+ [0i32; 0].sort();
+ [(); 10].sort();
+ [(); 100].sort();
+
+ let mut v = [0xDEADBEEFu64];
+ v.sort();
+ assert!(v == [0xDEADBEEF]);
+}
+
+#[test]
+fn test_sort_stability() {
+ // Miri is too slow
+ let large_range = if cfg!(miri) { 0..0 } else { 500..510 };
+ let rounds = if cfg!(miri) { 1 } else { 10 };
+
+ let mut rng = test_rng();
+ for len in (2..25).chain(large_range) {
+ for _ in 0..rounds {
+ let mut counts = [0; 10];
+
+ // create a vector like [(6, 1), (5, 1), (6, 2), ...],
+ // where the first item of each tuple is random, but
+ // the second item represents which occurrence of that
+ // number this element is, i.e., the second elements
+ // will occur in sorted order.
+ let orig: Vec<_> = (0..len)
+ .map(|_| {
+ let n = rng.gen::<usize>() % 10;
+ counts[n] += 1;
+ (n, counts[n])
+ })
+ .collect();
+
+ let mut v = orig.clone();
+ // Only sort on the first element, so an unstable sort
+ // may mix up the counts.
+ v.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
+
+ // This comparison includes the count (the second item
+ // of the tuple), so elements with equal first items
+ // will need to be ordered with increasing
+ // counts... i.e., exactly asserting that this sort is
+ // stable.
+ assert!(v.windows(2).all(|w| w[0] <= w[1]));
+
+ let mut v = orig.clone();
+ v.sort_by_cached_key(|&(x, _)| x);
+ assert!(v.windows(2).all(|w| w[0] <= w[1]));
+ }
+ }
+}
/// [`as_str()`]: String::as_str
#[derive(PartialOrd, Eq, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(all(not(bootstrap), not(test)), lang = "String")]
+#[cfg_attr(not(test), lang = "String")]
pub struct String {
vec: Vec<u8>,
}
}
}
-// note: test pulls in libstd, which causes errors here
+// note: test pulls in std, which causes errors here
#[cfg(not(test))]
#[stable(feature = "string_from_box", since = "1.18.0")]
impl From<Box<str>> for String {
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {}
#[stable(feature = "arc_weak", since = "1.4.0")]
-impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
+impl<T: ?Sized> fmt::Debug for Weak<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(Weak)")
}
--- /dev/null
+// We avoid relying on anything else in the crate, apart from the `Debug` trait.
+use crate::fmt::Debug;
+use std::cmp::Ordering;
+use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+
+/// A blueprint for crash test dummy instances that monitor particular events.
+/// Some instances may be configured to panic at some point.
+/// Events are `clone`, `drop` or some anonymous `query`.
+///
+/// Crash test dummies are identified and ordered by an id, so they can be used
+/// as keys in a BTreeMap.
+#[derive(Debug)]
+pub struct CrashTestDummy {
+ pub id: usize,
+ cloned: AtomicUsize,
+ dropped: AtomicUsize,
+ queried: AtomicUsize,
+}
+
+impl CrashTestDummy {
+ /// Creates a crash test dummy design. The `id` determines order and equality of instances.
+ pub fn new(id: usize) -> CrashTestDummy {
+ CrashTestDummy {
+ id,
+ cloned: AtomicUsize::new(0),
+ dropped: AtomicUsize::new(0),
+ queried: AtomicUsize::new(0),
+ }
+ }
+
+ /// Creates an instance of a crash test dummy that records what events it experiences
+ /// and optionally panics.
+ pub fn spawn(&self, panic: Panic) -> Instance<'_> {
+ Instance { origin: self, panic }
+ }
+
+ /// Returns how many times instances of the dummy have been cloned.
+ pub fn cloned(&self) -> usize {
+ self.cloned.load(SeqCst)
+ }
+
+ /// Returns how many times instances of the dummy have been dropped.
+ pub fn dropped(&self) -> usize {
+ self.dropped.load(SeqCst)
+ }
+
+ /// Returns how many times instances of the dummy have had their `query` member invoked.
+ pub fn queried(&self) -> usize {
+ self.queried.load(SeqCst)
+ }
+}
+
+#[derive(Debug)]
+pub struct Instance<'a> {
+ origin: &'a CrashTestDummy,
+ panic: Panic,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum Panic {
+ Never,
+ InClone,
+ InDrop,
+ InQuery,
+}
+
+impl Instance<'_> {
+ pub fn id(&self) -> usize {
+ self.origin.id
+ }
+
+ /// Some anonymous query, the result of which is already given.
+ pub fn query<R>(&self, result: R) -> R {
+ self.origin.queried.fetch_add(1, SeqCst);
+ if self.panic == Panic::InQuery {
+ panic!("panic in `query`");
+ }
+ result
+ }
+}
+
+impl Clone for Instance<'_> {
+ fn clone(&self) -> Self {
+ self.origin.cloned.fetch_add(1, SeqCst);
+ if self.panic == Panic::InClone {
+ panic!("panic in `clone`");
+ }
+ Self { origin: self.origin, panic: Panic::Never }
+ }
+}
+
+impl Drop for Instance<'_> {
+ fn drop(&mut self) {
+ self.origin.dropped.fetch_add(1, SeqCst);
+ if self.panic == Panic::InDrop {
+ panic!("panic in `drop`");
+ }
+ }
+}
+
+impl PartialOrd for Instance<'_> {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.id().partial_cmp(&other.id())
+ }
+}
+
+impl Ord for Instance<'_> {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.id().cmp(&other.id())
+ }
+}
+
+impl PartialEq for Instance<'_> {
+ fn eq(&self, other: &Self) -> bool {
+ self.id().eq(&other.id())
+ }
+}
+
+impl Eq for Instance<'_> {}
--- /dev/null
+pub mod crash_test;
+pub mod ord_chaos;
+pub mod rng;
--- /dev/null
+use std::cell::Cell;
+use std::cmp::Ordering::{self, *};
+use std::ptr;
+
+// Minimal type with an `Ord` implementation violating transitivity.
+#[derive(Debug)]
+pub enum Cyclic3 {
+ A,
+ B,
+ C,
+}
+use Cyclic3::*;
+
+impl PartialOrd for Cyclic3 {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Cyclic3 {
+ fn cmp(&self, other: &Self) -> Ordering {
+ match (self, other) {
+ (A, A) | (B, B) | (C, C) => Equal,
+ (A, B) | (B, C) | (C, A) => Less,
+ (A, C) | (B, A) | (C, B) => Greater,
+ }
+ }
+}
+
+impl PartialEq for Cyclic3 {
+ fn eq(&self, other: &Self) -> bool {
+ self.cmp(&other) == Equal
+ }
+}
+
+impl Eq for Cyclic3 {}
+
+// Controls the ordering of values wrapped by `Governed`.
+#[derive(Debug)]
+pub struct Governor {
+ flipped: Cell<bool>,
+}
+
+impl Governor {
+ pub fn new() -> Self {
+ Governor { flipped: Cell::new(false) }
+ }
+
+ pub fn flip(&self) {
+ self.flipped.set(!self.flipped.get());
+ }
+}
+
+// Type with an `Ord` implementation that forms a total order at any moment
+// (assuming that `T` respects total order), but can suddenly be made to invert
+// that total order.
+#[derive(Debug)]
+pub struct Governed<'a, T>(pub T, pub &'a Governor);
+
+impl<T: Ord> PartialOrd for Governed<'_, T> {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl<T: Ord> Ord for Governed<'_, T> {
+ fn cmp(&self, other: &Self) -> Ordering {
+ assert!(ptr::eq(self.1, other.1));
+ let ord = self.0.cmp(&other.0);
+ if self.1.flipped.get() { ord.reverse() } else { ord }
+ }
+}
+
+impl<T: PartialEq> PartialEq for Governed<'_, T> {
+ fn eq(&self, other: &Self) -> bool {
+ assert!(ptr::eq(self.1, other.1));
+ self.0.eq(&other.0)
+ }
+}
+
+impl<T: Eq> Eq for Governed<'_, T> {}
--- /dev/null
+/// XorShiftRng
+pub struct DeterministicRng {
+ count: usize,
+ x: u32,
+ y: u32,
+ z: u32,
+ w: u32,
+}
+
+impl DeterministicRng {
+ pub fn new() -> Self {
+ DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
+ }
+
+ /// Guarantees that each returned number is unique.
+ pub fn next(&mut self) -> u32 {
+ self.count += 1;
+ assert!(self.count <= 70029);
+ let x = self.x;
+ let t = x ^ (x << 11);
+ self.x = self.y;
+ self.y = self.z;
+ self.z = self.w;
+ let w_ = self.w;
+ self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
+ self.w
+ }
+}
/// vec[0] = 7;
/// assert_eq!(vec[0], 7);
///
-/// vec.extend([1, 2, 3].iter().copied());
+/// vec.extend([1, 2, 3]);
///
/// for x in &vec {
/// println!("{x}");
/// This is highly unsafe, due to the number of invariants that aren't
/// checked:
///
+ /// * `ptr` must have been allocated using the global allocator, such as via
+ /// the [`alloc::alloc`] function.
/// * `T` needs to have the same alignment as what `ptr` was allocated with.
/// (`T` having a less strict alignment is not sufficient, the alignment really
/// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
/// function.
///
/// [`String`]: crate::string::String
+ /// [`alloc::alloc`]: crate::alloc::alloc
/// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
///
/// # Examples
/// This is highly unsafe, due to the number of invariants that aren't
/// checked:
///
+ /// * `ptr` must be [*currently allocated*] via the given allocator `alloc`.
/// * `T` needs to have the same alignment as what `ptr` was allocated with.
/// (`T` having a less strict alignment is not sufficient, the alignment really
/// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
///
/// [`String`]: crate::string::String
/// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
+ /// [*currently allocated*]: crate::alloc::Allocator#currently-allocated-memory
/// [*fit*]: crate::alloc::Allocator#memory-fitting
///
/// # Examples
}
}
-// note: test pulls in libstd, which causes errors here
+// note: test pulls in std, which causes errors here
#[cfg(not(test))]
#[stable(feature = "vec_from_box", since = "1.18.0")]
impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
}
}
-// note: test pulls in libstd, which causes errors here
+// note: test pulls in std, which causes errors here
#[cfg(not(no_global_oom_handling))]
#[cfg(not(test))]
#[stable(feature = "box_from_vec", since = "1.20.0")]
// spawn(f());
// }
//
- // where with some unintentionally overconstrained Send impls in liballoc's
+ // where with some unintentionally overconstrained Send impls in alloc's
// internals, the future might incorrectly not be Send even though every
// single type involved in the program is Send and Sync.
require_send_sync(async {
-use std::cell::Cell;
-use std::cmp::Ordering::{self, Equal, Greater, Less};
+use std::cmp::Ordering::{Equal, Greater, Less};
use std::convert::identity;
use std::fmt;
use std::mem;
use std::panic;
use std::rc::Rc;
-use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
-
-use rand::distributions::Standard;
-use rand::seq::SliceRandom;
-use rand::{thread_rng, Rng, RngCore};
fn square(n: usize) -> usize {
n * n
assert_eq!(v, (-50..51i16).rev().collect::<Vec<_>>());
}
-#[test]
-#[cfg_attr(miri, ignore)] // Miri is too slow
-fn test_sort() {
- let mut rng = thread_rng();
-
- for len in (2..25).chain(500..510) {
- for &modulus in &[5, 10, 100, 1000] {
- for _ in 0..10 {
- let orig: Vec<_> =
- rng.sample_iter::<i32, _>(&Standard).map(|x| x % modulus).take(len).collect();
-
- // Sort in default order.
- let mut v = orig.clone();
- v.sort();
- assert!(v.windows(2).all(|w| w[0] <= w[1]));
-
- // Sort in ascending order.
- let mut v = orig.clone();
- v.sort_by(|a, b| a.cmp(b));
- assert!(v.windows(2).all(|w| w[0] <= w[1]));
-
- // Sort in descending order.
- let mut v = orig.clone();
- v.sort_by(|a, b| b.cmp(a));
- assert!(v.windows(2).all(|w| w[0] >= w[1]));
-
- // Sort in lexicographic order.
- let mut v1 = orig.clone();
- let mut v2 = orig.clone();
- v1.sort_by_key(|x| x.to_string());
- v2.sort_by_cached_key(|x| x.to_string());
- assert!(v1.windows(2).all(|w| w[0].to_string() <= w[1].to_string()));
- assert!(v1 == v2);
-
- // Sort with many pre-sorted runs.
- let mut v = orig.clone();
- v.sort();
- v.reverse();
- for _ in 0..5 {
- let a = rng.gen::<usize>() % len;
- let b = rng.gen::<usize>() % len;
- if a < b {
- v[a..b].reverse();
- } else {
- v.swap(a, b);
- }
- }
- v.sort();
- assert!(v.windows(2).all(|w| w[0] <= w[1]));
- }
- }
- }
-
- // Sort using a completely random comparison function.
- // This will reorder the elements *somehow*, but won't panic.
- let mut v = [0; 500];
- for i in 0..v.len() {
- v[i] = i as i32;
- }
- v.sort_by(|_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap());
- v.sort();
- for i in 0..v.len() {
- assert_eq!(v[i], i as i32);
- }
-
- // Should not panic.
- [0i32; 0].sort();
- [(); 10].sort();
- [(); 100].sort();
-
- let mut v = [0xDEADBEEFu64];
- v.sort();
- assert!(v == [0xDEADBEEF]);
-}
-
-#[test]
-fn test_sort_stability() {
- // Miri is too slow
- let large_range = if cfg!(miri) { 0..0 } else { 500..510 };
- let rounds = if cfg!(miri) { 1 } else { 10 };
-
- for len in (2..25).chain(large_range) {
- for _ in 0..rounds {
- let mut counts = [0; 10];
-
- // create a vector like [(6, 1), (5, 1), (6, 2), ...],
- // where the first item of each tuple is random, but
- // the second item represents which occurrence of that
- // number this element is, i.e., the second elements
- // will occur in sorted order.
- let orig: Vec<_> = (0..len)
- .map(|_| {
- let n = thread_rng().gen::<usize>() % 10;
- counts[n] += 1;
- (n, counts[n])
- })
- .collect();
-
- let mut v = orig.clone();
- // Only sort on the first element, so an unstable sort
- // may mix up the counts.
- v.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
-
- // This comparison includes the count (the second item
- // of the tuple), so elements with equal first items
- // will need to be ordered with increasing
- // counts... i.e., exactly asserting that this sort is
- // stable.
- assert!(v.windows(2).all(|w| w[0] <= w[1]));
-
- let mut v = orig.clone();
- v.sort_by_cached_key(|&(x, _)| x);
- assert!(v.windows(2).all(|w| w[0] <= w[1]));
- }
- }
-}
-
#[test]
fn test_rotate_left() {
let expected: Vec<_> = (0..13).collect();
dst.copy_from_slice(&src);
}
-const MAX_LEN: usize = 80;
-
-static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [
- // FIXME(RFC 1109): AtomicUsize is not Copy.
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
- AtomicUsize::new(0),
-];
-
-static VERSIONS: AtomicUsize = AtomicUsize::new(0);
-
-#[derive(Clone, Eq)]
-struct DropCounter {
- x: u32,
- id: usize,
- version: Cell<usize>,
-}
-
-impl PartialEq for DropCounter {
- fn eq(&self, other: &Self) -> bool {
- self.partial_cmp(other) == Some(Ordering::Equal)
- }
-}
-
-impl PartialOrd for DropCounter {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- self.version.set(self.version.get() + 1);
- other.version.set(other.version.get() + 1);
- VERSIONS.fetch_add(2, Relaxed);
- self.x.partial_cmp(&other.x)
- }
-}
-
-impl Ord for DropCounter {
- fn cmp(&self, other: &Self) -> Ordering {
- self.partial_cmp(other).unwrap()
- }
-}
-
-impl Drop for DropCounter {
- fn drop(&mut self) {
- DROP_COUNTS[self.id].fetch_add(1, Relaxed);
- VERSIONS.fetch_sub(self.version.get(), Relaxed);
- }
-}
-
-macro_rules! test {
- ($input:ident, $func:ident) => {
- let len = $input.len();
-
- // Work out the total number of comparisons required to sort
- // this array...
- let mut count = 0usize;
- $input.to_owned().$func(|a, b| {
- count += 1;
- a.cmp(b)
- });
-
- // ... and then panic on each and every single one.
- for panic_countdown in 0..count {
- // Refresh the counters.
- VERSIONS.store(0, Relaxed);
- for i in 0..len {
- DROP_COUNTS[i].store(0, Relaxed);
- }
-
- let v = $input.to_owned();
- let _ = std::panic::catch_unwind(move || {
- let mut v = v;
- let mut panic_countdown = panic_countdown;
- v.$func(|a, b| {
- if panic_countdown == 0 {
- SILENCE_PANIC.with(|s| s.set(true));
- panic!();
- }
- panic_countdown -= 1;
- a.cmp(b)
- })
- });
-
- // Check that the number of things dropped is exactly
- // what we expect (i.e., the contents of `v`).
- for (i, c) in DROP_COUNTS.iter().enumerate().take(len) {
- let count = c.load(Relaxed);
- assert!(count == 1, "found drop count == {} for i == {}, len == {}", count, i, len);
- }
-
- // Check that the most recent versions of values were dropped.
- assert_eq!(VERSIONS.load(Relaxed), 0);
- }
- };
-}
-
-thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
-
-#[test]
-#[cfg_attr(target_os = "emscripten", ignore)] // no threads
-fn panic_safe() {
- panic::update_hook(move |prev, info| {
- if !SILENCE_PANIC.with(|s| s.get()) {
- prev(info);
- }
- });
-
- let mut rng = thread_rng();
-
- // Miri is too slow (but still need to `chain` to make the types match)
- let lens = if cfg!(miri) { (1..10).chain(0..0) } else { (1..20).chain(70..MAX_LEN) };
- let moduli: &[u32] = if cfg!(miri) { &[5] } else { &[5, 20, 50] };
-
- for len in lens {
- for &modulus in moduli {
- for &has_runs in &[false, true] {
- let mut input = (0..len)
- .map(|id| DropCounter {
- x: rng.next_u32() % modulus,
- id: id,
- version: Cell::new(0),
- })
- .collect::<Vec<_>>();
-
- if has_runs {
- for c in &mut input {
- c.x = c.id as u32;
- }
-
- for _ in 0..5 {
- let a = rng.gen::<usize>() % len;
- let b = rng.gen::<usize>() % len;
- if a < b {
- input[a..b].reverse();
- } else {
- input.swap(a, b);
- }
- }
- }
-
- test!(input, sort_by);
- test!(input, sort_unstable_by);
- }
- }
- }
-
- // Set default panic hook again.
- drop(panic::take_hook());
-}
-
#[test]
fn repeat_generic_slice() {
assert_eq!([1, 2].repeat(2), vec![1, 2, 1, 2]);
test = true
[dev-dependencies]
-rand = "0.7"
-rand_xorshift = "0.2"
+rand = { version = "0.8.5", default-features = false }
+rand_xorshift = { version = "0.3.0", default-features = false }
[features]
# Make panics and failed asserts immediately abort without formatting any message
/* Exponentially distributed random numbers from the whole range of the type. */
let numbers: Vec<$t> = (0..256)
.map(|_| {
- let x = rng.gen::<$t>() >> rng.gen_range(0, <$t>::BITS);
+ let x = rng.gen::<$t>() >> rng.gen_range(0..<$t>::BITS);
if x != 0 { x } else { 1 }
})
.collect();
/* Exponentially distributed random numbers from the range 0..256. */
let numbers: Vec<$t> = (0..256)
.map(|_| {
- let x = (rng.gen::<u8>() >> rng.gen_range(0, u8::BITS)) as $t;
+ let x = (rng.gen::<u8>() >> rng.gen_range(0..u8::BITS)) as $t;
if x != 0 { x } else { 1 }
})
.collect();
//! ```
//!
//! In this example, if the concrete type of `obj` in `use_my_trait` is `SomeConcreteType`, then
-//! the `get_context_ref` call will return a reference to `obj.some_string` with type `&String`.
+//! the `get_context_by_ref` call will return a reference to `obj.some_string` with type `&String`.
#![stable(feature = "rust1", since = "1.0.0")]
///
/// # Panics
///
- /// Panics if the value in either `RefCell` is currently borrowed.
+ /// Panics if the value in either `RefCell` is currently borrowed, or
+ /// if `self` and `other` point to the same `RefCell`.
///
/// # Examples
///
impl<T: ?Sized + PartialEq> PartialEq for RefCell<T> {
/// # Panics
///
- /// Panics if the value in either `RefCell` is currently borrowed.
+ /// Panics if the value in either `RefCell` is currently mutably borrowed.
#[inline]
fn eq(&self, other: &RefCell<T>) -> bool {
*self.borrow() == *other.borrow()
impl<T: ?Sized + PartialOrd> PartialOrd for RefCell<T> {
/// # Panics
///
- /// Panics if the value in either `RefCell` is currently borrowed.
+ /// Panics if the value in either `RefCell` is currently mutably borrowed.
#[inline]
fn partial_cmp(&self, other: &RefCell<T>) -> Option<Ordering> {
self.borrow().partial_cmp(&*other.borrow())
/// # Panics
///
- /// Panics if the value in either `RefCell` is currently borrowed.
+ /// Panics if the value in either `RefCell` is currently mutably borrowed.
#[inline]
fn lt(&self, other: &RefCell<T>) -> bool {
*self.borrow() < *other.borrow()
/// # Panics
///
- /// Panics if the value in either `RefCell` is currently borrowed.
+ /// Panics if the value in either `RefCell` is currently mutably borrowed.
#[inline]
fn le(&self, other: &RefCell<T>) -> bool {
*self.borrow() <= *other.borrow()
/// # Panics
///
- /// Panics if the value in either `RefCell` is currently borrowed.
+ /// Panics if the value in either `RefCell` is currently mutably borrowed.
#[inline]
fn gt(&self, other: &RefCell<T>) -> bool {
*self.borrow() > *other.borrow()
/// # Panics
///
- /// Panics if the value in either `RefCell` is currently borrowed.
+ /// Panics if the value in either `RefCell` is currently mutably borrowed.
#[inline]
fn ge(&self, other: &RefCell<T>) -> bool {
*self.borrow() >= *other.borrow()
impl<T: ?Sized + Ord> Ord for RefCell<T> {
/// # Panics
///
- /// Panics if the value in either `RefCell` is currently borrowed.
+ /// Panics if the value in either `RefCell` is currently mutably borrowed.
#[inline]
fn cmp(&self, other: &RefCell<T>) -> Ordering {
self.borrow().cmp(&*other.borrow())
/// until the reference expires. As a special exception, given an `&T`, any part of it that is
/// inside an `UnsafeCell<_>` may be deallocated during the lifetime of the reference, after the
/// last time the reference is used (dereferenced or reborrowed). Since you cannot deallocate a part
-/// of what a reference points to, this means the memory an `&T` points to can be deallocted only if
+/// of what a reference points to, this means the memory an `&T` points to can be deallocated only if
/// *every part of it* (including padding) is inside an `UnsafeCell`.
///
/// However, whenever a `&UnsafeCell<T>` is constructed or dereferenced, it must still point to
#[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")]
pub const fn get(&self) -> *mut T {
// We can just cast the pointer from `UnsafeCell<T>` to `T` because of
- // #[repr(transparent)]. This exploits libstd's special status, there is
+ // #[repr(transparent)]. This exploits std's special status, there is
// no guarantee for user code that this will work in future versions of the compiler!
self as *const UnsafeCell<T> as *const T as *mut T
}
#[rustc_const_stable(feature = "unsafe_cell_raw_get", since = "1.56.0")]
pub const fn raw_get(this: *const Self) -> *mut T {
// We can just cast the pointer from `UnsafeCell<T>` to `T` because of
- // #[repr(transparent)]. This exploits libstd's special status, there is
+ // #[repr(transparent)]. This exploits std's special status, there is
// no guarantee for user code that this will work in future versions of the compiler!
this as *const T as *mut T
}
init: Cell<Option<F>>,
}
-impl<T, F> LazyCell<T, F> {
+impl<T, F: FnOnce() -> T> LazyCell<T, F> {
/// Creates a new lazy value with the given initializing function.
///
/// # Examples
///
/// assert_eq!(&*lazy, "HELLO, WORLD!");
/// ```
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub const fn new(init: F) -> LazyCell<T, F> {
LazyCell { cell: OnceCell::new(), init: Cell::new(Some(init)) }
}
-}
-impl<T, F: FnOnce() -> T> LazyCell<T, F> {
/// Forces the evaluation of this lazy value and returns a reference to
/// the result.
///
/// assert_eq!(LazyCell::force(&lazy), &92);
/// assert_eq!(&*lazy, &92);
/// ```
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn force(this: &LazyCell<T, F>) -> &T {
this.cell.get_or_init(|| match this.init.take() {
#[unstable(feature = "once_cell", issue = "74465")]
impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> {
type Target = T;
+ #[inline]
fn deref(&self) -> &T {
LazyCell::force(self)
}
#[unstable(feature = "once_cell", issue = "74465")]
impl<T: Default> Default for LazyCell<T> {
/// Creates a new lazy value using `Default` as the initializing function.
+ #[inline]
fn default() -> LazyCell<T> {
LazyCell::new(T::default)
}
impl<T> OnceCell<T> {
/// Creates a new empty cell.
- #[unstable(feature = "once_cell", issue = "74465")]
+ #[inline]
#[must_use]
+ #[unstable(feature = "once_cell", issue = "74465")]
pub const fn new() -> OnceCell<T> {
OnceCell { inner: UnsafeCell::new(None) }
}
/// Gets the reference to the underlying value.
///
/// Returns `None` if the cell is empty.
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn get(&self) -> Option<&T> {
// SAFETY: Safe due to `inner`'s invariant
/// Gets the mutable reference to the underlying value.
///
/// Returns `None` if the cell is empty.
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn get_mut(&mut self) -> Option<&mut T> {
self.inner.get_mut().as_mut()
///
/// assert!(cell.get().is_some());
/// ```
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn set(&self, value: T) -> Result<(), T> {
// SAFETY: Safe because we cannot have overlapping mutable borrows
/// let value = cell.get_or_init(|| unreachable!());
/// assert_eq!(value, &92);
/// ```
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn get_or_init<F>(&self, f: F) -> &T
where
/// cell.set("hello".to_string()).unwrap();
/// assert_eq!(cell.into_inner(), Some("hello".to_string()));
/// ```
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn into_inner(self) -> Option<T> {
// Because `into_inner` takes `self` by value, the compiler statically verifies
/// assert_eq!(cell.take(), Some("hello".to_string()));
/// assert_eq!(cell.get(), None);
/// ```
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn take(&mut self) -> Option<T> {
mem::take(self).into_inner()
#[unstable(feature = "once_cell", issue = "74465")]
impl<T> Default for OnceCell<T> {
+ #[inline]
fn default() -> Self {
Self::new()
}
#[unstable(feature = "once_cell", issue = "74465")]
impl<T: Clone> Clone for OnceCell<T> {
+ #[inline]
fn clone(&self) -> OnceCell<T> {
let res = OnceCell::new();
if let Some(value) = self.get() {
#[unstable(feature = "once_cell", issue = "74465")]
impl<T: PartialEq> PartialEq for OnceCell<T> {
+ #[inline]
fn eq(&self, other: &Self) -> bool {
self.get() == other.get()
}
#[unstable(feature = "once_cell", issue = "74465")]
impl<T> const From<T> for OnceCell<T> {
/// Creates a new `OnceCell<T>` which already contains the given `value`.
+ #[inline]
fn from(value: T) -> Self {
OnceCell { inner: UnsafeCell::new(Some(value)) }
}
/// assert_eq!(None, c);
/// ```
#[stable(feature = "assoc_char_funcs", since = "1.52.0")]
- #[rustc_const_stable(feature = "const_char_convert", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
#[must_use]
#[inline]
pub const fn from_u32(i: u32) -> Option<char> {
/// let _c = char::from_digit(1, 37);
/// ```
#[stable(feature = "assoc_char_funcs", since = "1.52.0")]
- #[rustc_const_stable(feature = "const_char_convert", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
#[must_use]
#[inline]
pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
/// let _ = '1'.to_digit(37);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_char_convert", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// Converts a `u32` to a `char`. Use [`char::from_u32`] instead.
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(feature = "const_char_convert", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
#[must_use]
#[inline]
pub const fn from_u32(i: u32) -> Option<char> {
/// Converts a digit in the given radix to a `char`. Use [`char::from_digit`] instead.
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(feature = "const_char_convert", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
#[must_use]
#[inline]
pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
use crate::const_closure::ConstFnMutClosure;
use crate::marker::Destruct;
-#[cfg(bootstrap)]
-use crate::marker::StructuralPartialEq;
use self::Ordering::*;
/// assert_eq!(Ordering::Greater, result);
/// ```
#[derive(Clone, Copy, Eq, Debug, Hash)]
-#[cfg_attr(not(bootstrap), derive_const(PartialOrd, Ord, PartialEq))]
+#[derive_const(PartialOrd, Ord, PartialEq)]
#[stable(feature = "rust1", since = "1.0.0")]
#[repr(i8)]
pub enum Ordering {
Self: Sized,
Self: ~const Destruct,
{
- // HACK(fee1-dead): go back to using `self.max_by(other, Ord::cmp)`
- // when trait methods are allowed to be used when a const closure is
- // expected.
+ #[cfg(not(bootstrap))]
+ {
+ max_by(self, other, Ord::cmp)
+ }
+
+ #[cfg(bootstrap)]
match self.cmp(&other) {
Ordering::Less | Ordering::Equal => other,
Ordering::Greater => self,
Self: Sized,
Self: ~const Destruct,
{
- // HACK(fee1-dead): go back to using `self.min_by(other, Ord::cmp)`
- // when trait methods are allowed to be used when a const closure is
- // expected.
+ #[cfg(not(bootstrap))]
+ {
+ min_by(self, other, Ord::cmp)
+ }
+
+ #[cfg(bootstrap)]
match self.cmp(&other) {
Ordering::Less | Ordering::Equal => self,
Ordering::Greater => other,
/* compiler built-in */
}
-#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg(bootstrap)]
-impl StructuralPartialEq for Ordering {}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
-#[cfg(bootstrap)]
-impl const PartialEq for Ordering {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- (*self as i32).eq(&(*other as i32))
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
-#[cfg(bootstrap)]
-impl const Ord for Ordering {
- #[inline]
- fn cmp(&self, other: &Ordering) -> Ordering {
- (*self as i32).cmp(&(*other as i32))
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
-#[cfg(bootstrap)]
-impl const PartialOrd for Ordering {
- #[inline]
- fn partial_cmp(&self, other: &Ordering) -> Option<Ordering> {
- (*self as i32).partial_cmp(&(*other as i32))
- }
-}
-
/// Trait for types that form a [partial order](https://en.wikipedia.org/wiki/Partial_order).
///
/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using
use crate::marker::Destruct;
-#[cfg(not(bootstrap))]
use crate::marker::Tuple;
/// Struct representing a closure with mutably borrowed data.
macro_rules! impl_fn_mut_tuple {
($($var:ident)*) => {
- #[cfg(bootstrap)]
- #[allow(unused_parens)]
- impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
- FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
- where
- Function: ~const Fn(($(&mut $var),*), ClosureArguments) -> ClosureReturnValue + ~const Destruct,
- {
- type Output = ClosureReturnValue;
-
- extern "rust-call" fn call_once(mut self, args: ClosureArguments) -> Self::Output {
- self.call_mut(args)
- }
- }
- #[cfg(bootstrap)]
- #[allow(unused_parens)]
- impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
- FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
- where
- Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue + ~const Destruct,
- {
- extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output {
- #[allow(non_snake_case)]
- let ($($var),*) = &mut self.data;
- (self.func)(($($var),*), args)
- }
- }
- #[cfg(not(bootstrap))]
#[allow(unused_parens)]
impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
self.call_mut(args)
}
}
- #[cfg(not(bootstrap))]
#[allow(unused_parens)]
impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
///
/// Derived `Debug` formats are not stable, and so may change with future Rust
/// versions. Additionally, `Debug` implementations of types provided by the
-/// standard library (`libstd`, `libcore`, `liballoc`, etc.) are not stable, and
+/// standard library (`std`, `core`, `alloc`, etc.) are not stable, and
/// may also change with future Rust versions.
///
/// # Examples
pub trait Future {
/// The type of value produced on completion.
#[stable(feature = "futures_api", since = "1.36.0")]
+ #[rustc_diagnostic_item = "FutureOutput"]
type Output;
/// Attempt to resolve the future to a final value, registering
/// non-Send/Sync as well, and we don't want that.
///
/// It also simplifies the HIR lowering of `.await`.
-#[cfg_attr(not(bootstrap), lang = "ResumeTy")]
+#[lang = "ResumeTy"]
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
#[derive(Debug, Copy, Clone)]
/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
// This is `const` to avoid extra errors after we recover from `const async fn`
-#[cfg_attr(bootstrap, lang = "from_generator")]
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
#[rustc_const_unstable(feature = "gen_future", issue = "50547")]
unsafe { &mut *cx.0.as_ptr().cast() }
}
-#[cfg_attr(not(bootstrap), lang = "identity_future")]
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
#[inline]
+#[lang = "identity_future"]
pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
f
}
#![allow(missing_docs)]
use crate::marker::DiscriminantKind;
-#[cfg(not(bootstrap))]
use crate::marker::Tuple;
use crate::mem;
/// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
/// which violates the principle that a `const fn` must behave the same at
/// compile-time and at run-time. The unsafe code in crate B is fine.
- #[cfg(bootstrap)]
- #[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
- pub fn const_eval_select<ARG, F, G, RET>(arg: ARG, called_in_const: F, called_at_rt: G) -> RET
- where
- G: FnOnce<ARG, Output = RET>,
- F: FnOnce<ARG, Output = RET>;
-
- /// Selects which function to call depending on the context.
- ///
- /// If this function is evaluated at compile-time, then a call to this
- /// intrinsic will be replaced with a call to `called_in_const`. It gets
- /// replaced with a call to `called_at_rt` otherwise.
- ///
- /// # Type Requirements
- ///
- /// The two functions must be both function items. They cannot be function
- /// pointers or closures. The first function must be a `const fn`.
- ///
- /// `arg` will be the tupled arguments that will be passed to either one of
- /// the two functions, therefore, both functions must accept the same type of
- /// arguments. Both functions must return RET.
- ///
- /// # Safety
- ///
- /// The two functions must behave observably equivalent. Safe code in other
- /// crates may assume that calling a `const fn` at compile-time and at run-time
- /// produces the same result. A function that produces a different result when
- /// evaluated at run-time, or has any other observable side-effects, is
- /// *unsound*.
- ///
- /// Here is an example of how this could cause a problem:
- /// ```no_run
- /// #![feature(const_eval_select)]
- /// #![feature(core_intrinsics)]
- /// use std::hint::unreachable_unchecked;
- /// use std::intrinsics::const_eval_select;
- ///
- /// // Crate A
- /// pub const fn inconsistent() -> i32 {
- /// fn runtime() -> i32 { 1 }
- /// const fn compiletime() -> i32 { 2 }
- ///
- /// unsafe {
- // // ⚠ This code violates the required equivalence of `compiletime`
- /// // and `runtime`.
- /// const_eval_select((), compiletime, runtime)
- /// }
- /// }
- ///
- /// // Crate B
- /// const X: i32 = inconsistent();
- /// let x = inconsistent();
- /// if x != X { unsafe { unreachable_unchecked(); }}
- /// ```
- ///
- /// This code causes Undefined Behavior when being run, since the
- /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
- /// which violates the principle that a `const fn` must behave the same at
- /// compile-time and at run-time. The unsafe code in crate B is fine.
- #[cfg(not(bootstrap))]
#[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
pub fn const_eval_select<ARG: Tuple, F, G, RET>(
arg: ARG,
//!
//! # Examples
//!
-//! ```rust
+#![cfg_attr(bootstrap, doc = "```rust,compile_fail")]
+#![cfg_attr(not(bootstrap), doc = "```rust")]
//! #![feature(core_intrinsics, custom_mir)]
//!
//! extern crate core;
///
/// # Examples
///
- /// ```rust
+ #[cfg_attr(bootstrap, doc = "```rust,compile_fail")]
+ #[cfg_attr(not(bootstrap), doc = "```rust")]
/// #![feature(custom_mir, core_intrinsics)]
///
/// extern crate core;
Empty(marker::PhantomData)
}
-// Newtype for use in `PhantomData` to avoid
-// > error: const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
-// in `const fn empty<T>()` above.
-struct FnReturning<T>(fn() -> T);
-
/// An iterator that yields nothing.
///
/// This `struct` is created by the [`empty()`] function. See its documentation for more.
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "iter_empty", since = "1.2.0")]
-pub struct Empty<T>(marker::PhantomData<FnReturning<T>>);
+pub struct Empty<T>(marker::PhantomData<fn() -> T>);
#[stable(feature = "core_impl_debug", since = "1.9.0")]
impl<T> fmt::Debug for Empty<T> {
+use crate::fmt;
use crate::iter::{FusedIterator, TrustedLen};
/// Creates an iterator that lazily generates a value exactly once by invoking
///
/// This `struct` is created by the [`once_with()`] function.
/// See its documentation for more.
-#[derive(Clone, Debug)]
+#[derive(Clone)]
#[stable(feature = "iter_once_with", since = "1.43.0")]
pub struct OnceWith<F> {
gen: Option<F>,
}
+#[stable(feature = "iter_once_with_debug", since = "CURRENT_RUSTC_VERSION")]
+impl<F> fmt::Debug for OnceWith<F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if self.gen.is_some() {
+ f.write_str("OnceWith(Some(_))")
+ } else {
+ f.write_str("OnceWith(None)")
+ }
+ }
+}
+
#[stable(feature = "iter_once_with", since = "1.43.0")]
impl<A, F: FnOnce() -> A> Iterator for OnceWith<F> {
type Item = A;
// zero so it won't be dropped later, and thus it's okay to take it here.
unsafe { ManuallyDrop::take(&mut self.element) }
} else {
- A::clone(&mut self.element)
+ A::clone(&self.element)
})
}
+use crate::fmt;
use crate::iter::{FusedIterator, TrustedLen};
use crate::ops::Try;
///
/// This `struct` is created by the [`repeat_with()`] function.
/// See its documentation for more.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone)]
#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
pub struct RepeatWith<F> {
repeater: F,
}
+#[stable(feature = "iterator_repeat_with_debug", since = "CURRENT_RUSTC_VERSION")]
+impl<F> fmt::Debug for RepeatWith<F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("RepeatWith").finish_non_exhaustive()
+ }
+}
+
#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
impl<A, F: FnMut() -> A> Iterator for RepeatWith<F> {
type Item = A;
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub trait Iterator {
/// The type of the elements being iterated over.
+ #[rustc_diagnostic_item = "IteratorItem"]
#[stable(feature = "rust1", since = "1.0.0")]
type Item;
/// (0..5).map(|x| x * 2 + 1)
/// .for_each(move |x| tx.send(x).unwrap());
///
- /// let v: Vec<_> = rx.iter().collect();
+ /// let v: Vec<_> = rx.iter().collect();
/// assert_eq!(v, vec![1, 3, 5, 7, 9]);
/// ```
///
Take::new(self, n)
}
- /// An iterator adapter similar to [`fold`] that holds internal state and
- /// produces a new iterator.
+ /// An iterator adapter which, like [`fold`], holds internal state, but
+ /// unlike [`fold`], produces a new iterator.
///
/// [`fold`]: Iterator::fold
///
///
/// On iteration, the closure will be applied to each element of the
/// iterator and the return value from the closure, an [`Option`], is
- /// yielded by the iterator.
+ /// returned by the `next` method. Thus the closure can return
+ /// `Some(value)` to yield `value`, or `None` to end the iteration.
///
/// # Examples
///
/// Basic usage:
///
/// ```
- /// let a = [1, 2, 3];
+ /// let a = [1, 2, 3, 4];
///
/// let mut iter = a.iter().scan(1, |state, &x| {
- /// // each iteration, we'll multiply the state by the element
+ /// // each iteration, we'll multiply the state by the element ...
/// *state = *state * x;
///
- /// // then, we'll yield the negation of the state
+ /// // ... and terminate if the state exceeds 6
+ /// if *state > 6 {
+ /// return None;
+ /// }
+ /// // ... else yield the negation of the state
/// Some(-*state)
/// });
///
/// assert_eq!(merged, "alphabetagamma");
/// ```
///
+ /// Flattening works on any `IntoIterator` type, including `Option` and `Result`:
+ ///
+ /// ```
+ /// let options = vec![Some(123), Some(321), None, Some(231)];
+ /// let flattened_options: Vec<_> = options.into_iter().flatten().collect();
+ /// assert_eq!(flattened_options, vec![123, 321, 231]);
+ ///
+ /// let results = vec![Ok(123), Ok(321), Err(456), Ok(231)];
+ /// let flattened_results: Vec<_> = results.into_iter().flatten().collect();
+ /// assert_eq!(flattened_results, vec![123, 321, 231]);
+ /// ```
+ ///
/// Flattening only removes one level of nesting at a time:
///
/// ```
/// argument is a double reference. You can see this effect in the
/// examples below, with `&&x`.
///
+ /// If you need the index of the element, see [`position()`].
+ ///
/// [`Some(element)`]: Some
+ /// [`position()`]: Iterator::position
///
/// # Examples
///
//! which do not trigger a panic can be assured that this function is never
//! called. The `lang` attribute is called `eh_personality`.
-// Since libcore defines many fundamental lang items, all tests live in a
-// separate crate, libcoretest, to avoid bizarre issues.
+// Since core defines many fundamental lang items, all tests live in a
+// separate crate, libcoretest (library/core/tests), to avoid bizarre issues.
//
// Here we explicitly #[cfg]-out this whole crate when testing. If we don't do
// this, both the generated test artifact and the linked libtest (which
-// transitively includes libcore) will both define the same set of lang items,
+// transitively includes core) will both define the same set of lang items,
// and this will cause the E0152 "found duplicate lang item" error. See
// discussion in #50466 for details.
//
// This cfg won't affect doc tests.
#![cfg(not(test))]
-// To run libcore tests without x.py without ending up with two copies of libcore, Miri needs to be
+// To run core tests without x.py without ending up with two copies of core, Miri needs to be
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
// rustc itself never sets the feature, so this line has no affect there.
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
#![feature(const_unsafecell_get_mut)]
#![feature(const_waker)]
#![feature(core_panic)]
+#![feature(char_indices_offset)]
#![feature(duration_consts_float)]
#![feature(maybe_uninit_uninit_array)]
#![feature(ptr_alignment_type)]
#![feature(slice_ptr_get)]
#![feature(slice_split_at_unchecked)]
#![feature(str_internals)]
+#![feature(str_split_remainder)]
+#![feature(str_split_inclusive_remainder)]
#![feature(strict_provenance)]
#![feature(utf16_extra)]
#![feature(utf16_extra_const)]
#![feature(const_refs_to_cell)]
#![feature(decl_macro)]
#![feature(deprecated_suggestion)]
-#![cfg_attr(not(bootstrap), feature(derive_const))]
+#![feature(derive_const)]
#![feature(doc_cfg)]
#![feature(doc_notable_trait)]
#![feature(rustdoc_internals)]
#[macro_use]
pub mod num;
-/* The libcore prelude, not as all-encompassing as the libstd prelude */
+/* The core prelude, not as all-encompassing as the std prelude */
pub mod prelude;
#[stable(feature = "core_primitive", since = "1.43.0")]
pub mod primitive;
-// Pull in the `core_arch` crate directly into libcore. The contents of
+// Pull in the `core_arch` crate directly into core. The contents of
// `core_arch` are in a different repository: rust-lang/stdarch.
//
-// `core_arch` depends on libcore, but the contents of this module are
+// `core_arch` depends on core, but the contents of this module are
// set up in such a way that directly pulling it here works such that the
-// crate uses the this crate as its libcore.
+// crate uses the this crate as its core.
#[path = "../../stdarch/crates/core_arch/src/mod.rs"]
#[allow(
missing_docs,
#[stable(feature = "simd_arch", since = "1.27.0")]
pub mod arch;
-// Pull in the `core_simd` crate directly into libcore. The contents of
+// Pull in the `core_simd` crate directly into core. The contents of
// `core_simd` are in a different repository: rust-lang/portable-simd.
//
-// `core_simd` depends on libcore, but the contents of this module are
+// `core_simd` depends on core, but the contents of this module are
// set up in such a way that directly pulling it here works such that the
-// crate uses this crate as its libcore.
+// crate uses this crate as its core.
#[path = "../../portable-simd/crates/core_simd/src/mod.rs"]
#[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
#[allow(rustdoc::bare_urls)]
/// Parses a file as an expression or an item according to the context.
///
- /// The file is located relative to the current file (similarly to how
- /// modules are found). The provided path is interpreted in a platform-specific
- /// way at compile time. So, for instance, an invocation with a Windows path
- /// containing backslashes `\` would not compile correctly on Unix.
+ /// **Warning**: For multi-file Rust projects, the `include!` macro is probably not what you
+ /// are looking for. Usually, multi-file Rust projects use
+ /// [modules](https://doc.rust-lang.org/reference/items/modules.html). Multi-file projects and
+ /// modules are explained in the Rust-by-Example book
+ /// [here](https://doc.rust-lang.org/rust-by-example/mod/split.html) and the module system is
+ /// explained in the Rust Book
+ /// [here](https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html).
+ ///
+ /// The included file is placed in the surrounding code
+ /// [unhygienically](https://doc.rust-lang.org/reference/macros-by-example.html#hygiene). If
+ /// the included file is parsed as an expression and variables or functions share names across
+ /// both files, it could result in variables or functions being different from what the
+ /// included file expected.
+ ///
+ /// The included file is located relative to the current file (similarly to how modules are
+ /// found). The provided path is interpreted in a platform-specific way at compile time. So,
+ /// for instance, an invocation with a Windows path containing backslashes `\` would not
+ /// compile correctly on Unix.
///
- /// Using this macro is often a bad idea, because if the file is
- /// parsed as an expression, it is going to be placed in the
- /// surrounding code unhygienically. This could result in variables
- /// or functions being different from what the file expected if
- /// there are variables or functions that have the same name in
- /// the current file.
+ /// # Uses
+ ///
+ /// The `include!` macro is primarily used for two purposes. It is used to include
+ /// documentation that is written in a separate file and it is used to include [build artifacts
+ /// usually as a result from the `build.rs`
+ /// script](https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script).
+ ///
+ /// When using the `include` macro to include stretches of documentation, remember that the
+ /// included file still needs to be a valid rust syntax. It is also possible to
+ /// use the [`include_str`] macro as `#![doc = include_str!("...")]` (at the module level) or
+ /// `#[doc = include_str!("...")]` (at the item level) to include documentation from a plain
+ /// text or markdown file.
///
/// # Examples
///
- /// Assume there are two files in the same directory with the following
- /// contents:
+ /// Assume there are two files in the same directory with the following contents:
///
/// File 'monkeys.in':
///
/// [the reference]: ../../../reference/attributes/derive.html
#[unstable(feature = "derive_const", issue = "none")]
#[rustc_builtin_macro]
- #[cfg(not(bootstrap))]
pub macro derive_const($item:item) {
/* compiler built-in */
}
/// Attribute macro applied to a function to register it as a handler for allocation failure.
///
/// See also [`std::alloc::handle_alloc_error`](../../../std/alloc/fn.handle_alloc_error.html).
- #[cfg(not(bootstrap))]
#[unstable(feature = "alloc_error_handler", issue = "51540")]
#[allow_internal_unstable(rustc_attrs)]
#[rustc_builtin_macro]
issue = "23416",
reason = "placeholder syntax for type ascription"
)]
- #[cfg(not(bootstrap))]
pub macro type_ascribe($expr:expr, $ty:ty) {
/* compiler built-in */
}
)]
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
#[rustc_specialization_trait]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl]
pub trait Sized {
// Empty.
}
/// [nomicon-coerce]: ../../nomicon/coercions.html
#[unstable(feature = "unsize", issue = "18598")]
#[lang = "unsize"]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl]
pub trait Unsize<T: ?Sized> {
// Empty.
}
/// (ideally) or `PhantomData<*const T>` (if no lifetime applies), so
/// as not to indicate ownership.
///
+/// ## Layout
+///
+/// For all `T`, the following are guaranteed:
+/// * `size_of::<PhantomData<T>>() == 0`
+/// * `align_of::<PhantomData<T>>() == 1`
+///
/// [drop check]: ../../nomicon/dropck.html
#[lang = "phantom_data"]
#[stable(feature = "rust1", since = "1.0.0")]
reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead"
)]
#[lang = "discriminant_kind"]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl]
pub trait DiscriminantKind {
/// The type of the discriminant, which must satisfy the trait
/// bounds required by `mem::Discriminant`.
#[lang = "destruct"]
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
#[const_trait]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl]
pub trait Destruct {}
/// A marker for tuple types.
#[unstable(feature = "tuple_trait", issue = "none")]
#[lang = "tuple_trait"]
#[rustc_on_unimplemented(message = "`{Self}` is not a tuple")]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl]
pub trait Tuple {}
/// A marker for things
#[unstable(feature = "pointer_sized_trait", issue = "none")]
-#[cfg_attr(not(bootstrap), lang = "pointer_sized")]
+#[lang = "pointer_sized"]
#[rustc_on_unimplemented(
message = "`{Self}` needs to be a pointer-sized type",
label = "`{Self}` needs to be a pointer-sized type"
self != self
}
- // FIXME(#50145): `abs` is publicly unavailable in libcore due to
+ // FIXME(#50145): `abs` is publicly unavailable in core due to
// concerns about portability, so this implementation is for
// private use internally.
#[inline]
self != self
}
- // FIXME(#50145): `abs` is publicly unavailable in libcore due to
+ // FIXME(#50145): `abs` is publicly unavailable in core due to
// concerns about portability, so this implementation is for
// private use internally.
#[inline]
/// ```
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
/// ```
- #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
- #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "int_log", since = "1.67.0")]
+ #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
#[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
/// ```
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
/// ```
- #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
- #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "int_log", since = "1.67.0")]
+ #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
#[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
/// ```
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
/// ```
- #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
- #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "int_log", since = "1.67.0")]
+ #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
#[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
/// ```
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
/// ```
- #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
- #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "int_log", since = "1.67.0")]
+ #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// ```
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
/// ```
- #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
- #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "int_log", since = "1.67.0")]
+ #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// ```
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
/// ```
- #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
- #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "int_log", since = "1.67.0")]
+ #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")]
/// ```
- #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
- #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "int_log", since = "1.67.0")]
+ #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")]
/// ```
- #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
- #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "int_log", since = "1.67.0")]
+ #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
///
#[doc = concat!("assert_eq!(", stringify!($Ty), "::BITS, ", stringify!($Int), "::BITS);")]
/// ```
- #[stable(feature = "nonzero_bits", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "nonzero_bits", since = "1.67.0")]
pub const BITS: u32 = <$Int>::BITS;
}
)+
/// ```
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
/// ```
- #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
- #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "int_log", since = "1.67.0")]
+ #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
#[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
/// ```
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
/// ```
- #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
- #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "int_log", since = "1.67.0")]
+ #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
#[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
/// ```
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
/// ```
- #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
- #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "int_log", since = "1.67.0")]
+ #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
#[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
/// ```
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
/// ```
- #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
- #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "int_log", since = "1.67.0")]
+ #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// ```
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
/// ```
- #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
- #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "int_log", since = "1.67.0")]
+ #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// ```
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
/// ```
- #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
- #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[stable(feature = "int_log", since = "1.67.0")]
+ #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
-#[cfg(not(bootstrap))]
use crate::marker::Tuple;
/// The version of the call operator that takes an immutable receiver.
/// let double = |x| x * 2;
/// assert_eq!(call_with_one(double), 2);
/// ```
-#[cfg(bootstrap)]
-#[lang = "fn"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_paren_sugar]
-#[rustc_on_unimplemented(
- on(
- Args = "()",
- note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
- ),
- on(
- _Self = "unsafe fn",
- note = "unsafe function cannot be called generically without an unsafe block",
- // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
- label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
- ),
- message = "expected a `{Fn}<{Args}>` closure, found `{Self}`",
- label = "expected an `Fn<{Args}>` closure, found `{Self}`"
-)]
-#[fundamental] // so that regex can rely that `&str: !FnMut`
-#[must_use = "closures are lazy and do nothing unless called"]
-#[const_trait]
-pub trait Fn<Args>: FnMut<Args> {
- /// Performs the call operation.
- #[unstable(feature = "fn_traits", issue = "29625")]
- extern "rust-call" fn call(&self, args: Args) -> Self::Output;
-}
-
-/// The version of the call operator that takes an immutable receiver.
-///
-/// Instances of `Fn` can be called repeatedly without mutating state.
-///
-/// *This trait (`Fn`) is not to be confused with [function pointers]
-/// (`fn`).*
-///
-/// `Fn` is implemented automatically by closures which only take immutable
-/// references to captured variables or don't capture anything at all, as well
-/// as (safe) [function pointers] (with some caveats, see their documentation
-/// for more details). Additionally, for any type `F` that implements `Fn`, `&F`
-/// implements `Fn`, too.
-///
-/// Since both [`FnMut`] and [`FnOnce`] are supertraits of `Fn`, any
-/// instance of `Fn` can be used as a parameter where a [`FnMut`] or [`FnOnce`]
-/// is expected.
-///
-/// Use `Fn` as a bound when you want to accept a parameter of function-like
-/// type and need to call it repeatedly and without mutating state (e.g., when
-/// calling it concurrently). If you do not need such strict requirements, use
-/// [`FnMut`] or [`FnOnce`] as bounds.
-///
-/// See the [chapter on closures in *The Rust Programming Language*][book] for
-/// some more information on this topic.
-///
-/// Also of note is the special syntax for `Fn` traits (e.g.
-/// `Fn(usize, bool) -> usize`). Those interested in the technical details of
-/// this can refer to [the relevant section in the *Rustonomicon*][nomicon].
-///
-/// [book]: ../../book/ch13-01-closures.html
-/// [function pointers]: fn
-/// [nomicon]: ../../nomicon/hrtb.html
-///
-/// # Examples
-///
-/// ## Calling a closure
-///
-/// ```
-/// let square = |x| x * x;
-/// assert_eq!(square(5), 25);
-/// ```
-///
-/// ## Using a `Fn` parameter
-///
-/// ```
-/// fn call_with_one<F>(func: F) -> usize
-/// where F: Fn(usize) -> usize {
-/// func(1)
-/// }
-///
-/// let double = |x| x * 2;
-/// assert_eq!(call_with_one(double), 2);
-/// ```
-#[cfg(not(bootstrap))]
#[lang = "fn"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
///
/// assert_eq!(x, 5);
/// ```
-#[cfg(bootstrap)]
-#[lang = "fn_mut"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_paren_sugar]
-#[rustc_on_unimplemented(
- on(
- Args = "()",
- note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
- ),
- on(
- _Self = "unsafe fn",
- note = "unsafe function cannot be called generically without an unsafe block",
- // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
- label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
- ),
- message = "expected a `{FnMut}<{Args}>` closure, found `{Self}`",
- label = "expected an `FnMut<{Args}>` closure, found `{Self}`"
-)]
-#[fundamental] // so that regex can rely that `&str: !FnMut`
-#[must_use = "closures are lazy and do nothing unless called"]
-#[const_trait]
-pub trait FnMut<Args>: FnOnce<Args> {
- /// Performs the call operation.
- #[unstable(feature = "fn_traits", issue = "29625")]
- extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
-}
-
-/// The version of the call operator that takes a mutable receiver.
-///
-/// Instances of `FnMut` can be called repeatedly and may mutate state.
-///
-/// `FnMut` is implemented automatically by closures which take mutable
-/// references to captured variables, as well as all types that implement
-/// [`Fn`], e.g., (safe) [function pointers] (since `FnMut` is a supertrait of
-/// [`Fn`]). Additionally, for any type `F` that implements `FnMut`, `&mut F`
-/// implements `FnMut`, too.
-///
-/// Since [`FnOnce`] is a supertrait of `FnMut`, any instance of `FnMut` can be
-/// used where a [`FnOnce`] is expected, and since [`Fn`] is a subtrait of
-/// `FnMut`, any instance of [`Fn`] can be used where `FnMut` is expected.
-///
-/// Use `FnMut` as a bound when you want to accept a parameter of function-like
-/// type and need to call it repeatedly, while allowing it to mutate state.
-/// If you don't want the parameter to mutate state, use [`Fn`] as a
-/// bound; if you don't need to call it repeatedly, use [`FnOnce`].
-///
-/// See the [chapter on closures in *The Rust Programming Language*][book] for
-/// some more information on this topic.
-///
-/// Also of note is the special syntax for `Fn` traits (e.g.
-/// `Fn(usize, bool) -> usize`). Those interested in the technical details of
-/// this can refer to [the relevant section in the *Rustonomicon*][nomicon].
-///
-/// [book]: ../../book/ch13-01-closures.html
-/// [function pointers]: fn
-/// [nomicon]: ../../nomicon/hrtb.html
-///
-/// # Examples
-///
-/// ## Calling a mutably capturing closure
-///
-/// ```
-/// let mut x = 5;
-/// {
-/// let mut square_x = || x *= x;
-/// square_x();
-/// }
-/// assert_eq!(x, 25);
-/// ```
-///
-/// ## Using a `FnMut` parameter
-///
-/// ```
-/// fn do_twice<F>(mut func: F)
-/// where F: FnMut()
-/// {
-/// func();
-/// func();
-/// }
-///
-/// let mut x: usize = 1;
-/// {
-/// let add_two_to_x = || x += 2;
-/// do_twice(add_two_to_x);
-/// }
-///
-/// assert_eq!(x, 5);
-/// ```
-#[cfg(not(bootstrap))]
#[lang = "fn_mut"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
///
/// // `consume_and_return_x` can no longer be invoked at this point
/// ```
-#[cfg(bootstrap)]
-#[lang = "fn_once"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_paren_sugar]
-#[rustc_on_unimplemented(
- on(
- Args = "()",
- note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
- ),
- on(
- _Self = "unsafe fn",
- note = "unsafe function cannot be called generically without an unsafe block",
- // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
- label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
- ),
- message = "expected a `{FnOnce}<{Args}>` closure, found `{Self}`",
- label = "expected an `FnOnce<{Args}>` closure, found `{Self}`"
-)]
-#[fundamental] // so that regex can rely that `&str: !FnMut`
-#[must_use = "closures are lazy and do nothing unless called"]
-#[const_trait]
-pub trait FnOnce<Args> {
- /// The returned type after the call operator is used.
- #[lang = "fn_once_output"]
- #[stable(feature = "fn_once_output", since = "1.12.0")]
- type Output;
-
- /// Performs the call operation.
- #[unstable(feature = "fn_traits", issue = "29625")]
- extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
-}
-
-/// The version of the call operator that takes a by-value receiver.
-///
-/// Instances of `FnOnce` can be called, but might not be callable multiple
-/// times. Because of this, if the only thing known about a type is that it
-/// implements `FnOnce`, it can only be called once.
-///
-/// `FnOnce` is implemented automatically by closures that might consume captured
-/// variables, as well as all types that implement [`FnMut`], e.g., (safe)
-/// [function pointers] (since `FnOnce` is a supertrait of [`FnMut`]).
-///
-/// Since both [`Fn`] and [`FnMut`] are subtraits of `FnOnce`, any instance of
-/// [`Fn`] or [`FnMut`] can be used where a `FnOnce` is expected.
-///
-/// Use `FnOnce` as a bound when you want to accept a parameter of function-like
-/// type and only need to call it once. If you need to call the parameter
-/// repeatedly, use [`FnMut`] as a bound; if you also need it to not mutate
-/// state, use [`Fn`].
-///
-/// See the [chapter on closures in *The Rust Programming Language*][book] for
-/// some more information on this topic.
-///
-/// Also of note is the special syntax for `Fn` traits (e.g.
-/// `Fn(usize, bool) -> usize`). Those interested in the technical details of
-/// this can refer to [the relevant section in the *Rustonomicon*][nomicon].
-///
-/// [book]: ../../book/ch13-01-closures.html
-/// [function pointers]: fn
-/// [nomicon]: ../../nomicon/hrtb.html
-///
-/// # Examples
-///
-/// ## Using a `FnOnce` parameter
-///
-/// ```
-/// fn consume_with_relish<F>(func: F)
-/// where F: FnOnce() -> String
-/// {
-/// // `func` consumes its captured variables, so it cannot be run more
-/// // than once.
-/// println!("Consumed: {}", func());
-///
-/// println!("Delicious!");
-///
-/// // Attempting to invoke `func()` again will throw a `use of moved
-/// // value` error for `func`.
-/// }
-///
-/// let x = String::from("x");
-/// let consume_and_return_x = move || x;
-/// consume_with_relish(consume_and_return_x);
-///
-/// // `consume_and_return_x` can no longer be invoked at this point
-/// ```
-#[cfg(not(bootstrap))]
#[lang = "fn_once"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
-#[cfg(bootstrap)]
-mod impls {
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
- impl<A, F: ?Sized> const Fn<A> for &F
- where
- F: ~const Fn<A>,
- {
- extern "rust-call" fn call(&self, args: A) -> F::Output {
- (**self).call(args)
- }
- }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
- impl<A, F: ?Sized> const FnMut<A> for &F
- where
- F: ~const Fn<A>,
- {
- extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
- (**self).call(args)
- }
- }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
- impl<A, F: ?Sized> const FnOnce<A> for &F
- where
- F: ~const Fn<A>,
- {
- type Output = F::Output;
-
- extern "rust-call" fn call_once(self, args: A) -> F::Output {
- (*self).call(args)
- }
- }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
- impl<A, F: ?Sized> const FnMut<A> for &mut F
- where
- F: ~const FnMut<A>,
- {
- extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
- (*self).call_mut(args)
- }
- }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
- impl<A, F: ?Sized> const FnOnce<A> for &mut F
- where
- F: ~const FnMut<A>,
- {
- type Output = F::Output;
- extern "rust-call" fn call_once(self, args: A) -> F::Output {
- (*self).call_mut(args)
- }
- }
-}
-
-#[cfg(not(bootstrap))]
mod impls {
use crate::marker::Tuple;
),
}
-/// An internal trait used by libstd to pass data from libstd to `panic_unwind`
-/// and other panic runtimes. Not intended to be stabilized any time soon, do
-/// not use.
+/// An internal trait used by std to pass data from std to `panic_unwind` and
+/// other panic runtimes. Not intended to be stabilized any time soon, do not
+/// use.
#[unstable(feature = "std_internals", issue = "none")]
#[doc(hidden)]
pub unsafe trait BoxMeUp {
/// Take full ownership of the contents.
- /// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in libcore.
+ /// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in core.
///
/// After this method got called, only some dummy default value is left in `self`.
/// Calling this method twice, or calling `get` after calling this method, is an error.
write!(formatter, "'{}', ", payload)?
}
// NOTE: we cannot use downcast_ref::<String>() here
- // since String is not available in libcore!
+ // since String is not available in core!
// The payload is a String when `std::panic!` is called with multiple arguments,
// but in that case the message is also available.
-//! Panic support for libcore
+//! Panic support for core
//!
//! The core library cannot define panicking, but it does *declare* panicking. This
-//! means that the functions inside of libcore are allowed to panic, but to be
-//! useful an upstream crate must define panicking for libcore to use. The current
+//! means that the functions inside of core are allowed to panic, but to be
+//! useful an upstream crate must define panicking for core to use. The current
//! interface for panicking is:
//!
//! ```
//! This definition allows for panicking with any general message, but it does not
//! allow for failing with a `Box<Any>` value. (`PanicInfo` just contains a `&(dyn Any + Send)`,
//! for which we fill in a dummy value in `PanicInfo::internal_constructor`.)
-//! The reason for this is that libcore is not allowed to allocate.
+//! The reason for this is that core is not allowed to allocate.
//!
//! This module contains a few other panicking functions, but these are just the
//! necessary lang items for the compiler. All panics are funneled through this
unsafe { panic_impl(&pi) }
}
-/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize.
-/// (No `fmt` variant as a `fmt::Arguments` needs more space to be passed.)
+/// Like `panic_fmt`, but for non-unwinding panics.
+///
+/// Has to be a separate function so that it can carry the `rustc_nounwind` attribute.
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cfg_attr(not(bootstrap), lang = "panic_nounwind")] // needed by codegen for non-unwinding panics
+#[track_caller]
+// This attribute has the key side-effect that if the panic handler ignores `can_unwind`
+// and unwinds anyway, we will hit the "unwinding out of nounwind function" guard,
+// which causes a "panic in a function that cannot unwind".
#[rustc_nounwind]
-pub fn panic_nounwind(msg: &'static str) -> ! {
+pub fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>) -> ! {
if cfg!(feature = "panic_immediate_abort") {
super::intrinsics::abort()
}
}
// PanicInfo with the `can_unwind` flag set to false forces an abort.
- let pieces = [msg];
- let fmt = fmt::Arguments::new_v1(&pieces, &[]);
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
// Next we define a bunch of higher-level wrappers that all bottom out in the two core functions
// above.
-/// The underlying implementation of libcore's `panic!` macro when no formatting is used.
+/// The underlying implementation of core's `panic!` macro when no formatting is used.
// never inline unless panic_immediate_abort to avoid code
// bloat at the call sites as much as possible
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]));
}
+/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize.
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(bootstrap), lang = "panic_nounwind")] // needed by codegen for non-unwinding panics
+#[rustc_nounwind]
+pub fn panic_nounwind(expr: &'static str) -> ! {
+ panic_nounwind_fmt(fmt::Arguments::new_v1(&[expr], &[]));
+}
+
#[inline]
#[track_caller]
#[rustc_diagnostic_item = "panic_str"]
-//! The libcore prelude
+//! The core prelude
//!
-//! This module is intended for users of libcore which do not link to libstd as
-//! well. This module is imported by default when `#![no_std]` is used in the
-//! same manner as the standard library's prelude.
+//! This module is intended for users of core which do not link to std as well.
+//! This module is imported by default when `#![no_std]` is used in the same
+//! manner as the standard library's prelude.
#![stable(feature = "core_prelude", since = "1.4.0")]
// Do not `doc(no_inline)` so that they become doc items on their own
// (no public module for them to be re-exported from).
-#[cfg(not(bootstrap))]
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-pub use crate::macros::builtin::alloc_error_handler;
-#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case};
+pub use crate::macros::builtin::{
+ alloc_error_handler, bench, derive, global_allocator, test, test_case,
+};
#[unstable(feature = "derive_const", issue = "none")]
-#[cfg(not(bootstrap))]
pub use crate::macros::builtin::derive_const;
#[unstable(
issue = "23416",
reason = "placeholder syntax for type ascription"
)]
-#[cfg(not(bootstrap))]
pub use crate::macros::builtin::type_ascribe;
/// are likely not to be supported by actual allocators and linkers.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[derive(Copy, Clone, Eq)]
-#[cfg_attr(bootstrap, derive(PartialEq))]
-#[cfg_attr(not(bootstrap), derive_const(PartialEq))]
+#[derive_const(PartialEq)]
#[repr(transparent)]
pub struct Alignment(AlignmentEnum);
type AlignmentEnum = AlignmentEnum64;
#[derive(Copy, Clone, Eq)]
-#[cfg_attr(bootstrap, derive(PartialEq))]
-#[cfg_attr(not(bootstrap), derive_const(PartialEq))]
+#[derive_const(PartialEq)]
#[repr(u16)]
enum AlignmentEnum16 {
_Align1Shl0 = 1 << 0,
}
#[derive(Copy, Clone, Eq)]
-#[cfg_attr(bootstrap, derive(PartialEq))]
-#[cfg_attr(not(bootstrap), derive_const(PartialEq))]
+#[derive_const(PartialEq)]
#[repr(u32)]
enum AlignmentEnum32 {
_Align1Shl0 = 1 << 0,
}
#[derive(Copy, Clone, Eq)]
-#[cfg_attr(bootstrap, derive(PartialEq))]
-#[cfg_attr(not(bootstrap), derive_const(PartialEq))]
+#[derive_const(PartialEq)]
#[repr(u64)]
enum AlignmentEnum64 {
_Align1Shl0 = 1 << 0,
use super::*;
use crate::cmp::Ordering::{self, Equal, Greater, Less};
-use crate::intrinsics;
+use crate::intrinsics::{self, const_eval_select};
use crate::mem;
use crate::slice::{self, SliceIndex};
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
#[inline]
pub const fn is_null(self) -> bool {
- // Compare via a cast to a thin pointer, so fat pointers are only
- // considering their "data" part for null-ness.
- match (self as *const u8).guaranteed_eq(null()) {
- None => false,
- Some(res) => res,
+ #[inline]
+ fn runtime_impl(ptr: *const u8) -> bool {
+ ptr.addr() == 0
}
+
+ #[inline]
+ const fn const_impl(ptr: *const u8) -> bool {
+ // Compare via a cast to a thin pointer, so fat pointers are only
+ // considering their "data" part for null-ness.
+ match (ptr).guaranteed_eq(null_mut()) {
+ None => false,
+ Some(res) => res,
+ }
+ }
+
+ // SAFETY: The two versions are equivalent at runtime.
+ unsafe { const_eval_select((self as *const u8,), const_impl, runtime_impl) }
}
/// Casts to a pointer of another type.
panic!("align_offset: align is not a power-of-two");
}
- #[cfg(bootstrap)]
- {
- fn rt_impl<T>(p: *const T, align: usize) -> usize {
- // SAFETY: `align` has been checked to be a power of 2 above
- unsafe { align_offset(p, align) }
- }
-
- const fn ctfe_impl<T>(_: *const T, _: usize) -> usize {
- usize::MAX
- }
-
- // SAFETY:
- // It is permissible for `align_offset` to always return `usize::MAX`,
- // algorithm correctness can not depend on `align_offset` returning non-max values.
- //
- // As such the behaviour can't change after replacing `align_offset` with `usize::MAX`, only performance can.
- unsafe { intrinsics::const_eval_select((self, align), ctfe_impl, rt_impl) }
- }
-
- #[cfg(not(bootstrap))]
{
// SAFETY: `align` has been checked to be a power of 2 above
unsafe { align_offset(self, align) }
/// is never aligned if cast to a type with a stricter alignment than the reference's
/// underlying allocation.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
/// cannot be stricter aligned than the reference's underlying allocation.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
panic!("is_aligned_to: align is not a power-of-two");
}
- // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
- // The cast to `()` is used to
- // 1. deal with fat pointers; and
- // 2. ensure that `align_offset` doesn't actually try to compute an offset.
- self.cast::<()>().align_offset(align) == 0
+ #[inline]
+ fn runtime_impl(ptr: *const (), align: usize) -> bool {
+ ptr.addr() & (align - 1) == 0
+ }
+
+ #[inline]
+ const fn const_impl(ptr: *const (), align: usize) -> bool {
+ // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
+ // The cast to `()` is used to
+ // 1. deal with fat pointers; and
+ // 2. ensure that `align_offset` doesn't actually try to compute an offset.
+ ptr.align_offset(align) == 0
+ }
+
+ // SAFETY: The two versions are equivalent at runtime.
+ unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) }
}
}
///
/// [`to_raw_parts`]: *const::to_raw_parts
#[lang = "pointee_trait"]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl]
pub trait Pointee {
/// The type for metadata in pointers and references to `Self`.
#[lang = "metadata_type"]
use super::*;
use crate::cmp::Ordering::{self, Equal, Greater, Less};
-use crate::intrinsics;
+use crate::intrinsics::{self, const_eval_select};
use crate::slice::{self, SliceIndex};
impl<T: ?Sized> *mut T {
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
#[inline]
pub const fn is_null(self) -> bool {
- // Compare via a cast to a thin pointer, so fat pointers are only
- // considering their "data" part for null-ness.
- match (self as *mut u8).guaranteed_eq(null_mut()) {
- None => false,
- Some(res) => res,
+ #[inline]
+ fn runtime_impl(ptr: *mut u8) -> bool {
+ ptr.addr() == 0
}
+
+ #[inline]
+ const fn const_impl(ptr: *mut u8) -> bool {
+ // Compare via a cast to a thin pointer, so fat pointers are only
+ // considering their "data" part for null-ness.
+ match (ptr).guaranteed_eq(null_mut()) {
+ None => false,
+ Some(res) => res,
+ }
+ }
+
+ // SAFETY: The two versions are equivalent at runtime.
+ unsafe { const_eval_select((self as *mut u8,), const_impl, runtime_impl) }
}
/// Casts to a pointer of another type.
panic!("align_offset: align is not a power-of-two");
}
- #[cfg(bootstrap)]
- {
- fn rt_impl<T>(p: *mut T, align: usize) -> usize {
- // SAFETY: `align` has been checked to be a power of 2 above
- unsafe { align_offset(p, align) }
- }
-
- const fn ctfe_impl<T>(_: *mut T, _: usize) -> usize {
- usize::MAX
- }
-
- // SAFETY:
- // It is permissible for `align_offset` to always return `usize::MAX`,
- // algorithm correctness can not depend on `align_offset` returning non-max values.
- //
- // As such the behaviour can't change after replacing `align_offset` with `usize::MAX`, only performance can.
- unsafe { intrinsics::const_eval_select((self, align), ctfe_impl, rt_impl) }
- }
-
- #[cfg(not(bootstrap))]
{
// SAFETY: `align` has been checked to be a power of 2 above
unsafe { align_offset(self, align) }
/// is never aligned if cast to a type with a stricter alignment than the reference's
/// underlying allocation.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
/// #![feature(const_mut_refs)]
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
/// cannot be stricter aligned than the reference's underlying allocation.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
/// #![feature(const_mut_refs)]
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
panic!("is_aligned_to: align is not a power-of-two");
}
- // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
- // The cast to `()` is used to
- // 1. deal with fat pointers; and
- // 2. ensure that `align_offset` doesn't actually try to compute an offset.
- self.cast::<()>().align_offset(align) == 0
+ #[inline]
+ fn runtime_impl(ptr: *mut (), align: usize) -> bool {
+ ptr.addr() & (align - 1) == 0
+ }
+
+ #[inline]
+ const fn const_impl(ptr: *mut (), align: usize) -> bool {
+ // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
+ // The cast to `()` is used to
+ // 1. deal with fat pointers; and
+ // 2. ensure that `align_offset` doesn't actually try to compute an offset.
+ ptr.align_offset(align) == 0
+ }
+
+ // SAFETY: The two versions are equivalent at runtime.
+ unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) }
}
}
//! 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
+//! Unstable sorting is compatible with core because it doesn't allocate memory, unlike our
//! stable sorting implementation.
use crate::cmp;
impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
#[inline]
fn get_end(&mut self) -> Option<&'a str> {
- if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) {
+ if !self.finished {
self.finished = true;
- // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
- unsafe {
- let string = self.matcher.haystack().get_unchecked(self.start..self.end);
- Some(string)
+
+ if self.allow_trailing_empty || self.end - self.start > 0 {
+ // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
+ let string = unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) };
+ return Some(string);
}
- } else {
- None
}
+
+ None
}
#[inline]
}
#[inline]
- fn as_str(&self) -> &'a str {
+ fn remainder(&self) -> Option<&'a str> {
// `Self::get_end` doesn't change `self.start`
if self.finished {
- return "";
+ return None;
}
// SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
- unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) }
+ Some(unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) })
}
}
}
impl<'a, P: Pattern<'a>> Split<'a, P> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_as_str)]
+ /// #![feature(str_split_remainder)]
/// let mut split = "Mary had a little lamb".split(' ');
- /// assert_eq!(split.as_str(), "Mary had a little lamb");
+ /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
/// split.next();
- /// assert_eq!(split.as_str(), "had a little lamb");
+ /// assert_eq!(split.remainder(), Some("had a little lamb"));
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
- #[unstable(feature = "str_split_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.0.as_str()
+ #[unstable(feature = "str_split_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.0.remainder()
}
}
impl<'a, P: Pattern<'a>> RSplit<'a, P> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_as_str)]
+ /// #![feature(str_split_remainder)]
/// let mut split = "Mary had a little lamb".rsplit(' ');
- /// assert_eq!(split.as_str(), "Mary had a little lamb");
+ /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
/// split.next();
- /// assert_eq!(split.as_str(), "Mary had a little");
+ /// assert_eq!(split.remainder(), Some("Mary had a little"));
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
- #[unstable(feature = "str_split_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.0.as_str()
+ #[unstable(feature = "str_split_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.0.remainder()
}
}
}
impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_as_str)]
+ /// #![feature(str_split_remainder)]
/// let mut split = "A..B..".split_terminator('.');
- /// assert_eq!(split.as_str(), "A..B..");
+ /// assert_eq!(split.remainder(), Some("A..B.."));
/// split.next();
- /// assert_eq!(split.as_str(), ".B..");
+ /// assert_eq!(split.remainder(), Some(".B.."));
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
- #[unstable(feature = "str_split_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.0.as_str()
+ #[unstable(feature = "str_split_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.0.remainder()
}
}
impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_as_str)]
+ /// #![feature(str_split_remainder)]
/// let mut split = "A..B..".rsplit_terminator('.');
- /// assert_eq!(split.as_str(), "A..B..");
+ /// assert_eq!(split.remainder(), Some("A..B.."));
/// split.next();
- /// assert_eq!(split.as_str(), "A..B");
+ /// assert_eq!(split.remainder(), Some("A..B"));
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
- #[unstable(feature = "str_split_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.0.as_str()
+ #[unstable(feature = "str_split_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.0.remainder()
}
}
}
#[inline]
- fn as_str(&self) -> &'a str {
- self.iter.as_str()
+ fn remainder(&self) -> Option<&'a str> {
+ self.iter.remainder()
}
}
}
impl<'a, P: Pattern<'a>> SplitN<'a, P> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_as_str)]
+ /// #![feature(str_split_remainder)]
/// let mut split = "Mary had a little lamb".splitn(3, ' ');
- /// assert_eq!(split.as_str(), "Mary had a little lamb");
+ /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
/// split.next();
- /// assert_eq!(split.as_str(), "had a little lamb");
+ /// assert_eq!(split.remainder(), Some("had a little lamb"));
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
- #[unstable(feature = "str_split_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.0.as_str()
+ #[unstable(feature = "str_split_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.0.remainder()
}
}
impl<'a, P: Pattern<'a>> RSplitN<'a, P> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_as_str)]
+ /// #![feature(str_split_remainder)]
/// let mut split = "Mary had a little lamb".rsplitn(3, ' ');
- /// assert_eq!(split.as_str(), "Mary had a little lamb");
+ /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
/// split.next();
- /// assert_eq!(split.as_str(), "Mary had a little");
+ /// assert_eq!(split.remainder(), Some("Mary had a little"));
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
- #[unstable(feature = "str_split_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.0.as_str()
+ #[unstable(feature = "str_split_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.0.remainder()
}
}
/// # Examples
///
/// ```
- /// #![feature(str_split_whitespace_as_str)]
+ /// #![feature(str_split_whitespace_remainder)]
///
/// let mut split = "Mary had a little lamb".split_whitespace();
- /// assert_eq!(split.as_str(), "Mary had a little lamb");
+ /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
///
/// split.next();
- /// assert_eq!(split.as_str(), "had a little lamb");
+ /// assert_eq!(split.remainder(), Some("had a little lamb"));
///
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
#[must_use]
- #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.inner.iter.as_str()
+ #[unstable(feature = "str_split_whitespace_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.inner.iter.remainder()
}
}
impl FusedIterator for SplitAsciiWhitespace<'_> {}
impl<'a> SplitAsciiWhitespace<'a> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_whitespace_as_str)]
+ /// #![feature(str_split_whitespace_remainder)]
///
/// let mut split = "Mary had a little lamb".split_ascii_whitespace();
- /// assert_eq!(split.as_str(), "Mary had a little lamb");
+ /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
///
/// split.next();
- /// assert_eq!(split.as_str(), "had a little lamb");
+ /// assert_eq!(split.remainder(), Some("had a little lamb"));
///
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
#[must_use]
- #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
+ #[unstable(feature = "str_split_whitespace_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
if self.inner.iter.iter.finished {
- return "";
+ return None;
}
// SAFETY: Slice is created from str.
- unsafe { crate::str::from_utf8_unchecked(&self.inner.iter.iter.v) }
+ Some(unsafe { crate::str::from_utf8_unchecked(&self.inner.iter.iter.v) })
}
}
impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_inclusive_as_str)]
+ /// #![feature(str_split_inclusive_remainder)]
/// let mut split = "Mary had a little lamb".split_inclusive(' ');
- /// assert_eq!(split.as_str(), "Mary had a little lamb");
+ /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
/// split.next();
- /// assert_eq!(split.as_str(), "had a little lamb");
+ /// assert_eq!(split.remainder(), Some("had a little lamb"));
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
- #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.0.as_str()
+ #[unstable(feature = "str_split_inclusive_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.0.remainder()
}
}
#[inline(always)]
pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
// SAFETY: the cast from `&str` to `&[u8]` is safe since `str`
- // has the same layout as `&[u8]` (only libstd can make this guarantee).
+ // has the same layout as `&[u8]` (only std can make this guarantee).
// The pointer dereference is safe since it comes from a mutable reference which
// is guaranteed to be valid for writes.
unsafe { &mut *(self as *mut str as *mut [u8]) }
/// scheduled to receive a wakeup instead.
#[must_use = "this `Poll` may be a `Pending` variant, which should be handled"]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
-#[cfg_attr(not(bootstrap), lang = "Poll")]
+#[lang = "Poll"]
#[stable(feature = "futures_api", since = "1.36.0")]
pub enum Poll<T> {
/// Represents that a value is immediately ready.
// are contravariant while return-position lifetimes are
// covariant).
_marker: PhantomData<fn(&'a ()) -> &'a ()>,
+ // Ensure `Context` is `!Send` and `!Sync` in order to allow
+ // for future `!Send` and / or `!Sync` fields.
+ _marker2: PhantomData<*mut ()>,
}
impl<'a> Context<'a> {
#[must_use]
#[inline]
pub const fn from_waker(waker: &'a Waker) -> Self {
- Context { waker, _marker: PhantomData }
+ Context { waker, _marker: PhantomData, _marker2: PhantomData }
}
/// Returns a reference to the [`Waker`] for the current task.
#[stable(feature = "unicode_version", since = "1.45.0")]
pub const UNICODE_VERSION: (u8, u8, u8) = unicode_data::UNICODE_VERSION;
-// For use in liballoc, not re-exported in libstd.
+// For use in alloc, not re-exported in std.
pub use unicode_data::{
case_ignorable::lookup as Case_Ignorable, cased::lookup as Cased, conversions,
};
assert_ne!(type_name_of_val(Velocity), type_name_of_val(Velocity(0.0, -9.8)),);
}
-#[cfg(not(bootstrap))]
#[test]
fn dyn_type_name() {
trait Foo {
assert_eq!(called.get(), 1);
}
+// Check that we can infer `T` from closure's type.
+#[test]
+fn lazy_type_inference() {
+ let _ = LazyCell::new(|| ());
+}
+
#[test]
fn aliasing_in_get() {
let x = OnceCell::new();
mod tuple;
mod unicode;
mod waker;
+
+/// Copied from `std::test_helpers::test_rng`, see that function for rationale.
+#[track_caller]
+#[allow(dead_code)] // Not used in all configurations.
+pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
+ use core::hash::{BuildHasher, Hash, Hasher};
+ let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
+ core::panic::Location::caller().hash(&mut hasher);
+ let hc64 = hasher.finish();
+ let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
+ let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
+ rand::SeedableRng::from_seed(seed)
+}
}
#[test]
-#[cfg(not(bootstrap))] // stage 0 doesn't have the fix yet, so the test fails
fn align_of_val_raw_packed() {
#[repr(C, packed)]
struct B {
use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded};
use rand::distributions::{Distribution, Uniform};
-use rand::rngs::StdRng;
-use rand::SeedableRng;
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
match decode(v).1 {
if cfg!(target_os = "emscripten") {
return; // using rng pulls in i128 support, which doesn't work
}
- let mut rng = StdRng::from_entropy();
+ let mut rng = crate::test_rng();
let f32_range = Uniform::new(0x0000_0001u32, 0x7f80_0000);
iterate("f32_random_equivalence_test", k, n, f, g, |_| {
let x = f32::from_bits(f32_range.sample(&mut rng));
if cfg!(target_os = "emscripten") {
return; // using rng pulls in i128 support, which doesn't work
}
- let mut rng = StdRng::from_entropy();
+ let mut rng = crate::test_rng();
let f64_range = Uniform::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000);
iterate("f64_random_equivalence_test", k, n, f, g, |_| {
let x = f64::from_bits(f64_range.sample(&mut rng));
}
#[test]
-#[cfg(not(bootstrap))]
fn align_offset_zst_const() {
const {
// For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at
}
#[test]
-#[cfg(not(bootstrap))]
fn align_offset_stride_one_const() {
const {
// For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
}
#[test]
-#[cfg(not(bootstrap))]
fn align_offset_various_strides_const() {
const unsafe fn test_stride<T>(ptr: *const T, numptr: usize, align: usize) {
let mut expected = usize::MAX;
}
#[test]
-#[cfg(not(bootstrap))]
fn align_offset_with_provenance_const() {
const {
// On some platforms (e.g. msp430-none-elf), the alignment of `i32` is less than 4.
}
#[test]
-#[cfg(not(bootstrap))]
fn align_offset_issue_103361_const() {
#[cfg(target_pointer_width = "64")]
const SIZE: usize = 1 << 47;
}
#[test]
-#[cfg(not(bootstrap))]
fn is_aligned_const() {
const {
let data = 42;
}
}
-#[test]
-#[cfg(bootstrap)]
-fn is_aligned_const() {
- const {
- let data = 42;
- let ptr: *const i32 = &data;
- // The bootstrap compiler always returns false for is_aligned.
- assert!(!ptr.is_aligned());
- assert!(!ptr.is_aligned_to(1));
- }
-}
-
#[test]
fn offset_from() {
let mut a = [0; 5];
}
// "Synthetic" trait impls generated by the compiler like those of `Pointee`
// are not checked for bounds of associated type.
- // So with a buggy libcore we could have both:
+ // So with a buggy core we could have both:
// * `<dyn Display as Pointee>::Metadata == DynMetadata`
// * `DynMetadata: !PartialEq`
// … and cause an ICE here:
fn sort_unstable() {
use core::cmp::Ordering::{Equal, Greater, Less};
use core::slice::heapsort;
- use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng};
+ use rand::{seq::SliceRandom, Rng};
// Miri is too slow (but still need to `chain` to make the types match)
let lens = if cfg!(miri) { (2..20).chain(0..0) } else { (2..25).chain(500..510) };
let mut v = [0; 600];
let mut tmp = [0; 600];
- let mut rng = StdRng::from_entropy();
+ let mut rng = crate::test_rng();
for len in lens {
let v = &mut v[0..len];
#[cfg_attr(miri, ignore)] // Miri is too slow
fn select_nth_unstable() {
use core::cmp::Ordering::{Equal, Greater, Less};
- use rand::rngs::StdRng;
use rand::seq::SliceRandom;
- use rand::{Rng, SeedableRng};
+ use rand::Rng;
- let mut rng = StdRng::from_entropy();
+ let mut rng = crate::test_rng();
for len in (2..21).chain(500..501) {
let mut orig = vec![0; len];
-// All `str` tests live in liballoc/tests
+// All `str` tests live in library/alloc/tests/str.rs
-use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
+use core::task::{Poll, RawWaker, RawWakerVTable, Waker};
#[test]
fn poll_const() {
static WAKER: Waker = unsafe { Waker::from_raw(VOID_WAKER) };
- static CONTEXT: Context<'static> = Context::from_waker(&WAKER);
-
- static WAKER_REF: &'static Waker = CONTEXT.waker();
-
- WAKER_REF.wake_by_ref();
+ WAKER.wake_by_ref();
}
//
// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail
//
- // Note: this is the same implementation as in libstd's `abort_internal`
+ // Note: this is the same implementation as in std's `abort_internal`
unsafe fn abort() -> ! {
#[allow(unused)]
const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
// This... is a bit of an oddity. The tl;dr; is that this is required to link
// correctly, the longer explanation is below.
//
-// Right now the binaries of libcore/libstd that we ship are all compiled with
+// Right now the binaries of core/std that we ship are all compiled with
// `-C panic=unwind`. This is done to ensure that the binaries are maximally
// compatible with as many situations as possible. The compiler, however,
// requires a "personality function" for all functions compiled with `-C
// library just defines this symbol so there's at least some personality
// somewhere.
//
-// Essentially this symbol is just defined to get wired up to libcore/libstd
+// Essentially this symbol is just defined to get wired up to core/std
// binaries, but it should never be called as we don't link in an unwinding
// runtime at all.
pub mod personalities {
}
extern "C" {
- /// Handler in libstd called when a panic object is dropped outside of
+ /// Handler in std called when a panic object is dropped outside of
/// `catch_unwind`.
fn __rust_drop_panic() -> !;
- /// Handler in libstd called when a foreign exception is caught.
+ /// Handler in std called when a foreign exception is caught.
fn __rust_foreign_exception() -> !;
}
fn maybe_install_panic_hook(force_show_panics: bool) {
// Hide the default panic output within `proc_macro` expansions.
- // NB. the server can't do this because it may use a different libstd.
+ // NB. the server can't do this because it may use a different std.
static HIDE_PANICS_DURING_EXPANSION: Once = Once::new();
HIDE_PANICS_DURING_EXPANSION.call_once(|| {
let prev = panic::take_hook();
/// Type alias for a hashmap using the `fx` hash algorithm.
pub type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
-/// A speedy hash algorithm for use within rustc. The hashmap in liballoc
-/// by default uses SipHash which isn't quite as speedy as we want. In the
-/// compiler we're not really worried about DOS attempts, so we use a fast
+/// A speedy hash algorithm for use within rustc. The hashmap in alloc by
+/// default uses SipHash which isn't quite as speedy as we want. In the compiler
+/// we're not really worried about DOS attempts, so we use a fast
/// non-cryptographic hash.
///
/// This is the same as the algorithm used by Firefox -- which is a homespun
$name::$method(server, $($arg),*)
};
// HACK(eddyb) don't use `panic::catch_unwind` in a panic.
- // If client and server happen to use the same `libstd`,
+ // If client and server happen to use the same `std`,
// `catch_unwind` asserts that the panic counter was 0,
// even when the closure passed to it didn't panic.
let r = if thread::panicking() {
// See rustc-std-workspace-core for why this crate is needed.
-// Rename the crate to avoid conflicting with the alloc module in liballoc.
+// Rename the crate to avoid conflicting with the alloc module in alloc.
extern crate alloc as foo;
pub use foo::*;
features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive']
[dev-dependencies]
-rand = "0.7"
+rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
+rand_xorshift = "0.3.0"
[target.'cfg(any(all(target_family = "wasm", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
#[allow(unused_unsafe)]
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
- panic!("memory allocation of {} bytes failed\n", layout.size());
+ panic!("memory allocation of {} bytes failed", layout.size());
} else {
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
}
//!
//! ## Platform support
//!
-//! Not all platforms that libstd compiles for support capturing backtraces.
-//! Some platforms simply do nothing when capturing a backtrace. To check
-//! whether the platform supports capturing backtraces you can consult the
-//! `BacktraceStatus` enum as a result of `Backtrace::status`.
+//! Not all platforms that std compiles for support capturing backtraces. Some
+//! platforms simply do nothing when capturing a backtrace. To check whether the
+//! platform supports capturing backtraces you can consult the `BacktraceStatus`
+//! enum as a result of `Backtrace::status`.
//!
//! Like above with accuracy platform support is done on a best effort basis.
//! Sometimes libraries might not be available at runtime or something may go
use super::RandomState;
use crate::assert_matches::assert_matches;
use crate::cell::RefCell;
-use rand::{thread_rng, Rng};
+use crate::test_helpers::test_rng;
+use rand::Rng;
use realstd::collections::TryReserveErrorKind::*;
// https://github.com/rust-lang/rust/issues/62301
}
let mut m = HashMap::new();
- let mut rng = thread_rng();
+ let mut rng = test_rng();
// Populate the map with some items.
for _ in 0..50 {
- let x = rng.gen_range(-10, 10);
+ let x = rng.gen_range(-10..10);
m.insert(x, ());
}
for _ in 0..1000 {
- let x = rng.gen_range(-10, 10);
+ let x = rng.gen_range(-10..10);
match m.entry(x) {
Vacant(_) => {}
Occupied(e) => {
///
/// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]);
/// set.retain(|&k| k % 2 == 0);
- /// assert_eq!(set.len(), 3);
+ /// assert_eq!(set, HashSet::from([2, 4, 6]));
/// ```
///
/// # Performance
use crate::thread;
use crate::time::{Duration, Instant};
-use rand::{rngs::StdRng, RngCore, SeedableRng};
+use rand::RngCore;
#[cfg(unix)]
use crate::os::unix::fs::symlink as symlink_dir;
#[test]
fn binary_file() {
let mut bytes = [0; 1024];
- StdRng::from_entropy().fill_bytes(&mut bytes);
+ crate::test_helpers::test_rng().fill_bytes(&mut bytes);
let tmpdir = tmpdir();
#[test]
fn write_then_read() {
let mut bytes = [0; 1024];
- StdRng::from_entropy().fill_bytes(&mut bytes);
+ crate::test_helpers::test_rng().fill_bytes(&mut bytes);
let tmpdir = tmpdir();
// `new_unchecked` is safe.
let res = Self(unsafe { NonNull::new_unchecked(tagged) }, PhantomData);
// quickly smoke-check we encoded the right thing (This generally will
- // only run in libstd's tests, unless the user uses -Zbuild-std)
+ // only run in std's tests, unless the user uses -Zbuild-std)
debug_assert!(matches!(res.data(), ErrorData::Custom(_)), "repr(custom) encoding failed");
res
}
// Safety: `TAG_OS` is not zero, so the result of the `|` is not 0.
let res = Self(unsafe { NonNull::new_unchecked(ptr::invalid_mut(utagged)) }, PhantomData);
// quickly smoke-check we encoded the right thing (This generally will
- // only run in libstd's tests, unless the user uses -Zbuild-std)
+ // only run in std's tests, unless the user uses -Zbuild-std)
debug_assert!(
matches!(res.data(), ErrorData::Os(c) if c == code),
"repr(os) encoding failed for {code}"
// Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0.
let res = Self(unsafe { NonNull::new_unchecked(ptr::invalid_mut(utagged)) }, PhantomData);
// quickly smoke-check we encoded the right thing (This generally will
- // only run in libstd's tests, unless the user uses -Zbuild-std)
+ // only run in std's tests, unless the user uses -Zbuild-std)
debug_assert!(
matches!(res.data(), ErrorData::Simple(k) if k == kind),
"repr(simple) encoding failed {:?}",
// that our encoding relies on for correctness and soundness. (Some of these are
// a bit overly thorough/cautious, admittedly)
//
-// If any of these are hit on a platform that libstd supports, we should likely
+// If any of these are hit on a platform that std supports, we should likely
// just use `repr_unpacked.rs` there instead (unless the fix is easy).
macro_rules! static_assert {
($condition:expr) => {
}
/// Read all bytes until a newline (the `0xA` byte) is reached, and append
- /// them to the provided buffer. You do not need to clear the buffer before
- /// appending.
+ /// them to the provided `String` buffer.
+ ///
+ /// Previous content of the buffer will be preserved. To avoid appending to
+ /// the buffer, you need to [`clear`] it first.
///
/// This function will read bytes from the underlying stream until the
/// newline delimiter (the `0xA` byte) or EOF is found. Once found, all bytes
///
/// This function is blocking and should be used carefully: it is possible for
/// an attacker to continuously send bytes without ever sending a newline
- /// or EOF.
+ /// or EOF. You can use [`take`] to limit the maximum number of bytes read.
///
/// [`Ok(0)`]: Ok
+ /// [`clear`]: String::clear
+ /// [`take`]: crate::io::Read::take
///
/// # Errors
///
use crate::fs::File;
use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines};
use crate::sync::atomic::{AtomicBool, Ordering};
-use crate::sync::{Arc, Mutex, MutexGuard, OnceLock};
+use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantMutex, ReentrantMutexGuard};
use crate::sys::stdio;
-use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
type LocalStream = Arc<Mutex<Vec<u8>>>;
//! # How to read this documentation
//!
//! If you already know the name of what you are looking for, the fastest way to
-//! find it is to use the <a href="#" onclick="focusSearchBar();">search
+//! find it is to use the <a href="#" onclick="window.searchState.focus();">search
//! bar</a> at the top of the page.
//!
//! Otherwise, you may want to jump to one of these useful sections:
no_global_oom_handling,
not(no_global_oom_handling)
))]
-// To run libstd tests without x.py without ending up with two copies of libstd, Miri needs to be
+// To run std tests without x.py without ending up with two copies of std, Miri needs to be
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
// rustc itself never sets the feature, so this line has no affect there.
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
pub mod sync;
pub mod time;
-// Pull in `std_float` crate into libstd. The contents of
+// Pull in `std_float` crate into std. The contents of
// `std_float` are in a different repository: rust-lang/portable-simd.
#[path = "../../portable-simd/crates/std_float/src/lib.rs"]
#[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
#[allow(dead_code, unused_attributes, fuzzy_provenance_casts)]
mod backtrace_rs;
-// Re-export macros defined in libcore.
+// Re-export macros defined in core.
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated, deprecated_in_future)]
pub use core::{
unimplemented, unreachable, write, writeln,
};
-// Re-export built-in macros defined through libcore.
+// Re-export built-in macros defined through core.
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
#[allow(deprecated)]
pub use core::{
#[unstable(feature = "sealed", issue = "none")]
pub trait Sealed {}
}
+
+#[cfg(test)]
+#[allow(dead_code)] // Not used in all configurations.
+pub(crate) mod test_helpers {
+ /// Test-only replacement for `rand::thread_rng()`, which is unusable for
+ /// us, as we want to allow running stdlib tests on tier-3 targets which may
+ /// not have `getrandom` support.
+ ///
+ /// Does a bit of a song and dance to ensure that the seed is different on
+ /// each call (as some tests sadly rely on this), but doesn't try that hard.
+ ///
+ /// This is duplicated in the `core`, `alloc` test suites (as well as
+ /// `std`'s integration tests), but figuring out a mechanism to share these
+ /// seems far more painful than copy-pasting a 7 line function a couple
+ /// times, given that even under a perma-unstable feature, I don't think we
+ /// want to expose types from `rand` from `std`.
+ #[track_caller]
+ pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
+ use core::hash::{BuildHasher, Hash, Hasher};
+ let mut hasher = crate::collections::hash_map::RandomState::new().build_hasher();
+ core::panic::Location::caller().hash(&mut hasher);
+ let hc64 = hasher.finish();
+ let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
+ let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
+ rand::SeedableRng::from_seed(seed)
+ }
+}
//! This module contains a set of macros which are exported from the standard
//! library. Each macro is available for use when linking against the standard
//! library.
+// ignore-tidy-dbg
#[doc = include_str!("../../core/src/macros/panic.md")]
#[macro_export]
/// An IPv6 address representing localhost: `::1`.
///
+ /// This corresponds to constant `IN6ADDR_LOOPBACK_INIT` or `in6addr_loopback` in other
+ /// languages.
+ ///
/// # Examples
///
/// ```
/// let addr = Ipv6Addr::LOCALHOST;
/// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
/// ```
+ #[doc(alias = "IN6ADDR_LOOPBACK_INIT")]
+ #[doc(alias = "in6addr_loopback")]
#[stable(feature = "ip_constructors", since = "1.30.0")]
pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
/// An IPv6 address representing the unspecified address: `::`
///
+ /// This corresponds to constant `IN6ADDR_ANY_INIT` or `in6addr_any` in other languages.
+ ///
/// # Examples
///
/// ```
/// let addr = Ipv6Addr::UNSPECIFIED;
/// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
/// ```
+ #[doc(alias = "IN6ADDR_ANY_INIT")]
+ #[doc(alias = "in6addr_any")]
#[stable(feature = "ip_constructors", since = "1.30.0")]
pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
/// aborting the process as well. This function *only* catches unwinding panics,
/// not those that abort the process.
///
+/// Note that if a custom panic hook has been set, it will be invoked before
+/// the panic is caught, before unwinding.
+///
/// Also note that unwinding into Rust code with a foreign exception (e.g.
/// an exception thrown from C++ code) is undefined behavior.
///
!panic_count::count_is_zero()
}
-/// Entry point of panics from the libcore crate (`panic_impl` lang item).
+/// Entry point of panics from the core crate (`panic_impl` lang item).
#[cfg(not(test))]
#[panic_handler]
pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
// have limited options. Currently our preference is to
// just abort. In the future we may consider resuming
// unwinding or otherwise exiting the thread cleanly.
- rtprintpanic!("thread panicked while panicking. aborting.\n");
+ if !can_unwind {
+ rtprintpanic!("thread caused non-unwinding panic. aborting.\n");
+ } else {
+ rtprintpanic!("thread panicked while panicking. aborting.\n");
+ }
crate::sys::abort_internal();
}
/// The primary separator of path components for the current platform.
///
/// For example, `/` on Unix and `\` on Windows.
-#[unstable(feature = "main_separator_str", issue = "94071")]
+#[stable(feature = "main_separator_str", since = "CURRENT_RUSTC_VERSION")]
pub const MAIN_SEPARATOR_STR: &str = crate::sys::path::MAIN_SEP_STR;
////////////////////////////////////////////////////////////////////////////////
// This casts are safe as OsStr is internally a wrapper around [u8] on all
// platforms.
//
- // Note that currently this relies on the special knowledge that libstd has;
+ // Note that currently this relies on the special knowledge that std has;
// these types are single-element structs but are not marked
// repr(transparent) or repr(C) which would make these casts not allowable
// outside std.
/// and `path` is not empty, the new path is normalized: all references
/// to `.` and `..` are removed.
///
+ /// Consider using [`Path::join`] if you need a new `PathBuf` instead of
+ /// using this function on a cloned `PathBuf`.
+ ///
/// # Examples
///
/// Pushing a relative path extends the existing path:
self.push(file_name);
}
- /// Updates [`self.extension`] to `extension`.
+ /// Updates [`self.extension`] to `Some(extension)` or to `None` if
+ /// `extension` is empty.
///
/// Returns `false` and does nothing if [`self.file_name`] is [`None`],
/// returns `true` and updates the extension otherwise.
/// If [`self.extension`] is [`None`], the extension is added; otherwise
/// it is replaced.
///
+ /// If `extension` is the empty string, [`self.extension`] will be [`None`]
+ /// afterwards, not `Some("")`.
+ ///
+ /// # Caveats
+ ///
+ /// The new `extension` may contain dots and will be used in its entirety,
+ /// but only the part after the final dot will be reflected in
+ /// [`self.extension`].
+ ///
+ /// If the file stem contains internal dots and `extension` is empty, part
+ /// of the old file stem will be considered the new [`self.extension`].
+ ///
+ /// See the examples below.
+ ///
/// [`self.file_name`]: Path::file_name
/// [`self.extension`]: Path::extension
///
/// p.set_extension("force");
/// assert_eq!(Path::new("/feel/the.force"), p.as_path());
///
- /// p.set_extension("dark_side");
- /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path());
+ /// p.set_extension("dark.side");
+ /// assert_eq!(Path::new("/feel/the.dark.side"), p.as_path());
+ ///
+ /// p.set_extension("cookie");
+ /// assert_eq!(Path::new("/feel/the.dark.cookie"), p.as_path());
+ ///
+ /// p.set_extension("");
+ /// assert_eq!(Path::new("/feel/the.dark"), p.as_path());
+ ///
+ /// p.set_extension("");
+ /// assert_eq!(Path::new("/feel/the"), p.as_path());
+ ///
+ /// p.set_extension("");
+ /// assert_eq!(Path::new("/feel/the"), p.as_path());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
// Do not `doc(no_inline)` so that they become doc items on their own
// (no public module for them to be re-exported from).
-#[cfg(not(bootstrap))]
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-pub use core::prelude::v1::alloc_error_handler;
-#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case};
+pub use core::prelude::v1::{
+ alloc_error_handler, bench, derive, global_allocator, test, test_case,
+};
#[unstable(feature = "derive_const", issue = "none")]
-#[cfg(not(bootstrap))]
pub use core::prelude::v1::derive_const;
// Do not `doc(no_inline)` either.
issue = "23416",
reason = "placeholder syntax for type ascription"
)]
-#[cfg(not(bootstrap))]
pub use core::prelude::v1::type_ascribe;
// The file so far is equivalent to src/libcore/prelude/v1.rs,
/// Format the program and arguments of a Command for display. Any
/// non-utf8 data is lossily converted using the utf8 replacement
/// character.
+ ///
+ /// The default format approximates a shell invocation of the program along with its
+ /// arguments. It does not include most of the other command properties. The output is not guaranteed to work
+ /// (e.g. due to lack of shell-escaping or differences in path resolution)
+ /// On some platforms you can use [the alternate syntax] to show more fields.
+ ///
+ /// Note that the debug implementation is platform-specific.
+ ///
+ /// [the alternate syntax]: fmt#sign0
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
/// to provide similar functionality.
#[cfg_attr(not(test), lang = "termination")]
#[stable(feature = "termination_trait_lib", since = "1.61.0")]
-#[rustc_on_unimplemented(
- on(
- all(not(bootstrap), cause = "MainFunctionType"),
- message = "`main` has invalid return type `{Self}`",
- label = "`main` can only return types that implement `{Termination}`"
- ),
- on(
- bootstrap,
- message = "`main` has invalid return type `{Self}`",
- label = "`main` can only return types that implement `{Termination}`"
- )
-)]
+#[rustc_on_unimplemented(on(
+ cause = "MainFunctionType",
+ message = "`main` has invalid return type `{Self}`",
+ label = "`main` can only return types that implement `{Termination}`"
+))]
pub trait Termination {
/// Is called to get the representation of the value as status code.
/// This status code is returned to the operating system.
assert!(p.is_ok());
}
+#[test]
+#[cfg(not(windows))]
+#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
+fn main() {
+ const PIDFD: &'static str =
+ if cfg!(target_os = "linux") { " create_pidfd: false,\n" } else { "" };
+
+ let mut command = Command::new("some-boring-name");
+
+ assert_eq!(format!("{command:?}"), format!(r#""some-boring-name""#));
+
+ assert_eq!(
+ format!("{command:#?}"),
+ format!(
+ r#"Command {{
+ program: "some-boring-name",
+ args: [
+ "some-boring-name",
+ ],
+{PIDFD}}}"#
+ )
+ );
+
+ command.args(&["1", "2", "3"]);
+
+ assert_eq!(format!("{command:?}"), format!(r#""some-boring-name" "1" "2" "3""#));
+
+ assert_eq!(
+ format!("{command:#?}"),
+ format!(
+ r#"Command {{
+ program: "some-boring-name",
+ args: [
+ "some-boring-name",
+ "1",
+ "2",
+ "3",
+ ],
+{PIDFD}}}"#
+ )
+ );
+
+ crate::os::unix::process::CommandExt::arg0(&mut command, "exciting-name");
+
+ assert_eq!(
+ format!("{command:?}"),
+ format!(r#"["some-boring-name"] "exciting-name" "1" "2" "3""#)
+ );
+
+ assert_eq!(
+ format!("{command:#?}"),
+ format!(
+ r#"Command {{
+ program: "some-boring-name",
+ args: [
+ "exciting-name",
+ "1",
+ "2",
+ "3",
+ ],
+{PIDFD}}}"#
+ )
+ );
+
+ let mut command_with_env_and_cwd = Command::new("boring-name");
+ command_with_env_and_cwd.current_dir("/some/path").env("FOO", "bar");
+ assert_eq!(
+ format!("{command_with_env_and_cwd:?}"),
+ r#"cd "/some/path" && FOO="bar" "boring-name""#
+ );
+ assert_eq!(
+ format!("{command_with_env_and_cwd:#?}"),
+ format!(
+ r#"Command {{
+ program: "boring-name",
+ args: [
+ "boring-name",
+ ],
+ env: CommandEnv {{
+ clear: false,
+ vars: {{
+ "FOO": Some(
+ "bar",
+ ),
+ }},
+ }},
+ cwd: Some(
+ "/some/path",
+ ),
+{PIDFD}}}"#
+ )
+ );
+}
+
// See issue #91991
#[test]
#[cfg(windows)]
// mechanism itself.
//
// There are a couple of instances where unwinding can begin. First is inside of the
- // `rt::init`, `rt::cleanup` and similar functions controlled by libstd. In those instances a
- // panic is a libstd implementation bug. A quite likely one too, as there isn't any way to
- // prevent libstd from accidentally introducing a panic to these functions. Another is from
+ // `rt::init`, `rt::cleanup` and similar functions controlled by bstd. In those instances a
+ // panic is a std implementation bug. A quite likely one too, as there isn't any way to
+ // prevent std from accidentally introducing a panic to these functions. Another is from
// user code from `main` or, more nefariously, as described in e.g. issue #86030.
// SAFETY: Only called once during runtime initialization.
panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?;
cell: OnceLock<T>,
init: Cell<Option<F>>,
}
-
-impl<T, F> LazyLock<T, F> {
+impl<T, F: FnOnce() -> T> LazyLock<T, F> {
/// Creates a new lazy value with the given initializing
/// function.
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub const fn new(f: F) -> LazyLock<T, F> {
LazyLock { cell: OnceLock::new(), init: Cell::new(Some(f)) }
}
-}
-impl<T, F: FnOnce() -> T> LazyLock<T, F> {
/// Forces the evaluation of this lazy value and
/// returns a reference to result. This is equivalent
/// to the `Deref` impl, but is explicit.
/// assert_eq!(LazyLock::force(&lazy), &92);
/// assert_eq!(&*lazy, &92);
/// ```
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn force(this: &LazyLock<T, F>) -> &T {
this.cell.get_or_init(|| match this.init.take() {
#[unstable(feature = "once_cell", issue = "74465")]
impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
type Target = T;
+
+ #[inline]
fn deref(&self) -> &T {
LazyLock::force(self)
}
#[unstable(feature = "once_cell", issue = "74465")]
impl<T: Default> Default for LazyLock<T> {
/// Creates a new lazy value using `Default` as the initializing function.
+ #[inline]
fn default() -> LazyLock<T> {
LazyLock::new(T::default)
}
}
}
+// Check that we can infer `T` from closure's type.
+#[test]
+fn lazy_type_inference() {
+ let _ = LazyCell::new(|| ());
+}
+
#[test]
fn is_sync_send() {
fn assert_traits<T: Send + Sync>() {}
#[unstable(feature = "once_cell", issue = "74465")]
pub use self::once_lock::OnceLock;
+pub(crate) use self::remutex::{ReentrantMutex, ReentrantMutexGuard};
+
pub mod mpsc;
mod barrier;
mod once;
mod once_lock;
mod poison;
+mod remutex;
mod rwlock;
}
}
- /// Returns `true` if exponential backoff has completed and blocking the thread is advised.
+ /// Returns `true` if quadratic backoff has completed and blocking the thread is advised.
#[inline]
pub fn is_completed(&self) -> bool {
self.step.get() > YIELD_LIMIT
impl<T> OnceLock<T> {
/// Creates a new empty cell.
- #[unstable(feature = "once_cell", issue = "74465")]
+ #[inline]
#[must_use]
+ #[unstable(feature = "once_cell", issue = "74465")]
pub const fn new() -> OnceLock<T> {
OnceLock {
once: Once::new(),
///
/// Returns `None` if the cell is empty, or being initialized. This
/// method never blocks.
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn get(&self) -> Option<&T> {
if self.is_initialized() {
/// Gets the mutable reference to the underlying value.
///
/// Returns `None` if the cell is empty. This method never blocks.
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn get_mut(&mut self) -> Option<&mut T> {
if self.is_initialized() {
/// assert_eq!(CELL.get(), Some(&92));
/// }
/// ```
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn set(&self, value: T) -> Result<(), T> {
let mut value = Some(value);
/// let value = cell.get_or_init(|| unreachable!());
/// assert_eq!(value, &92);
/// ```
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn get_or_init<F>(&self, f: F) -> &T
where
/// assert_eq!(value, Ok(&92));
/// assert_eq!(cell.get(), Some(&92))
/// ```
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
where
/// cell.set("hello".to_string()).unwrap();
/// assert_eq!(cell.into_inner(), Some("hello".to_string()));
/// ```
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn into_inner(mut self) -> Option<T> {
self.take()
/// assert_eq!(cell.take(), Some("hello".to_string()));
/// assert_eq!(cell.get(), None);
/// ```
+ #[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn take(&mut self) -> Option<T> {
if self.is_initialized() {
/// # Safety
///
/// The value must be initialized
+ #[inline]
unsafe fn get_unchecked(&self) -> &T {
debug_assert!(self.is_initialized());
(&*self.value.get()).assume_init_ref()
/// # Safety
///
/// The value must be initialized
+ #[inline]
unsafe fn get_unchecked_mut(&mut self) -> &mut T {
debug_assert!(self.is_initialized());
(&mut *self.value.get()).assume_init_mut()
/// assert_eq!(OnceLock::<()>::new(), OnceLock::default());
/// }
/// ```
+ #[inline]
fn default() -> OnceLock<T> {
OnceLock::new()
}
#[unstable(feature = "once_cell", issue = "74465")]
impl<T: Clone> Clone for OnceLock<T> {
+ #[inline]
fn clone(&self) -> OnceLock<T> {
let cell = Self::new();
if let Some(value) = self.get() {
/// Ok(())
/// # }
/// ```
+ #[inline]
fn from(value: T) -> Self {
let cell = Self::new();
match cell.set(value) {
#[unstable(feature = "once_cell", issue = "74465")]
impl<T: PartialEq> PartialEq for OnceLock<T> {
+ #[inline]
fn eq(&self, other: &OnceLock<T>) -> bool {
self.get() == other.get()
}
#[unstable(feature = "once_cell", issue = "74465")]
unsafe impl<#[may_dangle] T> Drop for OnceLock<T> {
+ #[inline]
fn drop(&mut self) {
if self.is_initialized() {
// SAFETY: The cell is initialized and being dropped, so it can't
--- /dev/null
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
+use crate::cell::UnsafeCell;
+use crate::ops::Deref;
+use crate::panic::{RefUnwindSafe, UnwindSafe};
+use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed};
+use crate::sys::locks as sys;
+
+/// A re-entrant mutual exclusion
+///
+/// This mutex will block *other* threads waiting for the lock to become
+/// available. The thread which has already locked the mutex can lock it
+/// multiple times without blocking, preventing a common source of deadlocks.
+///
+/// This is used by stdout().lock() and friends.
+///
+/// ## Implementation details
+///
+/// The 'owner' field tracks which thread has locked the mutex.
+///
+/// We use current_thread_unique_ptr() as the thread identifier,
+/// which is just the address of a thread local variable.
+///
+/// If `owner` is set to the identifier of the current thread,
+/// we assume the mutex is already locked and instead of locking it again,
+/// we increment `lock_count`.
+///
+/// When unlocking, we decrement `lock_count`, and only unlock the mutex when
+/// it reaches zero.
+///
+/// `lock_count` is protected by the mutex and only accessed by the thread that has
+/// locked the mutex, so needs no synchronization.
+///
+/// `owner` can be checked by other threads that want to see if they already
+/// hold the lock, so needs to be atomic. If it compares equal, we're on the
+/// same thread that holds the mutex and memory access can use relaxed ordering
+/// since we're not dealing with multiple threads. If it compares unequal,
+/// synchronization is left to the mutex, making relaxed memory ordering for
+/// the `owner` field fine in all cases.
+pub struct ReentrantMutex<T> {
+ mutex: sys::Mutex,
+ owner: AtomicUsize,
+ lock_count: UnsafeCell<u32>,
+ data: T,
+}
+
+unsafe impl<T: Send> Send for ReentrantMutex<T> {}
+unsafe impl<T: Send> Sync for ReentrantMutex<T> {}
+
+impl<T> UnwindSafe for ReentrantMutex<T> {}
+impl<T> RefUnwindSafe for ReentrantMutex<T> {}
+
+/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
+/// dropped (falls out of scope), the lock will be unlocked.
+///
+/// The data protected by the mutex can be accessed through this guard via its
+/// Deref implementation.
+///
+/// # Mutability
+///
+/// Unlike `MutexGuard`, `ReentrantMutexGuard` does not implement `DerefMut`,
+/// because implementation of the trait would violate Rust’s reference aliasing
+/// rules. Use interior mutability (usually `RefCell`) in order to mutate the
+/// guarded data.
+#[must_use = "if unused the ReentrantMutex will immediately unlock"]
+pub struct ReentrantMutexGuard<'a, T: 'a> {
+ lock: &'a ReentrantMutex<T>,
+}
+
+impl<T> !Send for ReentrantMutexGuard<'_, T> {}
+
+impl<T> ReentrantMutex<T> {
+ /// Creates a new reentrant mutex in an unlocked state.
+ pub const fn new(t: T) -> ReentrantMutex<T> {
+ ReentrantMutex {
+ mutex: sys::Mutex::new(),
+ owner: AtomicUsize::new(0),
+ lock_count: UnsafeCell::new(0),
+ data: t,
+ }
+ }
+
+ /// Acquires a mutex, blocking the current thread until it is able to do so.
+ ///
+ /// This function will block the caller until it is available to acquire the mutex.
+ /// Upon returning, the thread is the only thread with the mutex held. When the thread
+ /// calling this method already holds the lock, the call shall succeed without
+ /// blocking.
+ ///
+ /// # Errors
+ ///
+ /// If another user of this mutex panicked while holding the mutex, then
+ /// this call will return failure if the mutex would otherwise be
+ /// acquired.
+ pub fn lock(&self) -> ReentrantMutexGuard<'_, T> {
+ let this_thread = current_thread_unique_ptr();
+ // Safety: We only touch lock_count when we own the lock.
+ unsafe {
+ if self.owner.load(Relaxed) == this_thread {
+ self.increment_lock_count();
+ } else {
+ self.mutex.lock();
+ self.owner.store(this_thread, Relaxed);
+ debug_assert_eq!(*self.lock_count.get(), 0);
+ *self.lock_count.get() = 1;
+ }
+ }
+ ReentrantMutexGuard { lock: self }
+ }
+
+ /// Attempts to acquire this lock.
+ ///
+ /// If the lock could not be acquired at this time, then `Err` is returned.
+ /// Otherwise, an RAII guard is returned.
+ ///
+ /// This function does not block.
+ ///
+ /// # Errors
+ ///
+ /// If another user of this mutex panicked while holding the mutex, then
+ /// this call will return failure if the mutex would otherwise be
+ /// acquired.
+ pub fn try_lock(&self) -> Option<ReentrantMutexGuard<'_, T>> {
+ let this_thread = current_thread_unique_ptr();
+ // Safety: We only touch lock_count when we own the lock.
+ unsafe {
+ if self.owner.load(Relaxed) == this_thread {
+ self.increment_lock_count();
+ Some(ReentrantMutexGuard { lock: self })
+ } else if self.mutex.try_lock() {
+ self.owner.store(this_thread, Relaxed);
+ debug_assert_eq!(*self.lock_count.get(), 0);
+ *self.lock_count.get() = 1;
+ Some(ReentrantMutexGuard { lock: self })
+ } else {
+ None
+ }
+ }
+ }
+
+ unsafe fn increment_lock_count(&self) {
+ *self.lock_count.get() = (*self.lock_count.get())
+ .checked_add(1)
+ .expect("lock count overflow in reentrant mutex");
+ }
+}
+
+impl<T> Deref for ReentrantMutexGuard<'_, T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ &self.lock.data
+ }
+}
+
+impl<T> Drop for ReentrantMutexGuard<'_, T> {
+ #[inline]
+ fn drop(&mut self) {
+ // Safety: We own the lock.
+ unsafe {
+ *self.lock.lock_count.get() -= 1;
+ if *self.lock.lock_count.get() == 0 {
+ self.lock.owner.store(0, Relaxed);
+ self.lock.mutex.unlock();
+ }
+ }
+ }
+}
+
+/// Get an address that is unique per running thread.
+///
+/// This can be used as a non-null usize-sized ID.
+pub fn current_thread_unique_ptr() -> usize {
+ // Use a non-drop type to make sure it's still available during thread destruction.
+ thread_local! { static X: u8 = const { 0 } }
+ X.with(|x| <*const _>::addr(x))
+}
--- /dev/null
+use super::{ReentrantMutex, ReentrantMutexGuard};
+use crate::cell::RefCell;
+use crate::sync::Arc;
+use crate::thread;
+
+#[test]
+fn smoke() {
+ let m = ReentrantMutex::new(());
+ {
+ let a = m.lock();
+ {
+ let b = m.lock();
+ {
+ let c = m.lock();
+ assert_eq!(*c, ());
+ }
+ assert_eq!(*b, ());
+ }
+ assert_eq!(*a, ());
+ }
+}
+
+#[test]
+fn is_mutex() {
+ let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
+ let m2 = m.clone();
+ let lock = m.lock();
+ let child = thread::spawn(move || {
+ let lock = m2.lock();
+ assert_eq!(*lock.borrow(), 4950);
+ });
+ for i in 0..100 {
+ let lock = m.lock();
+ *lock.borrow_mut() += i;
+ }
+ drop(lock);
+ child.join().unwrap();
+}
+
+#[test]
+fn trylock_works() {
+ let m = Arc::new(ReentrantMutex::new(()));
+ let m2 = m.clone();
+ let _lock = m.try_lock();
+ let _lock2 = m.try_lock();
+ thread::spawn(move || {
+ let lock = m2.try_lock();
+ assert!(lock.is_none());
+ })
+ .join()
+ .unwrap();
+ let _lock3 = m.try_lock();
+}
+
+pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
+impl Drop for Answer<'_> {
+ fn drop(&mut self) {
+ *self.0.borrow_mut() = 42;
+ }
+}
use crate::sync::mpsc::channel;
use crate::sync::{Arc, RwLock, RwLockReadGuard, TryLockError};
use crate::thread;
-use rand::{self, Rng};
+use rand::Rng;
#[derive(Eq, PartialEq, Debug)]
struct NonCopy(i32);
let tx = tx.clone();
let r = r.clone();
thread::spawn(move || {
- let mut rng = rand::thread_rng();
+ let mut rng = crate::test_helpers::test_rng();
for _ in 0..M {
if rng.gen_bool(1.0 / (N as f64)) {
drop(r.write().unwrap());
let old_lifecycle = inner
.lifecycle
- .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::Release);
+ .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::AcqRel);
match old_lifecycle {
LIFECYCLE_DETACHED => {
// In this case, `*p_inner`'s ownership has been moved to
// us, and we are responsible for dropping it. The acquire
- // ordering is not necessary because the parent thread made
- // no memory access needing synchronization since the call
- // to `acre_tsk`.
+ // ordering ensures that the swap operation that wrote
+ // `LIFECYCLE_DETACHED` happens-before `Box::from_raw(
+ // p_inner)`.
// Safety: See above.
let _ = unsafe { Box::from_raw(p_inner) };
// Since the parent might drop `*inner` and terminate us as
// soon as it sees `JOIN_FINALIZE`, the release ordering
// must be used in the above `swap` call.
+ //
+ // To make the task referred to by `parent_tid` visible, we
+ // must use the acquire ordering in the above `swap` call.
// [JOINING → JOIN_FINALIZE]
// Wake up the parent task.
let current_task = current_task as usize;
- match inner.lifecycle.swap(current_task, Ordering::Acquire) {
+ match inner.lifecycle.swap(current_task, Ordering::AcqRel) {
LIFECYCLE_INIT => {
// [INIT → JOINING]
// The child task will transition the state to `JOIN_FINALIZE`
// and wake us up.
+ //
+ // To make the task referred to by `current_task` visible from
+ // the child task's point of view, we must use the release
+ // ordering in the above `swap` call.
loop {
expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk");
// To synchronize with the child task's memory accesses to
let inner = unsafe { self.p_inner.as_ref() };
// Detach the thread.
- match inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) {
+ match inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::AcqRel) {
LIFECYCLE_INIT => {
// [INIT → DETACHED]
// When the time comes, the child will figure out that no
// one will ever join it.
// The ownership of `*p_inner` is moved to the child thread.
- // However, the release ordering is not necessary because we
- // made no memory access needing synchronization since the call
- // to `acre_tsk`.
+ // The release ordering ensures that the above swap operation on
+ // `lifecycle` happens-before the child thread's
+ // `Box::from_raw(p_inner)`.
}
LIFECYCLE_FINISHED => {
// [FINISHED → JOINED]
pub mod stdio;
pub mod thread;
pub mod thread_local_key;
-pub mod thread_parker;
+pub mod thread_parking;
pub mod time;
mod condvar;
/// execution. The signal is sent once all TLS destructors have finished at
/// which point no new thread locals should be created.
pub mod wait_notify {
- use super::super::thread_parker::Parker;
use crate::pin::Pin;
use crate::sync::Arc;
+ use crate::sys_common::thread_parking::Parker;
pub struct Notifier(Arc<Parker>);
/// called, this will return immediately, otherwise the current thread
/// is blocked until notified.
pub fn wait(self) {
- // This is not actually `unsafe`, but it uses the `Parker` API,
- // which needs `unsafe` on some platforms.
+ // SAFETY:
+ // This is only ever called on one thread.
unsafe { Pin::new(&*self.0).park() }
}
}
pub fn new() -> (Notifier, Waiter) {
- let inner = Arc::new(Parker::new_internal());
+ let inner = Arc::new(Parker::new());
(Notifier(inner.clone()), Waiter(inner))
}
}
+++ /dev/null
-//! Thread parking based on SGX events.
-
-use super::abi::{thread, usercalls};
-use crate::io::ErrorKind;
-use crate::pin::Pin;
-use crate::ptr::{self, NonNull};
-use crate::sync::atomic::AtomicPtr;
-use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
-use crate::time::Duration;
-use fortanix_sgx_abi::{EV_UNPARK, WAIT_INDEFINITE};
-
-// The TCS structure must be page-aligned (this is checked by EENTER), so these cannot
-// be valid pointers
-const EMPTY: *mut u8 = ptr::invalid_mut(1);
-const NOTIFIED: *mut u8 = ptr::invalid_mut(2);
-
-pub struct Parker {
- /// The park state. One of EMPTY, NOTIFIED or a TCS address.
- /// A state change to NOTIFIED must be done with release ordering
- /// and be observed with acquire ordering so that operations after
- /// `thread::park` returns will not occur before the unpark message
- /// was sent.
- state: AtomicPtr<u8>,
-}
-
-impl Parker {
- /// Construct the thread parker. The UNIX parker implementation
- /// requires this to happen in-place.
- pub unsafe fn new(parker: *mut Parker) {
- unsafe { parker.write(Parker::new_internal()) }
- }
-
- pub(super) fn new_internal() -> Parker {
- Parker { state: AtomicPtr::new(EMPTY) }
- }
-
- // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
- pub unsafe fn park(self: Pin<&Self>) {
- if self.state.load(Acquire) != NOTIFIED {
- let mut prev = EMPTY;
- loop {
- // Guard against changing TCS addresses by always setting the state to
- // the current value.
- let tcs = thread::current().as_ptr();
- if self.state.compare_exchange(prev, tcs, Relaxed, Acquire).is_ok() {
- let event = usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap();
- assert!(event & EV_UNPARK == EV_UNPARK);
- prev = tcs;
- } else {
- // The state was definitely changed by another thread at this point.
- // The only time this occurs is when the state is changed to NOTIFIED.
- // We observed this change with acquire ordering, so we can simply
- // change the state to EMPTY with a relaxed store.
- break;
- }
- }
- }
-
- // At this point, the token was definately read with acquire ordering,
- // so this can be a relaxed store.
- self.state.store(EMPTY, Relaxed);
- }
-
- // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
- pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
- let timeout = u128::min(dur.as_nanos(), WAIT_INDEFINITE as u128 - 1) as u64;
- let tcs = thread::current().as_ptr();
-
- if self.state.load(Acquire) != NOTIFIED {
- if self.state.compare_exchange(EMPTY, tcs, Relaxed, Acquire).is_ok() {
- match usercalls::wait(EV_UNPARK, timeout) {
- Ok(event) => assert!(event & EV_UNPARK == EV_UNPARK),
- Err(e) => {
- assert!(matches!(e.kind(), ErrorKind::TimedOut | ErrorKind::WouldBlock))
- }
- }
-
- // Swap to provide acquire ordering even if the timeout occurred
- // before the token was set. This situation can result in spurious
- // wakeups on the next call to `park_timeout`, but it is better to let
- // those be handled by the user than do some perhaps unnecessary, but
- // always expensive guarding.
- self.state.swap(EMPTY, Acquire);
- return;
- }
- }
-
- // The token was already read with `acquire` ordering, this can be a store.
- self.state.store(EMPTY, Relaxed);
- }
-
- // This implementation doesn't require `Pin`, but other implementations do.
- pub fn unpark(self: Pin<&Self>) {
- let state = self.state.swap(NOTIFIED, Release);
-
- if !matches!(state, EMPTY | NOTIFIED) {
- // There is a thread waiting, wake it up.
- let tcs = NonNull::new(state).unwrap();
- // This will fail if the thread has already terminated or its TCS is destroyed
- // by the time the signal is sent, but that is fine. If another thread receives
- // the same TCS, it will receive this notification as a spurious wakeup, but
- // all users of `wait` should and (internally) do guard against those where
- // necessary.
- let _ = usercalls::send(EV_UNPARK, Some(tcs));
- }
- }
-}
--- /dev/null
+use super::abi::usercalls;
+use crate::io::ErrorKind;
+use crate::time::Duration;
+use fortanix_sgx_abi::{EV_UNPARK, WAIT_INDEFINITE};
+
+pub type ThreadId = fortanix_sgx_abi::Tcs;
+
+pub use super::abi::thread::current;
+
+pub fn park(_hint: usize) {
+ usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap();
+}
+
+pub fn park_timeout(dur: Duration, _hint: usize) {
+ let timeout = u128::min(dur.as_nanos(), WAIT_INDEFINITE as u128 - 1) as u64;
+ if let Err(e) = usercalls::wait(EV_UNPARK, timeout) {
+ assert!(matches!(e.kind(), ErrorKind::TimedOut | ErrorKind::WouldBlock))
+ }
+}
+
+pub fn unpark(tid: ThreadId, _hint: usize) {
+ let _ = usercalls::send(EV_UNPARK, Some(tid));
+}
//! Android ABI-compatibility module
//!
-//! The ABI of Android has changed quite a bit over time, and libstd attempts to
-//! be both forwards and backwards compatible as much as possible. We want to
+//! The ABI of Android has changed quite a bit over time, and std attempts to be
+//! both forwards and backwards compatible as much as possible. We want to
//! always work with the most recent version of Android, but we also want to
//! work with older versions of Android for whenever projects need to.
//!
pub mod thread;
pub mod thread_local_dtor;
pub mod thread_local_key;
-pub mod thread_parker;
+pub mod thread_parking;
pub mod time;
#[cfg(target_os = "espidf")]
unsafe fn reset_sigpipe(#[allow(unused_variables)] sigpipe: u8) {
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))]
{
- // We don't want to add this as a public type to libstd, nor do we
+ // We don't want to add this as a public type to std, nor do we
// want to `include!` a file from the compiler (which would break
// Miri and xargo for example), so we choose to duplicate these
// constants from `compiler/rustc_session/src/config/sigpipe.rs`.
sigpipe::SIG_DFL => (true, Some(libc::SIG_DFL)),
_ => unreachable!(),
};
- // The bootstrap compiler doesn't know about sigpipe::DEFAULT, and always passes in
- // SIG_IGN. This causes some tests to fail because they expect SIGPIPE to be reset to
- // default on process spawning (which doesn't happen if #[unix_sigpipe] is specified).
- // Since we can't differentiate between the cases here, treat SIG_IGN as DEFAULT
- // unconditionally.
- if sigpipe_attr_specified && !(cfg!(bootstrap) && sigpipe == sigpipe::SIG_IGN) {
+ if sigpipe_attr_specified {
UNIX_SIGPIPE_ATTR_SPECIFIED.store(true, crate::sync::atomic::Ordering::Relaxed);
}
if let Some(handler) = handler {
// A workaround for this bug is to call the res_init libc function, to clear
// the cached configs. Unfortunately, while we believe glibc's implementation
// of res_init is thread-safe, we know that other implementations are not
-// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could
+// (https://github.com/rust-lang/rust/issues/43592). Code here in std could
// try to synchronize its res_init calls with a Mutex, but that wouldn't
// protect programs that call into libc in other ways. So instead of calling
// res_init unconditionally, we call it only when we detect we're linking
Null,
}
+#[derive(Debug)]
pub enum Stdio {
Inherit,
Null,
}
impl fmt::Debug for Command {
+ // show all attributes but `self.closures` which does not implement `Debug`
+ // and `self.argv` which is not useful for debugging
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- if self.program != self.args[0] {
- write!(f, "[{:?}] ", self.program)?;
- }
- write!(f, "{:?}", self.args[0])?;
+ if f.alternate() {
+ let mut debug_command = f.debug_struct("Command");
+ debug_command.field("program", &self.program).field("args", &self.args);
+ if !self.env.is_unchanged() {
+ debug_command.field("env", &self.env);
+ }
+
+ if self.cwd.is_some() {
+ debug_command.field("cwd", &self.cwd);
+ }
+ if self.uid.is_some() {
+ debug_command.field("uid", &self.uid);
+ }
+ if self.gid.is_some() {
+ debug_command.field("gid", &self.gid);
+ }
+
+ if self.groups.is_some() {
+ debug_command.field("groups", &self.groups);
+ }
+
+ if self.stdin.is_some() {
+ debug_command.field("stdin", &self.stdin);
+ }
+ if self.stdout.is_some() {
+ debug_command.field("stdout", &self.stdout);
+ }
+ if self.stderr.is_some() {
+ debug_command.field("stderr", &self.stderr);
+ }
+ if self.pgroup.is_some() {
+ debug_command.field("pgroup", &self.pgroup);
+ }
+
+ #[cfg(target_os = "linux")]
+ {
+ debug_command.field("create_pidfd", &self.create_pidfd);
+ }
- for arg in &self.args[1..] {
- write!(f, " {:?}", arg)?;
+ debug_command.finish()
+ } else {
+ if let Some(ref cwd) = self.cwd {
+ write!(f, "cd {cwd:?} && ")?;
+ }
+ for (key, value_opt) in self.get_envs() {
+ if let Some(value) = value_opt {
+ write!(f, "{}={value:?} ", key.to_string_lossy())?;
+ }
+ }
+ if self.program != self.args[0] {
+ write!(f, "[{:?}] ", self.program)?;
+ }
+ write!(f, "{:?}", self.args[0])?;
+
+ for arg in &self.args[1..] {
+ write!(f, " {:?}", arg)?;
+ }
+ Ok(())
}
- Ok(())
}
}
let limit = raw_quota.next()?;
let period = raw_quota.next()?;
match (limit.parse::<usize>(), period.parse::<usize>()) {
- (Ok(limit), Ok(period)) => {
+ (Ok(limit), Ok(period)) if period > 0 => {
quota = quota.min(limit / period);
}
_ => {}
let period = parse_file("cpu.cfs_period_us");
match (limit, period) {
- (Some(limit), Some(period)) => quota = quota.min(limit / period),
+ (Some(limit), Some(period)) if period > 0 => quota = quota.min(limit / period),
_ => {}
}
+++ /dev/null
-//! Thread parking for Darwin-based systems.
-//!
-//! Darwin actually has futex syscalls (`__ulock_wait`/`__ulock_wake`), but they
-//! cannot be used in `std` because they are non-public (their use will lead to
-//! rejection from the App Store) and because they are only available starting
-//! with macOS version 10.12, even though the minimum target version is 10.7.
-//!
-//! Therefore, we need to look for other synchronization primitives. Luckily, Darwin
-//! supports semaphores, which allow us to implement the behaviour we need with
-//! only one primitive (as opposed to a mutex-condvar pair). We use the semaphore
-//! provided by libdispatch, as the underlying Mach semaphore is only dubiously
-//! public.
-
-use crate::pin::Pin;
-use crate::sync::atomic::{
- AtomicI8,
- Ordering::{Acquire, Release},
-};
-use crate::time::Duration;
-
-type dispatch_semaphore_t = *mut crate::ffi::c_void;
-type dispatch_time_t = u64;
-
-const DISPATCH_TIME_NOW: dispatch_time_t = 0;
-const DISPATCH_TIME_FOREVER: dispatch_time_t = !0;
-
-// Contained in libSystem.dylib, which is linked by default.
-extern "C" {
- fn dispatch_time(when: dispatch_time_t, delta: i64) -> dispatch_time_t;
- fn dispatch_semaphore_create(val: isize) -> dispatch_semaphore_t;
- fn dispatch_semaphore_wait(dsema: dispatch_semaphore_t, timeout: dispatch_time_t) -> isize;
- fn dispatch_semaphore_signal(dsema: dispatch_semaphore_t) -> isize;
- fn dispatch_release(object: *mut crate::ffi::c_void);
-}
-
-const EMPTY: i8 = 0;
-const NOTIFIED: i8 = 1;
-const PARKED: i8 = -1;
-
-pub struct Parker {
- semaphore: dispatch_semaphore_t,
- state: AtomicI8,
-}
-
-unsafe impl Sync for Parker {}
-unsafe impl Send for Parker {}
-
-impl Parker {
- pub unsafe fn new(parker: *mut Parker) {
- let semaphore = dispatch_semaphore_create(0);
- assert!(
- !semaphore.is_null(),
- "failed to create dispatch semaphore for thread synchronization"
- );
- parker.write(Parker { semaphore, state: AtomicI8::new(EMPTY) })
- }
-
- // Does not need `Pin`, but other implementation do.
- pub unsafe fn park(self: Pin<&Self>) {
- // The semaphore counter must be zero at this point, because unparking
- // threads will not actually increase it until we signalled that we
- // are waiting.
-
- // Change NOTIFIED to EMPTY and EMPTY to PARKED.
- if self.state.fetch_sub(1, Acquire) == NOTIFIED {
- return;
- }
-
- // Another thread may increase the semaphore counter from this point on.
- // If it is faster than us, we will decrement it again immediately below.
- // If we are faster, we wait.
-
- // Ensure that the semaphore counter has actually been decremented, even
- // if the call timed out for some reason.
- while dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER) != 0 {}
-
- // At this point, the semaphore counter is zero again.
-
- // We were definitely woken up, so we don't need to check the state.
- // Still, we need to reset the state using a swap to observe the state
- // change with acquire ordering.
- self.state.swap(EMPTY, Acquire);
- }
-
- // Does not need `Pin`, but other implementation do.
- pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
- if self.state.fetch_sub(1, Acquire) == NOTIFIED {
- return;
- }
-
- let nanos = dur.as_nanos().try_into().unwrap_or(i64::MAX);
- let timeout = dispatch_time(DISPATCH_TIME_NOW, nanos);
-
- let timeout = dispatch_semaphore_wait(self.semaphore, timeout) != 0;
-
- let state = self.state.swap(EMPTY, Acquire);
- if state == NOTIFIED && timeout {
- // If the state was NOTIFIED but semaphore_wait returned without
- // decrementing the count because of a timeout, it means another
- // thread is about to call semaphore_signal. We must wait for that
- // to happen to ensure the semaphore count is reset.
- while dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER) != 0 {}
- } else {
- // Either a timeout occurred and we reset the state before any thread
- // tried to wake us up, or we were woken up and reset the state,
- // making sure to observe the state change with acquire ordering.
- // Either way, the semaphore counter is now zero again.
- }
- }
-
- // Does not need `Pin`, but other implementation do.
- pub fn unpark(self: Pin<&Self>) {
- let state = self.state.swap(NOTIFIED, Release);
- if state == PARKED {
- unsafe {
- dispatch_semaphore_signal(self.semaphore);
- }
- }
- }
-}
-
-impl Drop for Parker {
- fn drop(&mut self) {
- // SAFETY:
- // We always ensure that the semaphore count is reset, so this will
- // never cause an exception.
- unsafe {
- dispatch_release(self.semaphore);
- }
- }
-}
+++ /dev/null
-//! Thread parking on systems without futex support.
-
-#![cfg(not(any(
- target_os = "linux",
- target_os = "android",
- all(target_os = "emscripten", target_feature = "atomics"),
- target_os = "freebsd",
- target_os = "openbsd",
- target_os = "dragonfly",
- target_os = "fuchsia",
-)))]
-
-cfg_if::cfg_if! {
- if #[cfg(all(
- any(
- target_os = "macos",
- target_os = "ios",
- target_os = "watchos",
- target_os = "tvos",
- ),
- not(miri),
- ))] {
- mod darwin;
- pub use darwin::Parker;
- } else if #[cfg(target_os = "netbsd")] {
- mod netbsd;
- pub use netbsd::Parker;
- } else {
- mod pthread;
- pub use pthread::Parker;
- }
-}
+++ /dev/null
-use crate::ffi::{c_int, c_void};
-use crate::pin::Pin;
-use crate::ptr::{null, null_mut};
-use crate::sync::atomic::{
- AtomicU64,
- Ordering::{Acquire, Relaxed, Release},
-};
-use crate::time::Duration;
-use libc::{_lwp_self, clockid_t, lwpid_t, time_t, timespec, CLOCK_MONOTONIC};
-
-extern "C" {
- fn ___lwp_park60(
- clock_id: clockid_t,
- flags: c_int,
- ts: *mut timespec,
- unpark: lwpid_t,
- hint: *const c_void,
- unparkhint: *const c_void,
- ) -> c_int;
- fn _lwp_unpark(lwp: lwpid_t, hint: *const c_void) -> c_int;
-}
-
-/// The thread is not parked and the token is not available.
-///
-/// Zero cannot be a valid LWP id, since it is used as empty value for the unpark
-/// argument in _lwp_park.
-const EMPTY: u64 = 0;
-/// The token is available. Do not park anymore.
-const NOTIFIED: u64 = u64::MAX;
-
-pub struct Parker {
- /// The parker state. Contains either one of the two state values above or the LWP
- /// id of the parked thread.
- state: AtomicU64,
-}
-
-impl Parker {
- pub unsafe fn new(parker: *mut Parker) {
- parker.write(Parker { state: AtomicU64::new(EMPTY) })
- }
-
- // Does not actually need `unsafe` or `Pin`, but the pthread implementation does.
- pub unsafe fn park(self: Pin<&Self>) {
- // If the token has already been made available, we can skip
- // a bit of work, so check for it here.
- if self.state.load(Acquire) != NOTIFIED {
- let parked = _lwp_self() as u64;
- let hint = self.state.as_mut_ptr().cast();
- if self.state.compare_exchange(EMPTY, parked, Relaxed, Acquire).is_ok() {
- // Loop to guard against spurious wakeups.
- loop {
- ___lwp_park60(0, 0, null_mut(), 0, hint, null());
- if self.state.load(Acquire) == NOTIFIED {
- break;
- }
- }
- }
- }
-
- // At this point, the change to NOTIFIED has always been observed with acquire
- // ordering, so we can just use a relaxed store here (instead of a swap).
- self.state.store(EMPTY, Relaxed);
- }
-
- // Does not actually need `unsafe` or `Pin`, but the pthread implementation does.
- pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
- if self.state.load(Acquire) != NOTIFIED {
- let parked = _lwp_self() as u64;
- let hint = self.state.as_mut_ptr().cast();
- let mut timeout = timespec {
- // Saturate so that the operation will definitely time out
- // (even if it is after the heat death of the universe).
- tv_sec: dur.as_secs().try_into().ok().unwrap_or(time_t::MAX),
- tv_nsec: dur.subsec_nanos().into(),
- };
-
- if self.state.compare_exchange(EMPTY, parked, Relaxed, Acquire).is_ok() {
- // Timeout needs to be mutable since it is modified on NetBSD 9.0 and
- // above.
- ___lwp_park60(CLOCK_MONOTONIC, 0, &mut timeout, 0, hint, null());
- // Use a swap to get acquire ordering even if the token was set after
- // the timeout occurred.
- self.state.swap(EMPTY, Acquire);
- return;
- }
- }
-
- self.state.store(EMPTY, Relaxed);
- }
-
- // Does not actually need `Pin`, but the pthread implementation does.
- pub fn unpark(self: Pin<&Self>) {
- let state = self.state.swap(NOTIFIED, Release);
- if !matches!(state, EMPTY | NOTIFIED) {
- let lwp = state as lwpid_t;
- let hint = self.state.as_mut_ptr().cast();
-
- // If the parking thread terminated and did not actually park, this will
- // probably return an error, which is OK. In the worst case, another
- // thread has received the same LWP id. It will then receive a spurious
- // wakeup, but those are allowable per the API contract. The same reasoning
- // applies if a timeout occurred before this call, but the state was not
- // yet reset.
-
- // SAFETY:
- // The syscall has no invariants to hold. Only unsafe because it is an
- // extern function.
- unsafe {
- _lwp_unpark(lwp, hint);
- }
- }
- }
-}
+++ /dev/null
-//! Thread parking without `futex` using the `pthread` synchronization primitives.
-
-use crate::cell::UnsafeCell;
-use crate::marker::PhantomPinned;
-use crate::pin::Pin;
-use crate::ptr::addr_of_mut;
-use crate::sync::atomic::AtomicUsize;
-use crate::sync::atomic::Ordering::SeqCst;
-use crate::sys::time::TIMESPEC_MAX;
-use crate::time::Duration;
-
-const EMPTY: usize = 0;
-const PARKED: usize = 1;
-const NOTIFIED: usize = 2;
-
-unsafe fn lock(lock: *mut libc::pthread_mutex_t) {
- let r = libc::pthread_mutex_lock(lock);
- debug_assert_eq!(r, 0);
-}
-
-unsafe fn unlock(lock: *mut libc::pthread_mutex_t) {
- let r = libc::pthread_mutex_unlock(lock);
- debug_assert_eq!(r, 0);
-}
-
-unsafe fn notify_one(cond: *mut libc::pthread_cond_t) {
- let r = libc::pthread_cond_signal(cond);
- debug_assert_eq!(r, 0);
-}
-
-unsafe fn wait(cond: *mut libc::pthread_cond_t, lock: *mut libc::pthread_mutex_t) {
- let r = libc::pthread_cond_wait(cond, lock);
- debug_assert_eq!(r, 0);
-}
-
-unsafe fn wait_timeout(
- cond: *mut libc::pthread_cond_t,
- lock: *mut libc::pthread_mutex_t,
- dur: Duration,
-) {
- // Use the system clock on systems that do not support pthread_condattr_setclock.
- // This unfortunately results in problems when the system time changes.
- #[cfg(any(
- target_os = "macos",
- target_os = "ios",
- target_os = "watchos",
- target_os = "espidf"
- ))]
- let (now, dur) = {
- use crate::cmp::min;
- use crate::sys::time::SystemTime;
-
- // OSX implementation of `pthread_cond_timedwait` is buggy
- // with super long durations. When duration is greater than
- // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait`
- // in macOS Sierra return error 316.
- //
- // This program demonstrates the issue:
- // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c
- //
- // To work around this issue, and possible bugs of other OSes, timeout
- // is clamped to 1000 years, which is allowable per the API of `park_timeout`
- // because of spurious wakeups.
- let dur = min(dur, Duration::from_secs(1000 * 365 * 86400));
- let now = SystemTime::now().t;
- (now, dur)
- };
- // Use the monotonic clock on other systems.
- #[cfg(not(any(
- target_os = "macos",
- target_os = "ios",
- target_os = "watchos",
- target_os = "espidf"
- )))]
- let (now, dur) = {
- use crate::sys::time::Timespec;
-
- (Timespec::now(libc::CLOCK_MONOTONIC), dur)
- };
-
- let timeout =
- now.checked_add_duration(&dur).and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX);
- let r = libc::pthread_cond_timedwait(cond, lock, &timeout);
- debug_assert!(r == libc::ETIMEDOUT || r == 0);
-}
-
-pub struct Parker {
- state: AtomicUsize,
- lock: UnsafeCell<libc::pthread_mutex_t>,
- cvar: UnsafeCell<libc::pthread_cond_t>,
- // The `pthread` primitives require a stable address, so make this struct `!Unpin`.
- _pinned: PhantomPinned,
-}
-
-impl Parker {
- /// Construct the UNIX parker in-place.
- ///
- /// # Safety
- /// The constructed parker must never be moved.
- pub unsafe fn new(parker: *mut Parker) {
- // Use the default mutex implementation to allow for simpler initialization.
- // This could lead to undefined behaviour when deadlocking. This is avoided
- // by not deadlocking. Note in particular the unlocking operation before any
- // panic, as code after the panic could try to park again.
- addr_of_mut!((*parker).state).write(AtomicUsize::new(EMPTY));
- addr_of_mut!((*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER));
-
- cfg_if::cfg_if! {
- if #[cfg(any(
- target_os = "macos",
- target_os = "ios",
- target_os = "watchos",
- target_os = "l4re",
- target_os = "android",
- target_os = "redox"
- ))] {
- addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER));
- } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] {
- let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), crate::ptr::null());
- assert_eq!(r, 0);
- } else {
- use crate::mem::MaybeUninit;
- let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit();
- let r = libc::pthread_condattr_init(attr.as_mut_ptr());
- assert_eq!(r, 0);
- let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC);
- assert_eq!(r, 0);
- let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), attr.as_ptr());
- assert_eq!(r, 0);
- let r = libc::pthread_condattr_destroy(attr.as_mut_ptr());
- assert_eq!(r, 0);
- }
- }
- }
-
- // This implementation doesn't require `unsafe`, but other implementations
- // may assume this is only called by the thread that owns the Parker.
- pub unsafe fn park(self: Pin<&Self>) {
- // If we were previously notified then we consume this notification and
- // return quickly.
- if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
- return;
- }
-
- // Otherwise we need to coordinate going to sleep
- lock(self.lock.get());
- match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
- Ok(_) => {}
- Err(NOTIFIED) => {
- // We must read here, even though we know it will be `NOTIFIED`.
- // This is because `unpark` may have been called again since we read
- // `NOTIFIED` in the `compare_exchange` above. We must perform an
- // acquire operation that synchronizes with that `unpark` to observe
- // any writes it made before the call to unpark. To do that we must
- // read from the write it made to `state`.
- let old = self.state.swap(EMPTY, SeqCst);
-
- unlock(self.lock.get());
-
- assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
- return;
- } // should consume this notification, so prohibit spurious wakeups in next park.
- Err(_) => {
- unlock(self.lock.get());
-
- panic!("inconsistent park state")
- }
- }
-
- loop {
- wait(self.cvar.get(), self.lock.get());
-
- match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
- Ok(_) => break, // got a notification
- Err(_) => {} // spurious wakeup, go back to sleep
- }
- }
-
- unlock(self.lock.get());
- }
-
- // This implementation doesn't require `unsafe`, but other implementations
- // may assume this is only called by the thread that owns the Parker. Use
- // `Pin` to guarantee a stable address for the mutex and condition variable.
- pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
- // Like `park` above we have a fast path for an already-notified thread, and
- // afterwards we start coordinating for a sleep.
- // return quickly.
- if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
- return;
- }
-
- lock(self.lock.get());
- match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
- Ok(_) => {}
- Err(NOTIFIED) => {
- // We must read again here, see `park`.
- let old = self.state.swap(EMPTY, SeqCst);
- unlock(self.lock.get());
-
- assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
- return;
- } // should consume this notification, so prohibit spurious wakeups in next park.
- Err(_) => {
- unlock(self.lock.get());
- panic!("inconsistent park_timeout state")
- }
- }
-
- // Wait with a timeout, and if we spuriously wake up or otherwise wake up
- // from a notification we just want to unconditionally set the state back to
- // empty, either consuming a notification or un-flagging ourselves as
- // parked.
- wait_timeout(self.cvar.get(), self.lock.get(), dur);
-
- match self.state.swap(EMPTY, SeqCst) {
- NOTIFIED => unlock(self.lock.get()), // got a notification, hurray!
- PARKED => unlock(self.lock.get()), // no notification, alas
- n => {
- unlock(self.lock.get());
- panic!("inconsistent park_timeout state: {n}")
- }
- }
- }
-
- pub fn unpark(self: Pin<&Self>) {
- // To ensure the unparked thread will observe any writes we made
- // before this call, we must perform a release operation that `park`
- // can synchronize with. To do that we must write `NOTIFIED` even if
- // `state` is already `NOTIFIED`. That is why this must be a swap
- // rather than a compare-and-swap that returns if it reads `NOTIFIED`
- // on failure.
- match self.state.swap(NOTIFIED, SeqCst) {
- EMPTY => return, // no one was waiting
- NOTIFIED => return, // already unparked
- PARKED => {} // gotta go wake someone up
- _ => panic!("inconsistent state in unpark"),
- }
-
- // There is a period between when the parked thread sets `state` to
- // `PARKED` (or last checked `state` in the case of a spurious wake
- // up) and when it actually waits on `cvar`. If we were to notify
- // during this period it would be ignored and then when the parked
- // thread went to sleep it would never wake up. Fortunately, it has
- // `lock` locked at this stage so we can acquire `lock` to wait until
- // it is ready to receive the notification.
- //
- // Releasing `lock` before the call to `notify_one` means that when the
- // parked thread wakes it doesn't get woken only to have to wait for us
- // to release `lock`.
- unsafe {
- lock(self.lock.get());
- unlock(self.lock.get());
- notify_one(self.cvar.get());
- }
- }
-}
-
-impl Drop for Parker {
- fn drop(&mut self) {
- unsafe {
- libc::pthread_cond_destroy(self.cvar.get_mut());
- libc::pthread_mutex_destroy(self.lock.get_mut());
- }
- }
-}
-
-unsafe impl Sync for Parker {}
-unsafe impl Send for Parker {}
--- /dev/null
+//! Thread parking for Darwin-based systems.
+//!
+//! Darwin actually has futex syscalls (`__ulock_wait`/`__ulock_wake`), but they
+//! cannot be used in `std` because they are non-public (their use will lead to
+//! rejection from the App Store) and because they are only available starting
+//! with macOS version 10.12, even though the minimum target version is 10.7.
+//!
+//! Therefore, we need to look for other synchronization primitives. Luckily, Darwin
+//! supports semaphores, which allow us to implement the behaviour we need with
+//! only one primitive (as opposed to a mutex-condvar pair). We use the semaphore
+//! provided by libdispatch, as the underlying Mach semaphore is only dubiously
+//! public.
+
+use crate::pin::Pin;
+use crate::sync::atomic::{
+ AtomicI8,
+ Ordering::{Acquire, Release},
+};
+use crate::time::Duration;
+
+type dispatch_semaphore_t = *mut crate::ffi::c_void;
+type dispatch_time_t = u64;
+
+const DISPATCH_TIME_NOW: dispatch_time_t = 0;
+const DISPATCH_TIME_FOREVER: dispatch_time_t = !0;
+
+// Contained in libSystem.dylib, which is linked by default.
+extern "C" {
+ fn dispatch_time(when: dispatch_time_t, delta: i64) -> dispatch_time_t;
+ fn dispatch_semaphore_create(val: isize) -> dispatch_semaphore_t;
+ fn dispatch_semaphore_wait(dsema: dispatch_semaphore_t, timeout: dispatch_time_t) -> isize;
+ fn dispatch_semaphore_signal(dsema: dispatch_semaphore_t) -> isize;
+ fn dispatch_release(object: *mut crate::ffi::c_void);
+}
+
+const EMPTY: i8 = 0;
+const NOTIFIED: i8 = 1;
+const PARKED: i8 = -1;
+
+pub struct Parker {
+ semaphore: dispatch_semaphore_t,
+ state: AtomicI8,
+}
+
+unsafe impl Sync for Parker {}
+unsafe impl Send for Parker {}
+
+impl Parker {
+ pub unsafe fn new_in_place(parker: *mut Parker) {
+ let semaphore = dispatch_semaphore_create(0);
+ assert!(
+ !semaphore.is_null(),
+ "failed to create dispatch semaphore for thread synchronization"
+ );
+ parker.write(Parker { semaphore, state: AtomicI8::new(EMPTY) })
+ }
+
+ // Does not need `Pin`, but other implementation do.
+ pub unsafe fn park(self: Pin<&Self>) {
+ // The semaphore counter must be zero at this point, because unparking
+ // threads will not actually increase it until we signalled that we
+ // are waiting.
+
+ // Change NOTIFIED to EMPTY and EMPTY to PARKED.
+ if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+ return;
+ }
+
+ // Another thread may increase the semaphore counter from this point on.
+ // If it is faster than us, we will decrement it again immediately below.
+ // If we are faster, we wait.
+
+ // Ensure that the semaphore counter has actually been decremented, even
+ // if the call timed out for some reason.
+ while dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER) != 0 {}
+
+ // At this point, the semaphore counter is zero again.
+
+ // We were definitely woken up, so we don't need to check the state.
+ // Still, we need to reset the state using a swap to observe the state
+ // change with acquire ordering.
+ self.state.swap(EMPTY, Acquire);
+ }
+
+ // Does not need `Pin`, but other implementation do.
+ pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+ if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+ return;
+ }
+
+ let nanos = dur.as_nanos().try_into().unwrap_or(i64::MAX);
+ let timeout = dispatch_time(DISPATCH_TIME_NOW, nanos);
+
+ let timeout = dispatch_semaphore_wait(self.semaphore, timeout) != 0;
+
+ let state = self.state.swap(EMPTY, Acquire);
+ if state == NOTIFIED && timeout {
+ // If the state was NOTIFIED but semaphore_wait returned without
+ // decrementing the count because of a timeout, it means another
+ // thread is about to call semaphore_signal. We must wait for that
+ // to happen to ensure the semaphore count is reset.
+ while dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER) != 0 {}
+ } else {
+ // Either a timeout occurred and we reset the state before any thread
+ // tried to wake us up, or we were woken up and reset the state,
+ // making sure to observe the state change with acquire ordering.
+ // Either way, the semaphore counter is now zero again.
+ }
+ }
+
+ // Does not need `Pin`, but other implementation do.
+ pub fn unpark(self: Pin<&Self>) {
+ let state = self.state.swap(NOTIFIED, Release);
+ if state == PARKED {
+ unsafe {
+ dispatch_semaphore_signal(self.semaphore);
+ }
+ }
+ }
+}
+
+impl Drop for Parker {
+ fn drop(&mut self) {
+ // SAFETY:
+ // We always ensure that the semaphore count is reset, so this will
+ // never cause an exception.
+ unsafe {
+ dispatch_release(self.semaphore);
+ }
+ }
+}
--- /dev/null
+//! Thread parking on systems without futex support.
+
+#![cfg(not(any(
+ target_os = "linux",
+ target_os = "android",
+ all(target_os = "emscripten", target_feature = "atomics"),
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "dragonfly",
+ target_os = "fuchsia",
+)))]
+
+cfg_if::cfg_if! {
+ if #[cfg(all(
+ any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "watchos",
+ target_os = "tvos",
+ ),
+ not(miri),
+ ))] {
+ mod darwin;
+ pub use darwin::Parker;
+ } else if #[cfg(target_os = "netbsd")] {
+ mod netbsd;
+ pub use netbsd::{current, park, park_timeout, unpark, ThreadId};
+ } else {
+ mod pthread;
+ pub use pthread::Parker;
+ }
+}
--- /dev/null
+use crate::ffi::{c_int, c_void};
+use crate::ptr;
+use crate::time::Duration;
+use libc::{_lwp_self, clockid_t, lwpid_t, time_t, timespec, CLOCK_MONOTONIC};
+
+extern "C" {
+ fn ___lwp_park60(
+ clock_id: clockid_t,
+ flags: c_int,
+ ts: *mut timespec,
+ unpark: lwpid_t,
+ hint: *const c_void,
+ unparkhint: *const c_void,
+ ) -> c_int;
+ fn _lwp_unpark(lwp: lwpid_t, hint: *const c_void) -> c_int;
+}
+
+pub type ThreadId = lwpid_t;
+
+#[inline]
+pub fn current() -> ThreadId {
+ unsafe { _lwp_self() }
+}
+
+#[inline]
+pub fn park(hint: usize) {
+ unsafe {
+ ___lwp_park60(0, 0, ptr::null_mut(), 0, ptr::invalid(hint), ptr::null());
+ }
+}
+
+pub fn park_timeout(dur: Duration, hint: usize) {
+ let mut timeout = timespec {
+ // Saturate so that the operation will definitely time out
+ // (even if it is after the heat death of the universe).
+ tv_sec: dur.as_secs().try_into().ok().unwrap_or(time_t::MAX),
+ tv_nsec: dur.subsec_nanos().into(),
+ };
+
+ // Timeout needs to be mutable since it is modified on NetBSD 9.0 and
+ // above.
+ unsafe {
+ ___lwp_park60(CLOCK_MONOTONIC, 0, &mut timeout, 0, ptr::invalid(hint), ptr::null());
+ }
+}
+
+#[inline]
+pub fn unpark(tid: ThreadId, hint: usize) {
+ unsafe {
+ _lwp_unpark(tid, ptr::invalid(hint));
+ }
+}
--- /dev/null
+//! Thread parking without `futex` using the `pthread` synchronization primitives.
+
+use crate::cell::UnsafeCell;
+use crate::marker::PhantomPinned;
+use crate::pin::Pin;
+use crate::ptr::addr_of_mut;
+use crate::sync::atomic::AtomicUsize;
+use crate::sync::atomic::Ordering::SeqCst;
+use crate::sys::time::TIMESPEC_MAX;
+use crate::time::Duration;
+
+const EMPTY: usize = 0;
+const PARKED: usize = 1;
+const NOTIFIED: usize = 2;
+
+unsafe fn lock(lock: *mut libc::pthread_mutex_t) {
+ let r = libc::pthread_mutex_lock(lock);
+ debug_assert_eq!(r, 0);
+}
+
+unsafe fn unlock(lock: *mut libc::pthread_mutex_t) {
+ let r = libc::pthread_mutex_unlock(lock);
+ debug_assert_eq!(r, 0);
+}
+
+unsafe fn notify_one(cond: *mut libc::pthread_cond_t) {
+ let r = libc::pthread_cond_signal(cond);
+ debug_assert_eq!(r, 0);
+}
+
+unsafe fn wait(cond: *mut libc::pthread_cond_t, lock: *mut libc::pthread_mutex_t) {
+ let r = libc::pthread_cond_wait(cond, lock);
+ debug_assert_eq!(r, 0);
+}
+
+unsafe fn wait_timeout(
+ cond: *mut libc::pthread_cond_t,
+ lock: *mut libc::pthread_mutex_t,
+ dur: Duration,
+) {
+ // Use the system clock on systems that do not support pthread_condattr_setclock.
+ // This unfortunately results in problems when the system time changes.
+ #[cfg(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "watchos",
+ target_os = "espidf",
+ target_os = "horizon",
+ ))]
+ let (now, dur) = {
+ use crate::cmp::min;
+ use crate::sys::time::SystemTime;
+
+ // OSX implementation of `pthread_cond_timedwait` is buggy
+ // with super long durations. When duration is greater than
+ // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait`
+ // in macOS Sierra return error 316.
+ //
+ // This program demonstrates the issue:
+ // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c
+ //
+ // To work around this issue, and possible bugs of other OSes, timeout
+ // is clamped to 1000 years, which is allowable per the API of `park_timeout`
+ // because of spurious wakeups.
+ let dur = min(dur, Duration::from_secs(1000 * 365 * 86400));
+ let now = SystemTime::now().t;
+ (now, dur)
+ };
+ // Use the monotonic clock on other systems.
+ #[cfg(not(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "watchos",
+ target_os = "espidf",
+ target_os = "horizon",
+ )))]
+ let (now, dur) = {
+ use crate::sys::time::Timespec;
+
+ (Timespec::now(libc::CLOCK_MONOTONIC), dur)
+ };
+
+ let timeout =
+ now.checked_add_duration(&dur).and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX);
+ let r = libc::pthread_cond_timedwait(cond, lock, &timeout);
+ debug_assert!(r == libc::ETIMEDOUT || r == 0);
+}
+
+pub struct Parker {
+ state: AtomicUsize,
+ lock: UnsafeCell<libc::pthread_mutex_t>,
+ cvar: UnsafeCell<libc::pthread_cond_t>,
+ // The `pthread` primitives require a stable address, so make this struct `!Unpin`.
+ _pinned: PhantomPinned,
+}
+
+impl Parker {
+ /// Construct the UNIX parker in-place.
+ ///
+ /// # Safety
+ /// The constructed parker must never be moved.
+ pub unsafe fn new_in_place(parker: *mut Parker) {
+ // Use the default mutex implementation to allow for simpler initialization.
+ // This could lead to undefined behaviour when deadlocking. This is avoided
+ // by not deadlocking. Note in particular the unlocking operation before any
+ // panic, as code after the panic could try to park again.
+ addr_of_mut!((*parker).state).write(AtomicUsize::new(EMPTY));
+ addr_of_mut!((*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER));
+
+ cfg_if::cfg_if! {
+ if #[cfg(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "watchos",
+ target_os = "l4re",
+ target_os = "android",
+ target_os = "redox"
+ ))] {
+ addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER));
+ } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] {
+ let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), crate::ptr::null());
+ assert_eq!(r, 0);
+ } else {
+ use crate::mem::MaybeUninit;
+ let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit();
+ let r = libc::pthread_condattr_init(attr.as_mut_ptr());
+ assert_eq!(r, 0);
+ let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC);
+ assert_eq!(r, 0);
+ let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), attr.as_ptr());
+ assert_eq!(r, 0);
+ let r = libc::pthread_condattr_destroy(attr.as_mut_ptr());
+ assert_eq!(r, 0);
+ }
+ }
+ }
+
+ // This implementation doesn't require `unsafe`, but other implementations
+ // may assume this is only called by the thread that owns the Parker.
+ pub unsafe fn park(self: Pin<&Self>) {
+ // If we were previously notified then we consume this notification and
+ // return quickly.
+ if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+ return;
+ }
+
+ // Otherwise we need to coordinate going to sleep
+ lock(self.lock.get());
+ match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+ Ok(_) => {}
+ Err(NOTIFIED) => {
+ // We must read here, even though we know it will be `NOTIFIED`.
+ // This is because `unpark` may have been called again since we read
+ // `NOTIFIED` in the `compare_exchange` above. We must perform an
+ // acquire operation that synchronizes with that `unpark` to observe
+ // any writes it made before the call to unpark. To do that we must
+ // read from the write it made to `state`.
+ let old = self.state.swap(EMPTY, SeqCst);
+
+ unlock(self.lock.get());
+
+ assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+ return;
+ } // should consume this notification, so prohibit spurious wakeups in next park.
+ Err(_) => {
+ unlock(self.lock.get());
+
+ panic!("inconsistent park state")
+ }
+ }
+
+ loop {
+ wait(self.cvar.get(), self.lock.get());
+
+ match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
+ Ok(_) => break, // got a notification
+ Err(_) => {} // spurious wakeup, go back to sleep
+ }
+ }
+
+ unlock(self.lock.get());
+ }
+
+ // This implementation doesn't require `unsafe`, but other implementations
+ // may assume this is only called by the thread that owns the Parker. Use
+ // `Pin` to guarantee a stable address for the mutex and condition variable.
+ pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+ // Like `park` above we have a fast path for an already-notified thread, and
+ // afterwards we start coordinating for a sleep.
+ // return quickly.
+ if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+ return;
+ }
+
+ lock(self.lock.get());
+ match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+ Ok(_) => {}
+ Err(NOTIFIED) => {
+ // We must read again here, see `park`.
+ let old = self.state.swap(EMPTY, SeqCst);
+ unlock(self.lock.get());
+
+ assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+ return;
+ } // should consume this notification, so prohibit spurious wakeups in next park.
+ Err(_) => {
+ unlock(self.lock.get());
+ panic!("inconsistent park_timeout state")
+ }
+ }
+
+ // Wait with a timeout, and if we spuriously wake up or otherwise wake up
+ // from a notification we just want to unconditionally set the state back to
+ // empty, either consuming a notification or un-flagging ourselves as
+ // parked.
+ wait_timeout(self.cvar.get(), self.lock.get(), dur);
+
+ match self.state.swap(EMPTY, SeqCst) {
+ NOTIFIED => unlock(self.lock.get()), // got a notification, hurray!
+ PARKED => unlock(self.lock.get()), // no notification, alas
+ n => {
+ unlock(self.lock.get());
+ panic!("inconsistent park_timeout state: {n}")
+ }
+ }
+ }
+
+ pub fn unpark(self: Pin<&Self>) {
+ // To ensure the unparked thread will observe any writes we made
+ // before this call, we must perform a release operation that `park`
+ // can synchronize with. To do that we must write `NOTIFIED` even if
+ // `state` is already `NOTIFIED`. That is why this must be a swap
+ // rather than a compare-and-swap that returns if it reads `NOTIFIED`
+ // on failure.
+ match self.state.swap(NOTIFIED, SeqCst) {
+ EMPTY => return, // no one was waiting
+ NOTIFIED => return, // already unparked
+ PARKED => {} // gotta go wake someone up
+ _ => panic!("inconsistent state in unpark"),
+ }
+
+ // There is a period between when the parked thread sets `state` to
+ // `PARKED` (or last checked `state` in the case of a spurious wake
+ // up) and when it actually waits on `cvar`. If we were to notify
+ // during this period it would be ignored and then when the parked
+ // thread went to sleep it would never wake up. Fortunately, it has
+ // `lock` locked at this stage so we can acquire `lock` to wait until
+ // it is ready to receive the notification.
+ //
+ // Releasing `lock` before the call to `notify_one` means that when the
+ // parked thread wakes it doesn't get woken only to have to wait for us
+ // to release `lock`.
+ unsafe {
+ lock(self.lock.get());
+ unlock(self.lock.get());
+ notify_one(self.cvar.get());
+ }
+ }
+}
+
+impl Drop for Parker {
+ fn drop(&mut self) {
+ unsafe {
+ libc::pthread_cond_destroy(self.cvar.get_mut());
+ libc::pthread_mutex_destroy(self.lock.get_mut());
+ }
+ }
+}
+
+unsafe impl Sync for Parker {}
+unsafe impl Send for Parker {}
//! Support for "weak linkage" to symbols on Unix
//!
-//! Some I/O operations we do in libstd require newer versions of OSes but we
-//! need to maintain binary compatibility with older releases for now. In order
-//! to use the new functionality when available we use this module for
-//! detection.
+//! Some I/O operations we do in std require newer versions of OSes but we need
+//! to maintain binary compatibility with older releases for now. In order to
+//! use the new functionality when available we use this module for detection.
//!
//! One option to use here is weak linkage, but that is unfortunately only
//! really workable with ELF. Otherwise, use dlsym to get the symbol value at
use crate::sync::atomic::{self, AtomicPtr, Ordering};
// We can use true weak linkage on ELF targets.
-#[cfg(all(not(any(target_os = "macos", target_os = "ios")), not(bootstrap)))]
+#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub(crate) macro weak {
(fn $name:ident($($t:ty),*) -> $ret:ty) => (
let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
)
}
-#[cfg(all(not(any(target_os = "macos", target_os = "ios")), bootstrap))]
-pub(crate) macro weak {
- (fn $name:ident($($t:ty),*) -> $ret:ty) => (
- let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
- extern "C" {
- #[linkage = "extern_weak"]
- static $name: *const libc::c_void;
- }
- #[allow(unused_unsafe)]
- ExternWeak::new(unsafe { $name })
- };
- )
-}
-
// On non-ELF targets, use the dlsym approximation of weak linkage.
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub(crate) use self::dlsym as weak;
-#[cfg(not(bootstrap))]
pub(crate) struct ExternWeak<F: Copy> {
weak_ptr: Option<F>,
}
-#[cfg(not(bootstrap))]
impl<F: Copy> ExternWeak<F> {
#[inline]
pub(crate) fn new(weak_ptr: Option<F>) -> Self {
}
}
-#[cfg(bootstrap)]
-pub(crate) struct ExternWeak<F> {
- weak_ptr: *const libc::c_void,
- _marker: PhantomData<F>,
-}
-
-#[cfg(bootstrap)]
-impl<F> ExternWeak<F> {
- #[inline]
- pub(crate) fn new(weak_ptr: *const libc::c_void) -> Self {
- ExternWeak { weak_ptr, _marker: PhantomData }
- }
-}
-
-#[cfg(bootstrap)]
-impl<F> ExternWeak<F> {
- #[inline]
- pub(crate) fn get(&self) -> Option<F> {
- unsafe {
- if self.weak_ptr.is_null() {
- None
- } else {
- Some(mem::transmute_copy::<*const libc::c_void, F>(&self.weak_ptr))
- }
- }
- }
-}
-
pub(crate) macro dlsym {
(fn $name:ident($($t:ty),*) -> $ret:ty) => (
dlsym!(fn $name($($t),*) -> $ret, stringify!($name));
pub mod thread;
pub mod thread_local_dtor;
pub mod thread_local_key;
-pub mod thread_parker;
+pub mod thread_parking;
pub mod time;
cfg_if::cfg_if! {
if #[cfg(not(target_vendor = "uwp"))] {
+++ /dev/null
-// Thread parker implementation for Windows.
-//
-// This uses WaitOnAddress and WakeByAddressSingle if available (Windows 8+).
-// This modern API is exactly the same as the futex syscalls the Linux thread
-// parker uses. When These APIs are available, the implementation of this
-// thread parker matches the Linux thread parker exactly.
-//
-// However, when the modern API is not available, this implementation falls
-// back to NT Keyed Events, which are similar, but have some important
-// differences. These are available since Windows XP.
-//
-// WaitOnAddress first checks the state of the thread parker to make sure it no
-// WakeByAddressSingle calls can be missed between updating the parker state
-// and calling the function.
-//
-// NtWaitForKeyedEvent does not have this option, and unconditionally blocks
-// without checking the parker state first. Instead, NtReleaseKeyedEvent
-// (unlike WakeByAddressSingle) *blocks* until it woke up a thread waiting for
-// it by NtWaitForKeyedEvent. This way, we can be sure no events are missed,
-// but we need to be careful not to block unpark() if park_timeout() was woken
-// up by a timeout instead of unpark().
-//
-// Unlike WaitOnAddress, NtWaitForKeyedEvent/NtReleaseKeyedEvent operate on a
-// HANDLE (created with NtCreateKeyedEvent). This means that we can be sure
-// a successfully awoken park() was awoken by unpark() and not a
-// NtReleaseKeyedEvent call from some other code, as these events are not only
-// matched by the key (address of the parker (state)), but also by this HANDLE.
-// We lazily allocate this handle the first time it is needed.
-//
-// The fast path (calling park() after unpark() was already called) and the
-// possible states are the same for both implementations. This is used here to
-// make sure the fast path does not even check which API to use, but can return
-// right away, independent of the used API. Only the slow paths (which will
-// actually block/wake a thread) check which API is available and have
-// different implementations.
-//
-// Unfortunately, NT Keyed Events are an undocumented Windows API. However:
-// - This API is relatively simple with obvious behaviour, and there are
-// several (unofficial) articles documenting the details. [1]
-// - `parking_lot` has been using this API for years (on Windows versions
-// before Windows 8). [2] Many big projects extensively use parking_lot,
-// such as servo and the Rust compiler itself.
-// - It is the underlying API used by Windows SRW locks and Windows critical
-// sections. [3] [4]
-// - The source code of the implementations of Wine, ReactOs, and Windows XP
-// are available and match the expected behaviour.
-// - The main risk with an undocumented API is that it might change in the
-// future. But since we only use it for older versions of Windows, that's not
-// a problem.
-// - Even if these functions do not block or wake as we expect (which is
-// unlikely, see all previous points), this implementation would still be
-// memory safe. The NT Keyed Events API is only used to sleep/block in the
-// right place.
-//
-// [1]: http://www.locklessinc.com/articles/keyed_events/
-// [2]: https://github.com/Amanieu/parking_lot/commit/43abbc964e
-// [3]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2012/november/windows-with-c-the-evolution-of-synchronization-in-windows-and-c
-// [4]: Windows Internals, Part 1, ISBN 9780735671300
-
-use crate::pin::Pin;
-use crate::ptr;
-use crate::sync::atomic::{
- AtomicI8, AtomicPtr,
- Ordering::{Acquire, Relaxed, Release},
-};
-use crate::sys::{c, dur2timeout};
-use crate::time::Duration;
-
-pub struct Parker {
- state: AtomicI8,
-}
-
-const PARKED: i8 = -1;
-const EMPTY: i8 = 0;
-const NOTIFIED: i8 = 1;
-
-// Notes about memory ordering:
-//
-// Memory ordering is only relevant for the relative ordering of operations
-// between different variables. Even Ordering::Relaxed guarantees a
-// monotonic/consistent order when looking at just a single atomic variable.
-//
-// So, since this parker is just a single atomic variable, we only need to look
-// at the ordering guarantees we need to provide to the 'outside world'.
-//
-// The only memory ordering guarantee that parking and unparking provide, is
-// that things which happened before unpark() are visible on the thread
-// returning from park() afterwards. Otherwise, it was effectively unparked
-// before unpark() was called while still consuming the 'token'.
-//
-// In other words, unpark() needs to synchronize with the part of park() that
-// consumes the token and returns.
-//
-// This is done with a release-acquire synchronization, by using
-// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
-// Ordering::Acquire when reading this state in park() after waking up.
-impl Parker {
- /// Construct the Windows parker. The UNIX parker implementation
- /// requires this to happen in-place.
- pub unsafe fn new(parker: *mut Parker) {
- parker.write(Self { state: AtomicI8::new(EMPTY) });
- }
-
- // Assumes this is only called by the thread that owns the Parker,
- // which means that `self.state != PARKED`. This implementation doesn't require `Pin`,
- // but other implementations do.
- pub unsafe fn park(self: Pin<&Self>) {
- // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
- // first case.
- if self.state.fetch_sub(1, Acquire) == NOTIFIED {
- return;
- }
-
- if let Some(wait_on_address) = c::WaitOnAddress::option() {
- loop {
- // Wait for something to happen, assuming it's still set to PARKED.
- wait_on_address(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE);
- // Change NOTIFIED=>EMPTY but leave PARKED alone.
- if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() {
- // Actually woken up by unpark().
- return;
- } else {
- // Spurious wake up. We loop to try again.
- }
- }
- } else {
- // Wait for unpark() to produce this event.
- c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
- // Set the state back to EMPTY (from either PARKED or NOTIFIED).
- // Note that we don't just write EMPTY, but use swap() to also
- // include an acquire-ordered read to synchronize with unpark()'s
- // release-ordered write.
- self.state.swap(EMPTY, Acquire);
- }
- }
-
- // Assumes this is only called by the thread that owns the Parker,
- // which means that `self.state != PARKED`. This implementation doesn't require `Pin`,
- // but other implementations do.
- pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) {
- // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
- // first case.
- if self.state.fetch_sub(1, Acquire) == NOTIFIED {
- return;
- }
-
- if let Some(wait_on_address) = c::WaitOnAddress::option() {
- // Wait for something to happen, assuming it's still set to PARKED.
- wait_on_address(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout));
- // Set the state back to EMPTY (from either PARKED or NOTIFIED).
- // Note that we don't just write EMPTY, but use swap() to also
- // include an acquire-ordered read to synchronize with unpark()'s
- // release-ordered write.
- if self.state.swap(EMPTY, Acquire) == NOTIFIED {
- // Actually woken up by unpark().
- } else {
- // Timeout or spurious wake up.
- // We return either way, because we can't easily tell if it was the
- // timeout or not.
- }
- } else {
- // Need to wait for unpark() using NtWaitForKeyedEvent.
- let handle = keyed_event_handle();
-
- // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative
- // values to indicate a relative time on the monotonic clock.
- // This is documented here for the underlying KeWaitForSingleObject function:
- // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kewaitforsingleobject
- let mut timeout = match i64::try_from((timeout.as_nanos() + 99) / 100) {
- Ok(t) => -t,
- Err(_) => i64::MIN,
- };
-
- // Wait for unpark() to produce this event.
- let unparked =
- c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS;
-
- // Set the state back to EMPTY (from either PARKED or NOTIFIED).
- let prev_state = self.state.swap(EMPTY, Acquire);
-
- if !unparked && prev_state == NOTIFIED {
- // We were awoken by a timeout, not by unpark(), but the state
- // was set to NOTIFIED, which means we *just* missed an
- // unpark(), which is now blocked on us to wait for it.
- // Wait for it to consume the event and unblock that thread.
- c::NtWaitForKeyedEvent(handle, self.ptr(), 0, ptr::null_mut());
- }
- }
- }
-
- // This implementation doesn't require `Pin`, but other implementations do.
- pub fn unpark(self: Pin<&Self>) {
- // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
- // wake the thread in the first case.
- //
- // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
- // purpose, to make sure every unpark() has a release-acquire ordering
- // with park().
- if self.state.swap(NOTIFIED, Release) == PARKED {
- unsafe {
- if let Some(wake_by_address_single) = c::WakeByAddressSingle::option() {
- wake_by_address_single(self.ptr());
- } else {
- // If we run NtReleaseKeyedEvent before the waiting thread runs
- // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
- // If the waiting thread wakes up before we run NtReleaseKeyedEvent
- // (e.g. due to a timeout), this blocks until we do wake up a thread.
- // To prevent this thread from blocking indefinitely in that case,
- // park_impl() will, after seeing the state set to NOTIFIED after
- // waking up, call NtWaitForKeyedEvent again to unblock us.
- c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
- }
- }
- }
- }
-
- fn ptr(&self) -> c::LPVOID {
- &self.state as *const _ as c::LPVOID
- }
-}
-
-fn keyed_event_handle() -> c::HANDLE {
- const INVALID: c::HANDLE = ptr::invalid_mut(!0);
- static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID);
- match HANDLE.load(Relaxed) {
- INVALID => {
- let mut handle = c::INVALID_HANDLE_VALUE;
- unsafe {
- match c::NtCreateKeyedEvent(
- &mut handle,
- c::GENERIC_READ | c::GENERIC_WRITE,
- ptr::null_mut(),
- 0,
- ) {
- c::STATUS_SUCCESS => {}
- r => panic!("Unable to create keyed event handle: error {r}"),
- }
- }
- match HANDLE.compare_exchange(INVALID, handle, Relaxed, Relaxed) {
- Ok(_) => handle,
- Err(h) => {
- // Lost the race to another thread initializing HANDLE before we did.
- // Closing our handle and using theirs instead.
- unsafe {
- c::CloseHandle(handle);
- }
- h
- }
- }
- }
- handle => handle,
- }
-}
--- /dev/null
+// Thread parker implementation for Windows.
+//
+// This uses WaitOnAddress and WakeByAddressSingle if available (Windows 8+).
+// This modern API is exactly the same as the futex syscalls the Linux thread
+// parker uses. When These APIs are available, the implementation of this
+// thread parker matches the Linux thread parker exactly.
+//
+// However, when the modern API is not available, this implementation falls
+// back to NT Keyed Events, which are similar, but have some important
+// differences. These are available since Windows XP.
+//
+// WaitOnAddress first checks the state of the thread parker to make sure it no
+// WakeByAddressSingle calls can be missed between updating the parker state
+// and calling the function.
+//
+// NtWaitForKeyedEvent does not have this option, and unconditionally blocks
+// without checking the parker state first. Instead, NtReleaseKeyedEvent
+// (unlike WakeByAddressSingle) *blocks* until it woke up a thread waiting for
+// it by NtWaitForKeyedEvent. This way, we can be sure no events are missed,
+// but we need to be careful not to block unpark() if park_timeout() was woken
+// up by a timeout instead of unpark().
+//
+// Unlike WaitOnAddress, NtWaitForKeyedEvent/NtReleaseKeyedEvent operate on a
+// HANDLE (created with NtCreateKeyedEvent). This means that we can be sure
+// a successfully awoken park() was awoken by unpark() and not a
+// NtReleaseKeyedEvent call from some other code, as these events are not only
+// matched by the key (address of the parker (state)), but also by this HANDLE.
+// We lazily allocate this handle the first time it is needed.
+//
+// The fast path (calling park() after unpark() was already called) and the
+// possible states are the same for both implementations. This is used here to
+// make sure the fast path does not even check which API to use, but can return
+// right away, independent of the used API. Only the slow paths (which will
+// actually block/wake a thread) check which API is available and have
+// different implementations.
+//
+// Unfortunately, NT Keyed Events are an undocumented Windows API. However:
+// - This API is relatively simple with obvious behaviour, and there are
+// several (unofficial) articles documenting the details. [1]
+// - `parking_lot` has been using this API for years (on Windows versions
+// before Windows 8). [2] Many big projects extensively use parking_lot,
+// such as servo and the Rust compiler itself.
+// - It is the underlying API used by Windows SRW locks and Windows critical
+// sections. [3] [4]
+// - The source code of the implementations of Wine, ReactOs, and Windows XP
+// are available and match the expected behaviour.
+// - The main risk with an undocumented API is that it might change in the
+// future. But since we only use it for older versions of Windows, that's not
+// a problem.
+// - Even if these functions do not block or wake as we expect (which is
+// unlikely, see all previous points), this implementation would still be
+// memory safe. The NT Keyed Events API is only used to sleep/block in the
+// right place.
+//
+// [1]: http://www.locklessinc.com/articles/keyed_events/
+// [2]: https://github.com/Amanieu/parking_lot/commit/43abbc964e
+// [3]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2012/november/windows-with-c-the-evolution-of-synchronization-in-windows-and-c
+// [4]: Windows Internals, Part 1, ISBN 9780735671300
+
+use crate::pin::Pin;
+use crate::ptr;
+use crate::sync::atomic::{
+ AtomicI8, AtomicPtr,
+ Ordering::{Acquire, Relaxed, Release},
+};
+use crate::sys::{c, dur2timeout};
+use crate::time::Duration;
+
+pub struct Parker {
+ state: AtomicI8,
+}
+
+const PARKED: i8 = -1;
+const EMPTY: i8 = 0;
+const NOTIFIED: i8 = 1;
+
+// Notes about memory ordering:
+//
+// Memory ordering is only relevant for the relative ordering of operations
+// between different variables. Even Ordering::Relaxed guarantees a
+// monotonic/consistent order when looking at just a single atomic variable.
+//
+// So, since this parker is just a single atomic variable, we only need to look
+// at the ordering guarantees we need to provide to the 'outside world'.
+//
+// The only memory ordering guarantee that parking and unparking provide, is
+// that things which happened before unpark() are visible on the thread
+// returning from park() afterwards. Otherwise, it was effectively unparked
+// before unpark() was called while still consuming the 'token'.
+//
+// In other words, unpark() needs to synchronize with the part of park() that
+// consumes the token and returns.
+//
+// This is done with a release-acquire synchronization, by using
+// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
+// Ordering::Acquire when reading this state in park() after waking up.
+impl Parker {
+ /// Construct the Windows parker. The UNIX parker implementation
+ /// requires this to happen in-place.
+ pub unsafe fn new_in_place(parker: *mut Parker) {
+ parker.write(Self { state: AtomicI8::new(EMPTY) });
+ }
+
+ // Assumes this is only called by the thread that owns the Parker,
+ // which means that `self.state != PARKED`. This implementation doesn't require `Pin`,
+ // but other implementations do.
+ pub unsafe fn park(self: Pin<&Self>) {
+ // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
+ // first case.
+ if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+ return;
+ }
+
+ if let Some(wait_on_address) = c::WaitOnAddress::option() {
+ loop {
+ // Wait for something to happen, assuming it's still set to PARKED.
+ wait_on_address(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE);
+ // Change NOTIFIED=>EMPTY but leave PARKED alone.
+ if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() {
+ // Actually woken up by unpark().
+ return;
+ } else {
+ // Spurious wake up. We loop to try again.
+ }
+ }
+ } else {
+ // Wait for unpark() to produce this event.
+ c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
+ // Set the state back to EMPTY (from either PARKED or NOTIFIED).
+ // Note that we don't just write EMPTY, but use swap() to also
+ // include an acquire-ordered read to synchronize with unpark()'s
+ // release-ordered write.
+ self.state.swap(EMPTY, Acquire);
+ }
+ }
+
+ // Assumes this is only called by the thread that owns the Parker,
+ // which means that `self.state != PARKED`. This implementation doesn't require `Pin`,
+ // but other implementations do.
+ pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) {
+ // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
+ // first case.
+ if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+ return;
+ }
+
+ if let Some(wait_on_address) = c::WaitOnAddress::option() {
+ // Wait for something to happen, assuming it's still set to PARKED.
+ wait_on_address(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout));
+ // Set the state back to EMPTY (from either PARKED or NOTIFIED).
+ // Note that we don't just write EMPTY, but use swap() to also
+ // include an acquire-ordered read to synchronize with unpark()'s
+ // release-ordered write.
+ if self.state.swap(EMPTY, Acquire) == NOTIFIED {
+ // Actually woken up by unpark().
+ } else {
+ // Timeout or spurious wake up.
+ // We return either way, because we can't easily tell if it was the
+ // timeout or not.
+ }
+ } else {
+ // Need to wait for unpark() using NtWaitForKeyedEvent.
+ let handle = keyed_event_handle();
+
+ // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative
+ // values to indicate a relative time on the monotonic clock.
+ // This is documented here for the underlying KeWaitForSingleObject function:
+ // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kewaitforsingleobject
+ let mut timeout = match i64::try_from((timeout.as_nanos() + 99) / 100) {
+ Ok(t) => -t,
+ Err(_) => i64::MIN,
+ };
+
+ // Wait for unpark() to produce this event.
+ let unparked =
+ c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS;
+
+ // Set the state back to EMPTY (from either PARKED or NOTIFIED).
+ let prev_state = self.state.swap(EMPTY, Acquire);
+
+ if !unparked && prev_state == NOTIFIED {
+ // We were awoken by a timeout, not by unpark(), but the state
+ // was set to NOTIFIED, which means we *just* missed an
+ // unpark(), which is now blocked on us to wait for it.
+ // Wait for it to consume the event and unblock that thread.
+ c::NtWaitForKeyedEvent(handle, self.ptr(), 0, ptr::null_mut());
+ }
+ }
+ }
+
+ // This implementation doesn't require `Pin`, but other implementations do.
+ pub fn unpark(self: Pin<&Self>) {
+ // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
+ // wake the thread in the first case.
+ //
+ // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
+ // purpose, to make sure every unpark() has a release-acquire ordering
+ // with park().
+ if self.state.swap(NOTIFIED, Release) == PARKED {
+ unsafe {
+ if let Some(wake_by_address_single) = c::WakeByAddressSingle::option() {
+ wake_by_address_single(self.ptr());
+ } else {
+ // If we run NtReleaseKeyedEvent before the waiting thread runs
+ // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
+ // If the waiting thread wakes up before we run NtReleaseKeyedEvent
+ // (e.g. due to a timeout), this blocks until we do wake up a thread.
+ // To prevent this thread from blocking indefinitely in that case,
+ // park_impl() will, after seeing the state set to NOTIFIED after
+ // waking up, call NtWaitForKeyedEvent again to unblock us.
+ c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
+ }
+ }
+ }
+ }
+
+ fn ptr(&self) -> c::LPVOID {
+ &self.state as *const _ as c::LPVOID
+ }
+}
+
+fn keyed_event_handle() -> c::HANDLE {
+ const INVALID: c::HANDLE = ptr::invalid_mut(!0);
+ static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID);
+ match HANDLE.load(Relaxed) {
+ INVALID => {
+ let mut handle = c::INVALID_HANDLE_VALUE;
+ unsafe {
+ match c::NtCreateKeyedEvent(
+ &mut handle,
+ c::GENERIC_READ | c::GENERIC_WRITE,
+ ptr::null_mut(),
+ 0,
+ ) {
+ c::STATUS_SUCCESS => {}
+ r => panic!("Unable to create keyed event handle: error {r}"),
+ }
+ }
+ match HANDLE.compare_exchange(INVALID, handle, Relaxed, Relaxed) {
+ Ok(_) => handle,
+ Err(h) => {
+ // Lost the race to another thread initializing HANDLE before we did.
+ // Closing our handle and using theirs instead.
+ unsafe {
+ c::CloseHandle(handle);
+ }
+ h
+ }
+ }
+ }
+ handle => handle,
+ }
+}
/// Prints the current backtrace.
pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
// There are issues currently linking libbacktrace into tests, and in
- // general during libstd's own unit tests we're not testing this path. In
+ // general during std's own unit tests we're not testing this path. In
// test mode immediately return here to optimize away any references to the
// libbacktrace symbols
if cfg!(test) {
}
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
-/// this is only inline(never) when backtraces in libstd are enabled, otherwise
+/// this is only inline(never) when backtraces in std are enabled, otherwise
/// it's fine to optimize away.
#[cfg_attr(feature = "backtrace", inline(never))]
pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
}
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
-/// this is only inline(never) when backtraces in libstd are enabled, otherwise
+/// this is only inline(never) when backtraces in std are enabled, otherwise
/// it's fine to optimize away.
#[cfg_attr(feature = "backtrace", inline(never))]
pub fn __rust_end_short_backtrace<F, T>(f: F) -> T
}
}
+ #[track_caller] // for `test_rng`
pub fn tmpdir() -> TempDir {
let p = env::temp_dir();
- let mut r = rand::thread_rng();
+ let mut r = crate::test_helpers::test_rng();
let ret = p.join(&format!("rust-{}", r.next_u32()));
fs::create_dir(&ret).unwrap();
TempDir(ret)
pub mod memchr;
pub mod once;
pub mod process;
-pub mod remutex;
pub mod thread;
pub mod thread_info;
pub mod thread_local_dtor;
-pub mod thread_parker;
+pub mod thread_parking;
pub mod wstr;
pub mod wtf8;
use crate::collections::BTreeMap;
use crate::env;
use crate::ffi::{OsStr, OsString};
+use crate::fmt;
use crate::io;
use crate::sys::pipe::read2;
use crate::sys::process::{EnvKey, ExitStatus, Process, StdioPipes};
// Stores a set of changes to an environment
-#[derive(Clone, Debug)]
+#[derive(Clone)]
pub struct CommandEnv {
clear: bool,
saw_path: bool,
}
}
+impl fmt::Debug for CommandEnv {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut debug_command_env = f.debug_struct("CommandEnv");
+ debug_command_env.field("clear", &self.clear).field("vars", &self.vars);
+ debug_command_env.finish()
+ }
+}
+
impl CommandEnv {
// Capture the current environment with these changes applied
pub fn capture(&self) -> BTreeMap<EnvKey, OsString> {
+++ /dev/null
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests;
-
-use crate::cell::UnsafeCell;
-use crate::ops::Deref;
-use crate::panic::{RefUnwindSafe, UnwindSafe};
-use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed};
-use crate::sys::locks as sys;
-
-/// A re-entrant mutual exclusion
-///
-/// This mutex will block *other* threads waiting for the lock to become
-/// available. The thread which has already locked the mutex can lock it
-/// multiple times without blocking, preventing a common source of deadlocks.
-///
-/// This is used by stdout().lock() and friends.
-///
-/// ## Implementation details
-///
-/// The 'owner' field tracks which thread has locked the mutex.
-///
-/// We use current_thread_unique_ptr() as the thread identifier,
-/// which is just the address of a thread local variable.
-///
-/// If `owner` is set to the identifier of the current thread,
-/// we assume the mutex is already locked and instead of locking it again,
-/// we increment `lock_count`.
-///
-/// When unlocking, we decrement `lock_count`, and only unlock the mutex when
-/// it reaches zero.
-///
-/// `lock_count` is protected by the mutex and only accessed by the thread that has
-/// locked the mutex, so needs no synchronization.
-///
-/// `owner` can be checked by other threads that want to see if they already
-/// hold the lock, so needs to be atomic. If it compares equal, we're on the
-/// same thread that holds the mutex and memory access can use relaxed ordering
-/// since we're not dealing with multiple threads. If it compares unequal,
-/// synchronization is left to the mutex, making relaxed memory ordering for
-/// the `owner` field fine in all cases.
-pub struct ReentrantMutex<T> {
- mutex: sys::Mutex,
- owner: AtomicUsize,
- lock_count: UnsafeCell<u32>,
- data: T,
-}
-
-unsafe impl<T: Send> Send for ReentrantMutex<T> {}
-unsafe impl<T: Send> Sync for ReentrantMutex<T> {}
-
-impl<T> UnwindSafe for ReentrantMutex<T> {}
-impl<T> RefUnwindSafe for ReentrantMutex<T> {}
-
-/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
-/// dropped (falls out of scope), the lock will be unlocked.
-///
-/// The data protected by the mutex can be accessed through this guard via its
-/// Deref implementation.
-///
-/// # Mutability
-///
-/// Unlike `MutexGuard`, `ReentrantMutexGuard` does not implement `DerefMut`,
-/// because implementation of the trait would violate Rust’s reference aliasing
-/// rules. Use interior mutability (usually `RefCell`) in order to mutate the
-/// guarded data.
-#[must_use = "if unused the ReentrantMutex will immediately unlock"]
-pub struct ReentrantMutexGuard<'a, T: 'a> {
- lock: &'a ReentrantMutex<T>,
-}
-
-impl<T> !Send for ReentrantMutexGuard<'_, T> {}
-
-impl<T> ReentrantMutex<T> {
- /// Creates a new reentrant mutex in an unlocked state.
- pub const fn new(t: T) -> ReentrantMutex<T> {
- ReentrantMutex {
- mutex: sys::Mutex::new(),
- owner: AtomicUsize::new(0),
- lock_count: UnsafeCell::new(0),
- data: t,
- }
- }
-
- /// Acquires a mutex, blocking the current thread until it is able to do so.
- ///
- /// This function will block the caller until it is available to acquire the mutex.
- /// Upon returning, the thread is the only thread with the mutex held. When the thread
- /// calling this method already holds the lock, the call shall succeed without
- /// blocking.
- ///
- /// # Errors
- ///
- /// If another user of this mutex panicked while holding the mutex, then
- /// this call will return failure if the mutex would otherwise be
- /// acquired.
- pub fn lock(&self) -> ReentrantMutexGuard<'_, T> {
- let this_thread = current_thread_unique_ptr();
- // Safety: We only touch lock_count when we own the lock.
- unsafe {
- if self.owner.load(Relaxed) == this_thread {
- self.increment_lock_count();
- } else {
- self.mutex.lock();
- self.owner.store(this_thread, Relaxed);
- debug_assert_eq!(*self.lock_count.get(), 0);
- *self.lock_count.get() = 1;
- }
- }
- ReentrantMutexGuard { lock: self }
- }
-
- /// Attempts to acquire this lock.
- ///
- /// If the lock could not be acquired at this time, then `Err` is returned.
- /// Otherwise, an RAII guard is returned.
- ///
- /// This function does not block.
- ///
- /// # Errors
- ///
- /// If another user of this mutex panicked while holding the mutex, then
- /// this call will return failure if the mutex would otherwise be
- /// acquired.
- pub fn try_lock(&self) -> Option<ReentrantMutexGuard<'_, T>> {
- let this_thread = current_thread_unique_ptr();
- // Safety: We only touch lock_count when we own the lock.
- unsafe {
- if self.owner.load(Relaxed) == this_thread {
- self.increment_lock_count();
- Some(ReentrantMutexGuard { lock: self })
- } else if self.mutex.try_lock() {
- self.owner.store(this_thread, Relaxed);
- debug_assert_eq!(*self.lock_count.get(), 0);
- *self.lock_count.get() = 1;
- Some(ReentrantMutexGuard { lock: self })
- } else {
- None
- }
- }
- }
-
- unsafe fn increment_lock_count(&self) {
- *self.lock_count.get() = (*self.lock_count.get())
- .checked_add(1)
- .expect("lock count overflow in reentrant mutex");
- }
-}
-
-impl<T> Deref for ReentrantMutexGuard<'_, T> {
- type Target = T;
-
- fn deref(&self) -> &T {
- &self.lock.data
- }
-}
-
-impl<T> Drop for ReentrantMutexGuard<'_, T> {
- #[inline]
- fn drop(&mut self) {
- // Safety: We own the lock.
- unsafe {
- *self.lock.lock_count.get() -= 1;
- if *self.lock.lock_count.get() == 0 {
- self.lock.owner.store(0, Relaxed);
- self.lock.mutex.unlock();
- }
- }
- }
-}
-
-/// Get an address that is unique per running thread.
-///
-/// This can be used as a non-null usize-sized ID.
-pub fn current_thread_unique_ptr() -> usize {
- // Use a non-drop type to make sure it's still available during thread destruction.
- thread_local! { static X: u8 = const { 0 } }
- X.with(|x| <*const _>::addr(x))
-}
+++ /dev/null
-use crate::cell::RefCell;
-use crate::sync::Arc;
-use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
-use crate::thread;
-
-#[test]
-fn smoke() {
- let m = ReentrantMutex::new(());
- {
- let a = m.lock();
- {
- let b = m.lock();
- {
- let c = m.lock();
- assert_eq!(*c, ());
- }
- assert_eq!(*b, ());
- }
- assert_eq!(*a, ());
- }
-}
-
-#[test]
-fn is_mutex() {
- let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
- let m2 = m.clone();
- let lock = m.lock();
- let child = thread::spawn(move || {
- let lock = m2.lock();
- assert_eq!(*lock.borrow(), 4950);
- });
- for i in 0..100 {
- let lock = m.lock();
- *lock.borrow_mut() += i;
- }
- drop(lock);
- child.join().unwrap();
-}
-
-#[test]
-fn trylock_works() {
- let m = Arc::new(ReentrantMutex::new(()));
- let m2 = m.clone();
- let _lock = m.try_lock();
- let _lock2 = m.try_lock();
- thread::spawn(move || {
- let lock = m2.try_lock();
- assert!(lock.is_none());
- })
- .join()
- .unwrap();
- let _lock3 = m.try_lock();
-}
-
-pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
-impl Drop for Answer<'_> {
- fn drop(&mut self) {
- *self.0.borrow_mut() = 42;
- }
-}
/// This value specifies no destructor by default.
pub const INIT: StaticKey = StaticKey::new(None);
+// Define a sentinel value that is unlikely to be returned
+// as a TLS key (but it may be returned).
+const KEY_SENTVAL: usize = 0;
+
impl StaticKey {
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> StaticKey {
- StaticKey { key: atomic::AtomicUsize::new(0), dtor }
+ StaticKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor }
}
/// Gets the value associated with this TLS key
#[inline]
unsafe fn key(&self) -> imp::Key {
match self.key.load(Ordering::Relaxed) {
- 0 => self.lazy_init() as imp::Key,
+ KEY_SENTVAL => self.lazy_init() as imp::Key,
n => n as imp::Key,
}
}
unsafe fn lazy_init(&self) -> usize {
- // POSIX allows the key created here to be 0, but the compare_exchange
- // below relies on using 0 as a sentinel value to check who won the
+ // POSIX allows the key created here to be KEY_SENTVAL, but the compare_exchange
+ // below relies on using KEY_SENTVAL as a sentinel value to check who won the
// race to set the shared TLS key. As far as I know, there is no
// guaranteed value that cannot be returned as a posix_key_create key,
// so there is no value we can initialize the inner key with to
// prove that it has not yet been set. As such, we'll continue using a
- // value of 0, but with some gyrations to make sure we have a non-0
+ // value of KEY_SENTVAL, but with some gyrations to make sure we have a non-KEY_SENTVAL
// value returned from the creation routine.
// FIXME: this is clearly a hack, and should be cleaned up.
let key1 = imp::create(self.dtor);
- let key = if key1 != 0 {
+ let key = if key1 as usize != KEY_SENTVAL {
key1
} else {
let key2 = imp::create(self.dtor);
imp::destroy(key1);
key2
};
- rtassert!(key != 0);
- match self.key.compare_exchange(0, key as usize, Ordering::SeqCst, Ordering::SeqCst) {
+ rtassert!(key as usize != KEY_SENTVAL);
+ match self.key.compare_exchange(
+ KEY_SENTVAL,
+ key as usize,
+ Ordering::SeqCst,
+ Ordering::SeqCst,
+ ) {
// The CAS succeeded, so we've created the actual key
Ok(_) => key as usize,
// If someone beat us to the punch, use their key instead
+++ /dev/null
-use crate::pin::Pin;
-use crate::sync::atomic::AtomicU32;
-use crate::sync::atomic::Ordering::{Acquire, Release};
-use crate::sys::futex::{futex_wait, futex_wake};
-use crate::time::Duration;
-
-const PARKED: u32 = u32::MAX;
-const EMPTY: u32 = 0;
-const NOTIFIED: u32 = 1;
-
-pub struct Parker {
- state: AtomicU32,
-}
-
-// Notes about memory ordering:
-//
-// Memory ordering is only relevant for the relative ordering of operations
-// between different variables. Even Ordering::Relaxed guarantees a
-// monotonic/consistent order when looking at just a single atomic variable.
-//
-// So, since this parker is just a single atomic variable, we only need to look
-// at the ordering guarantees we need to provide to the 'outside world'.
-//
-// The only memory ordering guarantee that parking and unparking provide, is
-// that things which happened before unpark() are visible on the thread
-// returning from park() afterwards. Otherwise, it was effectively unparked
-// before unpark() was called while still consuming the 'token'.
-//
-// In other words, unpark() needs to synchronize with the part of park() that
-// consumes the token and returns.
-//
-// This is done with a release-acquire synchronization, by using
-// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
-// Ordering::Acquire when checking for this state in park().
-impl Parker {
- /// Construct the futex parker. The UNIX parker implementation
- /// requires this to happen in-place.
- pub unsafe fn new(parker: *mut Parker) {
- parker.write(Self { state: AtomicU32::new(EMPTY) });
- }
-
- // Assumes this is only called by the thread that owns the Parker,
- // which means that `self.state != PARKED`.
- pub unsafe fn park(self: Pin<&Self>) {
- // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
- // first case.
- if self.state.fetch_sub(1, Acquire) == NOTIFIED {
- return;
- }
- loop {
- // Wait for something to happen, assuming it's still set to PARKED.
- futex_wait(&self.state, PARKED, None);
- // Change NOTIFIED=>EMPTY and return in that case.
- if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() {
- return;
- } else {
- // Spurious wake up. We loop to try again.
- }
- }
- }
-
- // Assumes this is only called by the thread that owns the Parker,
- // which means that `self.state != PARKED`. This implementation doesn't
- // require `Pin`, but other implementations do.
- pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) {
- // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
- // first case.
- if self.state.fetch_sub(1, Acquire) == NOTIFIED {
- return;
- }
- // Wait for something to happen, assuming it's still set to PARKED.
- futex_wait(&self.state, PARKED, Some(timeout));
- // This is not just a store, because we need to establish a
- // release-acquire ordering with unpark().
- if self.state.swap(EMPTY, Acquire) == NOTIFIED {
- // Woke up because of unpark().
- } else {
- // Timeout or spurious wake up.
- // We return either way, because we can't easily tell if it was the
- // timeout or not.
- }
- }
-
- // This implementation doesn't require `Pin`, but other implementations do.
- #[inline]
- pub fn unpark(self: Pin<&Self>) {
- // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
- // wake the thread in the first case.
- //
- // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
- // purpose, to make sure every unpark() has a release-acquire ordering
- // with park().
- if self.state.swap(NOTIFIED, Release) == PARKED {
- futex_wake(&self.state);
- }
- }
-}
+++ /dev/null
-//! Parker implementation based on a Mutex and Condvar.
-
-use crate::pin::Pin;
-use crate::sync::atomic::AtomicUsize;
-use crate::sync::atomic::Ordering::SeqCst;
-use crate::sync::{Condvar, Mutex};
-use crate::time::Duration;
-
-const EMPTY: usize = 0;
-const PARKED: usize = 1;
-const NOTIFIED: usize = 2;
-
-pub struct Parker {
- state: AtomicUsize,
- lock: Mutex<()>,
- cvar: Condvar,
-}
-
-impl Parker {
- /// Construct the generic parker. The UNIX parker implementation
- /// requires this to happen in-place.
- pub unsafe fn new(parker: *mut Parker) {
- parker.write(Parker {
- state: AtomicUsize::new(EMPTY),
- lock: Mutex::new(()),
- cvar: Condvar::new(),
- });
- }
-
- // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
- pub unsafe fn park(self: Pin<&Self>) {
- // If we were previously notified then we consume this notification and
- // return quickly.
- if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
- return;
- }
-
- // Otherwise we need to coordinate going to sleep
- let mut m = self.lock.lock().unwrap();
- match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
- Ok(_) => {}
- Err(NOTIFIED) => {
- // We must read here, even though we know it will be `NOTIFIED`.
- // This is because `unpark` may have been called again since we read
- // `NOTIFIED` in the `compare_exchange` above. We must perform an
- // acquire operation that synchronizes with that `unpark` to observe
- // any writes it made before the call to unpark. To do that we must
- // read from the write it made to `state`.
- let old = self.state.swap(EMPTY, SeqCst);
- assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
- return;
- } // should consume this notification, so prohibit spurious wakeups in next park.
- Err(_) => panic!("inconsistent park state"),
- }
- loop {
- m = self.cvar.wait(m).unwrap();
- match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
- Ok(_) => return, // got a notification
- Err(_) => {} // spurious wakeup, go back to sleep
- }
- }
- }
-
- // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
- pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
- // Like `park` above we have a fast path for an already-notified thread, and
- // afterwards we start coordinating for a sleep.
- // return quickly.
- if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
- return;
- }
- let m = self.lock.lock().unwrap();
- match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
- Ok(_) => {}
- Err(NOTIFIED) => {
- // We must read again here, see `park`.
- let old = self.state.swap(EMPTY, SeqCst);
- assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
- return;
- } // should consume this notification, so prohibit spurious wakeups in next park.
- Err(_) => panic!("inconsistent park_timeout state"),
- }
-
- // Wait with a timeout, and if we spuriously wake up or otherwise wake up
- // from a notification we just want to unconditionally set the state back to
- // empty, either consuming a notification or un-flagging ourselves as
- // parked.
- let (_m, _result) = self.cvar.wait_timeout(m, dur).unwrap();
- match self.state.swap(EMPTY, SeqCst) {
- NOTIFIED => {} // got a notification, hurray!
- PARKED => {} // no notification, alas
- n => panic!("inconsistent park_timeout state: {n}"),
- }
- }
-
- // This implementation doesn't require `Pin`, but other implementations do.
- pub fn unpark(self: Pin<&Self>) {
- // To ensure the unparked thread will observe any writes we made
- // before this call, we must perform a release operation that `park`
- // can synchronize with. To do that we must write `NOTIFIED` even if
- // `state` is already `NOTIFIED`. That is why this must be a swap
- // rather than a compare-and-swap that returns if it reads `NOTIFIED`
- // on failure.
- match self.state.swap(NOTIFIED, SeqCst) {
- EMPTY => return, // no one was waiting
- NOTIFIED => return, // already unparked
- PARKED => {} // gotta go wake someone up
- _ => panic!("inconsistent state in unpark"),
- }
-
- // There is a period between when the parked thread sets `state` to
- // `PARKED` (or last checked `state` in the case of a spurious wake
- // up) and when it actually waits on `cvar`. If we were to notify
- // during this period it would be ignored and then when the parked
- // thread went to sleep it would never wake up. Fortunately, it has
- // `lock` locked at this stage so we can acquire `lock` to wait until
- // it is ready to receive the notification.
- //
- // Releasing `lock` before the call to `notify_one` means that when the
- // parked thread wakes it doesn't get woken only to have to wait for us
- // to release `lock`.
- drop(self.lock.lock().unwrap());
- self.cvar.notify_one()
- }
-}
+++ /dev/null
-cfg_if::cfg_if! {
- if #[cfg(any(
- target_os = "linux",
- target_os = "android",
- all(target_arch = "wasm32", target_feature = "atomics"),
- target_os = "freebsd",
- target_os = "openbsd",
- target_os = "dragonfly",
- target_os = "fuchsia",
- target_os = "hermit",
- ))] {
- mod futex;
- pub use futex::Parker;
- } else if #[cfg(target_os = "solid_asp3")] {
- mod wait_flag;
- pub use wait_flag::Parker;
- } else if #[cfg(any(windows, target_family = "unix"))] {
- pub use crate::sys::thread_parker::Parker;
- } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
- pub use crate::sys::thread_parker::Parker;
- } else {
- mod generic;
- pub use generic::Parker;
- }
-}
+++ /dev/null
-//! A wait-flag-based thread parker.
-//!
-//! Some operating systems provide low-level parking primitives like wait counts,
-//! event flags or semaphores which are not susceptible to race conditions (meaning
-//! the wakeup can occur before the wait operation). To implement the `std` thread
-//! parker on top of these primitives, we only have to ensure that parking is fast
-//! when the thread token is available, the atomic ordering guarantees are maintained
-//! and spurious wakeups are minimized.
-//!
-//! To achieve this, this parker uses an atomic variable with three states: `EMPTY`,
-//! `PARKED` and `NOTIFIED`:
-//! * `EMPTY` means the token has not been made available, but the thread is not
-//! currently waiting on it.
-//! * `PARKED` means the token is not available and the thread is parked.
-//! * `NOTIFIED` means the token is available.
-//!
-//! `park` and `park_timeout` change the state from `EMPTY` to `PARKED` and from
-//! `NOTIFIED` to `EMPTY`. If the state was `NOTIFIED`, the thread was unparked and
-//! execution can continue without calling into the OS. If the state was `EMPTY`,
-//! the token is not available and the thread waits on the primitive (here called
-//! "wait flag").
-//!
-//! `unpark` changes the state to `NOTIFIED`. If the state was `PARKED`, the thread
-//! is or will be sleeping on the wait flag, so we raise it.
-
-use crate::pin::Pin;
-use crate::sync::atomic::AtomicI8;
-use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
-use crate::sys::wait_flag::WaitFlag;
-use crate::time::Duration;
-
-const EMPTY: i8 = 0;
-const PARKED: i8 = -1;
-const NOTIFIED: i8 = 1;
-
-pub struct Parker {
- state: AtomicI8,
- wait_flag: WaitFlag,
-}
-
-impl Parker {
- /// Construct a parker for the current thread. The UNIX parker
- /// implementation requires this to happen in-place.
- pub unsafe fn new(parker: *mut Parker) {
- parker.write(Parker { state: AtomicI8::new(EMPTY), wait_flag: WaitFlag::new() })
- }
-
- // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
- pub unsafe fn park(self: Pin<&Self>) {
- match self.state.fetch_sub(1, Acquire) {
- // NOTIFIED => EMPTY
- NOTIFIED => return,
- // EMPTY => PARKED
- EMPTY => (),
- _ => panic!("inconsistent park state"),
- }
-
- // Avoid waking up from spurious wakeups (these are quite likely, see below).
- loop {
- self.wait_flag.wait();
-
- match self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed) {
- Ok(_) => return,
- Err(PARKED) => (),
- Err(_) => panic!("inconsistent park state"),
- }
- }
- }
-
- // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
- pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
- match self.state.fetch_sub(1, Acquire) {
- NOTIFIED => return,
- EMPTY => (),
- _ => panic!("inconsistent park state"),
- }
-
- self.wait_flag.wait_timeout(dur);
-
- // Either a wakeup or a timeout occurred. Wakeups may be spurious, as there can be
- // a race condition when `unpark` is performed between receiving the timeout and
- // resetting the state, resulting in the eventflag being set unnecessarily. `park`
- // is protected against this by looping until the token is actually given, but
- // here we cannot easily tell.
-
- // Use `swap` to provide acquire ordering.
- match self.state.swap(EMPTY, Acquire) {
- NOTIFIED => (),
- PARKED => (),
- _ => panic!("inconsistent park state"),
- }
- }
-
- // This implementation doesn't require `Pin`, but other implementations do.
- pub fn unpark(self: Pin<&Self>) {
- let state = self.state.swap(NOTIFIED, Release);
-
- if state == PARKED {
- self.wait_flag.raise();
- }
- }
-}
--- /dev/null
+use crate::pin::Pin;
+use crate::sync::atomic::AtomicU32;
+use crate::sync::atomic::Ordering::{Acquire, Release};
+use crate::sys::futex::{futex_wait, futex_wake};
+use crate::time::Duration;
+
+const PARKED: u32 = u32::MAX;
+const EMPTY: u32 = 0;
+const NOTIFIED: u32 = 1;
+
+pub struct Parker {
+ state: AtomicU32,
+}
+
+// Notes about memory ordering:
+//
+// Memory ordering is only relevant for the relative ordering of operations
+// between different variables. Even Ordering::Relaxed guarantees a
+// monotonic/consistent order when looking at just a single atomic variable.
+//
+// So, since this parker is just a single atomic variable, we only need to look
+// at the ordering guarantees we need to provide to the 'outside world'.
+//
+// The only memory ordering guarantee that parking and unparking provide, is
+// that things which happened before unpark() are visible on the thread
+// returning from park() afterwards. Otherwise, it was effectively unparked
+// before unpark() was called while still consuming the 'token'.
+//
+// In other words, unpark() needs to synchronize with the part of park() that
+// consumes the token and returns.
+//
+// This is done with a release-acquire synchronization, by using
+// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
+// Ordering::Acquire when checking for this state in park().
+impl Parker {
+ /// Construct the futex parker. The UNIX parker implementation
+ /// requires this to happen in-place.
+ pub unsafe fn new_in_place(parker: *mut Parker) {
+ parker.write(Self { state: AtomicU32::new(EMPTY) });
+ }
+
+ // Assumes this is only called by the thread that owns the Parker,
+ // which means that `self.state != PARKED`.
+ pub unsafe fn park(self: Pin<&Self>) {
+ // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
+ // first case.
+ if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+ return;
+ }
+ loop {
+ // Wait for something to happen, assuming it's still set to PARKED.
+ futex_wait(&self.state, PARKED, None);
+ // Change NOTIFIED=>EMPTY and return in that case.
+ if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() {
+ return;
+ } else {
+ // Spurious wake up. We loop to try again.
+ }
+ }
+ }
+
+ // Assumes this is only called by the thread that owns the Parker,
+ // which means that `self.state != PARKED`. This implementation doesn't
+ // require `Pin`, but other implementations do.
+ pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) {
+ // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
+ // first case.
+ if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+ return;
+ }
+ // Wait for something to happen, assuming it's still set to PARKED.
+ futex_wait(&self.state, PARKED, Some(timeout));
+ // This is not just a store, because we need to establish a
+ // release-acquire ordering with unpark().
+ if self.state.swap(EMPTY, Acquire) == NOTIFIED {
+ // Woke up because of unpark().
+ } else {
+ // Timeout or spurious wake up.
+ // We return either way, because we can't easily tell if it was the
+ // timeout or not.
+ }
+ }
+
+ // This implementation doesn't require `Pin`, but other implementations do.
+ #[inline]
+ pub fn unpark(self: Pin<&Self>) {
+ // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
+ // wake the thread in the first case.
+ //
+ // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
+ // purpose, to make sure every unpark() has a release-acquire ordering
+ // with park().
+ if self.state.swap(NOTIFIED, Release) == PARKED {
+ futex_wake(&self.state);
+ }
+ }
+}
--- /dev/null
+//! Parker implementation based on a Mutex and Condvar.
+
+use crate::pin::Pin;
+use crate::sync::atomic::AtomicUsize;
+use crate::sync::atomic::Ordering::SeqCst;
+use crate::sync::{Condvar, Mutex};
+use crate::time::Duration;
+
+const EMPTY: usize = 0;
+const PARKED: usize = 1;
+const NOTIFIED: usize = 2;
+
+pub struct Parker {
+ state: AtomicUsize,
+ lock: Mutex<()>,
+ cvar: Condvar,
+}
+
+impl Parker {
+ /// Construct the generic parker. The UNIX parker implementation
+ /// requires this to happen in-place.
+ pub unsafe fn new_in_place(parker: *mut Parker) {
+ parker.write(Parker {
+ state: AtomicUsize::new(EMPTY),
+ lock: Mutex::new(()),
+ cvar: Condvar::new(),
+ });
+ }
+
+ // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+ pub unsafe fn park(self: Pin<&Self>) {
+ // If we were previously notified then we consume this notification and
+ // return quickly.
+ if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+ return;
+ }
+
+ // Otherwise we need to coordinate going to sleep
+ let mut m = self.lock.lock().unwrap();
+ match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+ Ok(_) => {}
+ Err(NOTIFIED) => {
+ // We must read here, even though we know it will be `NOTIFIED`.
+ // This is because `unpark` may have been called again since we read
+ // `NOTIFIED` in the `compare_exchange` above. We must perform an
+ // acquire operation that synchronizes with that `unpark` to observe
+ // any writes it made before the call to unpark. To do that we must
+ // read from the write it made to `state`.
+ let old = self.state.swap(EMPTY, SeqCst);
+ assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+ return;
+ } // should consume this notification, so prohibit spurious wakeups in next park.
+ Err(_) => panic!("inconsistent park state"),
+ }
+ loop {
+ m = self.cvar.wait(m).unwrap();
+ match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
+ Ok(_) => return, // got a notification
+ Err(_) => {} // spurious wakeup, go back to sleep
+ }
+ }
+ }
+
+ // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+ pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+ // Like `park` above we have a fast path for an already-notified thread, and
+ // afterwards we start coordinating for a sleep.
+ // return quickly.
+ if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+ return;
+ }
+ let m = self.lock.lock().unwrap();
+ match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+ Ok(_) => {}
+ Err(NOTIFIED) => {
+ // We must read again here, see `park`.
+ let old = self.state.swap(EMPTY, SeqCst);
+ assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+ return;
+ } // should consume this notification, so prohibit spurious wakeups in next park.
+ Err(_) => panic!("inconsistent park_timeout state"),
+ }
+
+ // Wait with a timeout, and if we spuriously wake up or otherwise wake up
+ // from a notification we just want to unconditionally set the state back to
+ // empty, either consuming a notification or un-flagging ourselves as
+ // parked.
+ let (_m, _result) = self.cvar.wait_timeout(m, dur).unwrap();
+ match self.state.swap(EMPTY, SeqCst) {
+ NOTIFIED => {} // got a notification, hurray!
+ PARKED => {} // no notification, alas
+ n => panic!("inconsistent park_timeout state: {n}"),
+ }
+ }
+
+ // This implementation doesn't require `Pin`, but other implementations do.
+ pub fn unpark(self: Pin<&Self>) {
+ // To ensure the unparked thread will observe any writes we made
+ // before this call, we must perform a release operation that `park`
+ // can synchronize with. To do that we must write `NOTIFIED` even if
+ // `state` is already `NOTIFIED`. That is why this must be a swap
+ // rather than a compare-and-swap that returns if it reads `NOTIFIED`
+ // on failure.
+ match self.state.swap(NOTIFIED, SeqCst) {
+ EMPTY => return, // no one was waiting
+ NOTIFIED => return, // already unparked
+ PARKED => {} // gotta go wake someone up
+ _ => panic!("inconsistent state in unpark"),
+ }
+
+ // There is a period between when the parked thread sets `state` to
+ // `PARKED` (or last checked `state` in the case of a spurious wake
+ // up) and when it actually waits on `cvar`. If we were to notify
+ // during this period it would be ignored and then when the parked
+ // thread went to sleep it would never wake up. Fortunately, it has
+ // `lock` locked at this stage so we can acquire `lock` to wait until
+ // it is ready to receive the notification.
+ //
+ // Releasing `lock` before the call to `notify_one` means that when the
+ // parked thread wakes it doesn't get woken only to have to wait for us
+ // to release `lock`.
+ drop(self.lock.lock().unwrap());
+ self.cvar.notify_one()
+ }
+}
--- /dev/null
+//! Thread parking using thread ids.
+//!
+//! Some platforms (notably NetBSD) have thread parking primitives whose semantics
+//! match those offered by `thread::park`, with the difference that the thread to
+//! be unparked is referenced by a platform-specific thread id. Since the thread
+//! parker is constructed before that id is known, an atomic state variable is used
+//! to manage the park state and propagate the thread id. This also avoids platform
+//! calls in the case where `unpark` is called before `park`.
+
+use crate::cell::UnsafeCell;
+use crate::pin::Pin;
+use crate::sync::atomic::{
+ fence, AtomicI8,
+ Ordering::{Acquire, Relaxed, Release},
+};
+use crate::sys::thread_parking::{current, park, park_timeout, unpark, ThreadId};
+use crate::time::Duration;
+
+pub struct Parker {
+ state: AtomicI8,
+ tid: UnsafeCell<Option<ThreadId>>,
+}
+
+const PARKED: i8 = -1;
+const EMPTY: i8 = 0;
+const NOTIFIED: i8 = 1;
+
+impl Parker {
+ pub fn new() -> Parker {
+ Parker { state: AtomicI8::new(EMPTY), tid: UnsafeCell::new(None) }
+ }
+
+ /// Create a new thread parker. UNIX requires this to happen in-place.
+ pub unsafe fn new_in_place(parker: *mut Parker) {
+ parker.write(Parker::new())
+ }
+
+ /// # Safety
+ /// * must always be called from the same thread
+ /// * must be called before the state is set to PARKED
+ unsafe fn init_tid(&self) {
+ // The field is only ever written to from this thread, so we don't need
+ // synchronization to read it here.
+ if self.tid.get().read().is_none() {
+ // Because this point is only reached once, before the state is set
+ // to PARKED for the first time, the non-atomic write here can not
+ // conflict with reads by other threads.
+ self.tid.get().write(Some(current()));
+ // Ensure that the write can be observed by all threads reading the
+ // state. Synchronizes with the acquire barrier in `unpark`.
+ fence(Release);
+ }
+ }
+
+ pub unsafe fn park(self: Pin<&Self>) {
+ self.init_tid();
+
+ // Changes NOTIFIED to EMPTY and EMPTY to PARKED.
+ let mut state = self.state.fetch_sub(1, Acquire).wrapping_sub(1);
+ if state == PARKED {
+ // Loop to guard against spurious wakeups.
+ while state == PARKED {
+ park(self.state.as_mut_ptr().addr());
+ state = self.state.load(Acquire);
+ }
+
+ // Since the state change has already been observed with acquire
+ // ordering, the state can be reset with a relaxed store instead
+ // of a swap.
+ self.state.store(EMPTY, Relaxed);
+ }
+ }
+
+ pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+ self.init_tid();
+
+ let state = self.state.fetch_sub(1, Acquire).wrapping_sub(1);
+ if state == PARKED {
+ park_timeout(dur, self.state.as_mut_ptr().addr());
+ // Swap to ensure that we observe all state changes with acquire
+ // ordering, even if the state has been changed after the timeout
+ // occured.
+ self.state.swap(EMPTY, Acquire);
+ }
+ }
+
+ pub fn unpark(self: Pin<&Self>) {
+ let state = self.state.swap(NOTIFIED, Release);
+ if state == PARKED {
+ // Synchronize with the release fence in `init_tid` to observe the
+ // write to `tid`.
+ fence(Acquire);
+ // # Safety
+ // The thread id is initialized before the state is set to `PARKED`
+ // for the first time and is not written to from that point on
+ // (negating the need for an atomic read).
+ let tid = unsafe { self.tid.get().read().unwrap_unchecked() };
+ // It is possible that the waiting thread woke up because of a timeout
+ // and terminated before this call is made. This call then returns an
+ // error or wakes up an unrelated thread. The platform API and
+ // environment does allow this, however.
+ unpark(tid, self.state.as_mut_ptr().addr());
+ }
+ }
+}
+
+unsafe impl Send for Parker {}
+unsafe impl Sync for Parker {}
--- /dev/null
+cfg_if::cfg_if! {
+ if #[cfg(any(
+ target_os = "linux",
+ target_os = "android",
+ all(target_arch = "wasm32", target_feature = "atomics"),
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "dragonfly",
+ target_os = "fuchsia",
+ target_os = "hermit",
+ ))] {
+ mod futex;
+ pub use futex::Parker;
+ } else if #[cfg(any(
+ target_os = "netbsd",
+ all(target_vendor = "fortanix", target_env = "sgx"),
+ ))] {
+ mod id;
+ pub use id::Parker;
+ } else if #[cfg(target_os = "solid_asp3")] {
+ mod wait_flag;
+ pub use wait_flag::Parker;
+ } else if #[cfg(any(windows, target_family = "unix"))] {
+ pub use crate::sys::thread_parking::Parker;
+ } else {
+ mod generic;
+ pub use generic::Parker;
+ }
+}
--- /dev/null
+//! A wait-flag-based thread parker.
+//!
+//! Some operating systems provide low-level parking primitives like wait counts,
+//! event flags or semaphores which are not susceptible to race conditions (meaning
+//! the wakeup can occur before the wait operation). To implement the `std` thread
+//! parker on top of these primitives, we only have to ensure that parking is fast
+//! when the thread token is available, the atomic ordering guarantees are maintained
+//! and spurious wakeups are minimized.
+//!
+//! To achieve this, this parker uses an atomic variable with three states: `EMPTY`,
+//! `PARKED` and `NOTIFIED`:
+//! * `EMPTY` means the token has not been made available, but the thread is not
+//! currently waiting on it.
+//! * `PARKED` means the token is not available and the thread is parked.
+//! * `NOTIFIED` means the token is available.
+//!
+//! `park` and `park_timeout` change the state from `EMPTY` to `PARKED` and from
+//! `NOTIFIED` to `EMPTY`. If the state was `NOTIFIED`, the thread was unparked and
+//! execution can continue without calling into the OS. If the state was `EMPTY`,
+//! the token is not available and the thread waits on the primitive (here called
+//! "wait flag").
+//!
+//! `unpark` changes the state to `NOTIFIED`. If the state was `PARKED`, the thread
+//! is or will be sleeping on the wait flag, so we raise it.
+
+use crate::pin::Pin;
+use crate::sync::atomic::AtomicI8;
+use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
+use crate::sys::wait_flag::WaitFlag;
+use crate::time::Duration;
+
+const EMPTY: i8 = 0;
+const PARKED: i8 = -1;
+const NOTIFIED: i8 = 1;
+
+pub struct Parker {
+ state: AtomicI8,
+ wait_flag: WaitFlag,
+}
+
+impl Parker {
+ /// Construct a parker for the current thread. The UNIX parker
+ /// implementation requires this to happen in-place.
+ pub unsafe fn new_in_place(parker: *mut Parker) {
+ parker.write(Parker { state: AtomicI8::new(EMPTY), wait_flag: WaitFlag::new() })
+ }
+
+ // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+ pub unsafe fn park(self: Pin<&Self>) {
+ match self.state.fetch_sub(1, Acquire) {
+ // NOTIFIED => EMPTY
+ NOTIFIED => return,
+ // EMPTY => PARKED
+ EMPTY => (),
+ _ => panic!("inconsistent park state"),
+ }
+
+ // Avoid waking up from spurious wakeups (these are quite likely, see below).
+ loop {
+ self.wait_flag.wait();
+
+ match self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed) {
+ Ok(_) => return,
+ Err(PARKED) => (),
+ Err(_) => panic!("inconsistent park state"),
+ }
+ }
+ }
+
+ // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+ pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+ match self.state.fetch_sub(1, Acquire) {
+ NOTIFIED => return,
+ EMPTY => (),
+ _ => panic!("inconsistent park state"),
+ }
+
+ self.wait_flag.wait_timeout(dur);
+
+ // Either a wakeup or a timeout occurred. Wakeups may be spurious, as there can be
+ // a race condition when `unpark` is performed between receiving the timeout and
+ // resetting the state, resulting in the eventflag being set unnecessarily. `park`
+ // is protected against this by looping until the token is actually given, but
+ // here we cannot easily tell.
+
+ // Use `swap` to provide acquire ordering.
+ match self.state.swap(EMPTY, Acquire) {
+ NOTIFIED => (),
+ PARKED => (),
+ _ => panic!("inconsistent park state"),
+ }
+ }
+
+ // This implementation doesn't require `Pin`, but other implementations do.
+ pub fn unpark(self: Pin<&Self>) {
+ let state = self.state.swap(NOTIFIED, Release);
+
+ if state == PARKED {
+ self.wait_flag.raise();
+ }
+ }
+}
pub mod fast {
use super::lazy::LazyKeyInner;
use crate::cell::Cell;
- use crate::fmt;
- use crate::mem;
use crate::sys::thread_local_dtor::register_dtor;
+ use crate::{fmt, mem, panic};
#[derive(Copy, Clone)]
enum DtorState {
// note that this is just a publicly-callable function only for the
// const-initialized form of thread locals, basically a way to call the
- // free `register_dtor` function defined elsewhere in libstd.
+ // free `register_dtor` function defined elsewhere in std.
pub unsafe fn register_dtor(a: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
unsafe {
register_dtor(a, dtor);
// `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
// causes future calls to `get` to run `try_initialize_drop` again,
// which will now fail, and return `None`.
- unsafe {
+ //
+ // Wrap the call in a catch to ensure unwinding is caught in the event
+ // a panic takes place in a destructor.
+ if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe {
let value = (*ptr).inner.take();
(*ptr).dtor_state.set(DtorState::RunningOrHasRun);
drop(value);
+ })) {
+ rtabort!("thread local panicked on drop");
}
}
}
pub mod os {
use super::lazy::LazyKeyInner;
use crate::cell::Cell;
- use crate::fmt;
- use crate::marker;
- use crate::ptr;
use crate::sys_common::thread_local_key::StaticKey as OsStaticKey;
+ use crate::{fmt, marker, panic, ptr};
/// Use a regular global static to store this key; the state provided will then be
/// thread-local.
//
// Note that to prevent an infinite loop we reset it back to null right
// before we return from the destructor ourselves.
- unsafe {
+ //
+ // Wrap the call in a catch to ensure unwinding is caught in the event
+ // a panic takes place in a destructor.
+ if let Err(_) = panic::catch_unwind(|| unsafe {
let ptr = Box::from_raw(ptr as *mut Value<T>);
let key = ptr.key;
key.os.set(ptr::invalid_mut(1));
drop(ptr);
key.os.set(ptr::null_mut());
+ }) {
+ rtabort!("thread local panicked on drop");
}
}
}
use crate::sys::thread as imp;
use crate::sys_common::thread;
use crate::sys_common::thread_info;
-use crate::sys_common::thread_parker::Parker;
+use crate::sys_common::thread_parking::Parker;
use crate::sys_common::{AsInner, IntoInner};
use crate::time::Duration;
let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr();
addr_of_mut!((*ptr).name).write(name);
addr_of_mut!((*ptr).id).write(ThreadId::new());
- Parker::new(addr_of_mut!((*ptr).parker));
+ Parker::new_in_place(addr_of_mut!((*ptr).parker));
Pin::new_unchecked(arc.assume_init())
};
use std::env::*;
use std::ffi::{OsStr, OsString};
-use rand::distributions::Alphanumeric;
-use rand::{thread_rng, Rng};
+use rand::distributions::{Alphanumeric, DistString};
+
+/// Copied from `std::test_helpers::test_rng`, since these tests rely on the
+/// seed not being the same for every RNG invocation too.
+#[track_caller]
+pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
+ use core::hash::{BuildHasher, Hash, Hasher};
+ let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
+ core::panic::Location::caller().hash(&mut hasher);
+ let hc64 = hasher.finish();
+ let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
+ let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
+ rand::SeedableRng::from_seed(seed)
+}
+#[track_caller]
fn make_rand_name() -> OsString {
- let rng = thread_rng();
- let n = format!("TEST{}", rng.sample_iter(&Alphanumeric).take(10).collect::<String>());
+ let n = format!("TEST{}", Alphanumeric.sample_string(&mut test_rng(), 10));
let n = OsString::from(n);
assert!(var_os(&n).is_none());
n
-//! These tests just check that the macros are available in libstd.
+//! These tests just check that the macros are available in std.
#![cfg_attr(
any(
all(target_arch = "arm", any(target_os = "linux", target_os = "android")),
- all(bootstrap, target_arch = "aarch64", any(target_os = "linux", target_os = "android")),
all(target_arch = "powerpc", target_os = "linux"),
all(target_arch = "powerpc64", target_os = "linux"),
),
let mut ntest = 0;
let mut nbench = 0;
- for test in filter_tests(&opts, tests).into_iter() {
+ for test in filter_tests(opts, tests).into_iter() {
use crate::TestFn::*;
let TestDescAndFn { desc: TestDesc { name, .. }, testfn } = test;
let stdout = &completed_test.stdout;
st.write_log_result(test, result, exec_time.as_ref())?;
- out.write_result(test, result, exec_time.as_ref(), &*stdout, st)?;
+ out.write_result(test, result, exec_time.as_ref(), stdout, st)?;
handle_test_result(st, completed_test);
}
}
let max_name_len = tests
.iter()
- .max_by_key(|t| len_if_padded(*t))
+ .max_by_key(|t| len_if_padded(t))
.map(|t| t.desc.name.as_slice().len())
.unwrap_or(0);
extra: Option<&str>,
) -> io::Result<()> {
// A doc test's name includes a filename which must be escaped for correct json.
- self.write_message(&*format!(
+ self.write_message(&format!(
r#"{{ "type": "{}", "name": "{}", "event": "{}""#,
ty,
EscapedString(name),
evt
))?;
if let Some(exec_time) = exec_time {
- self.write_message(&*format!(r#", "exec_time": {}"#, exec_time.0.as_secs_f64()))?;
+ self.write_message(&format!(r#", "exec_time": {}"#, exec_time.0.as_secs_f64()))?;
}
if let Some(stdout) = stdout {
- self.write_message(&*format!(r#", "stdout": "{}""#, EscapedString(stdout)))?;
+ self.write_message(&format!(r#", "stdout": "{}""#, EscapedString(stdout)))?;
}
if let Some(extra) = extra {
- self.write_message(&*format!(r#", {extra}"#))?;
+ self.write_message(&format!(r#", {extra}"#))?;
}
self.writeln_message(" }")
}
} else {
String::new()
};
- self.writeln_message(&*format!(
+ self.writeln_message(&format!(
r#"{{ "type": "suite", "event": "started", "test_count": {test_count}{shuffle_seed_json} }}"#
))
}
fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
- self.writeln_message(&*format!(
+ self.writeln_message(&format!(
r#"{{ "type": "test", "event": "started", "name": "{}" }}"#,
EscapedString(desc.name.as_slice())
))
mbps
);
- self.writeln_message(&*line)
+ self.writeln_message(&line)
}
}
}
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
- self.writeln_message(&*format!(
+ self.writeln_message(&format!(
r#"{{ "type": "test", "event": "timeout", "name": "{}" }}"#,
EscapedString(desc.name.as_slice())
))
}
fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
- self.write_message(&*format!(
+ self.write_message(&format!(
"{{ \"type\": \"suite\", \
\"event\": \"{}\", \
\"passed\": {}, \
fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
self.write_message("<testsuites>")?;
- self.write_message(&*format!(
+ self.write_message(&format!(
"<testsuite name=\"test\" package=\"test\" id=\"0\" \
errors=\"0\" \
failures=\"{}\" \
>",
state.failed, state.total, state.ignored
))?;
- for (desc, result, duration) in std::mem::replace(&mut self.results, Vec::new()) {
+ for (desc, result, duration) in std::mem::take(&mut self.results) {
let (class_name, test_name) = parse_class_name(&desc);
match result {
TestResult::TrIgnored => { /* no-op */ }
TestResult::TrFailed => {
- self.write_message(&*format!(
+ self.write_message(&format!(
"<testcase classname=\"{}\" \
name=\"{}\" time=\"{}\">",
class_name,
}
TestResult::TrFailedMsg(ref m) => {
- self.write_message(&*format!(
+ self.write_message(&format!(
"<testcase classname=\"{}\" \
name=\"{}\" time=\"{}\">",
class_name,
test_name,
duration.as_secs_f64()
))?;
- self.write_message(&*format!("<failure message=\"{m}\" type=\"assert\"/>"))?;
+ self.write_message(&format!("<failure message=\"{m}\" type=\"assert\"/>"))?;
self.write_message("</testcase>")?;
}
TestResult::TrTimedFail => {
- self.write_message(&*format!(
+ self.write_message(&format!(
"<testcase classname=\"{}\" \
name=\"{}\" time=\"{}\">",
class_name,
}
TestResult::TrBench(ref b) => {
- self.write_message(&*format!(
+ self.write_message(&format!(
"<testcase classname=\"benchmark::{}\" \
name=\"{}\" time=\"{}\" />",
class_name, test_name, b.ns_iter_summ.sum
}
TestResult::TrOk => {
- self.write_message(&*format!(
+ self.write_message(&format!(
"<testcase classname=\"{}\" \
name=\"{}\" time=\"{}\"/>",
class_name,
let mut results = Vec::new();
let mut stdouts = String::new();
- for &(ref f, ref stdout) in inputs {
+ for (f, stdout) in inputs {
results.push(f.name.to_string());
if !stdout.is_empty() {
stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
let name = desc.padded_name(self.max_name_len, desc.name.padding());
if let Some(test_mode) = desc.test_mode() {
- self.write_plain(&format!("test {name} - {test_mode} ... "))?;
+ self.write_plain(format!("test {name} - {test_mode} ... "))?;
} else {
- self.write_plain(&format!("test {name} ... "))?;
+ self.write_plain(format!("test {name} ... "))?;
}
Ok(())
} else {
String::new()
};
- self.write_plain(&format!("\nrunning {test_count} {noun}{shuffle_seed_msg}\n"))
+ self.write_plain(format!("\nrunning {test_count} {noun}{shuffle_seed_msg}\n"))
}
fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
TestResult::TrIgnored => self.write_ignored(desc.ignore_message)?,
TestResult::TrBench(ref bs) => {
self.write_bench()?;
- self.write_plain(&format!(": {}", fmt_bench_samples(bs)))?;
+ self.write_plain(format!(": {}", fmt_bench_samples(bs)))?;
}
TestResult::TrTimedFail => self.write_time_failed()?,
}
}
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
- self.write_plain(&format!(
+ self.write_plain(format!(
"test {} has been running for over {} seconds\n",
desc.name,
time::TEST_WARN_TIMEOUT_S
state.passed, state.failed, state.ignored, state.measured, state.filtered_out
);
- self.write_plain(&s)?;
+ self.write_plain(s)?;
if let Some(ref exec_time) = state.exec_time {
let time_str = format!("; finished in {exec_time}");
- self.write_plain(&time_str)?;
+ self.write_plain(time_str)?;
}
self.write_plain("\n\n")?;
// screen when dealing with line-buffered output (e.g., piping to
// `stamp` in the rust CI).
let out = format!(" {}/{}\n", self.test_count + 1, self.total_test_count);
- self.write_plain(&out)?;
+ self.write_plain(out)?;
}
self.test_count += 1;
self.write_plain("\nsuccesses:\n")?;
let mut successes = Vec::new();
let mut stdouts = String::new();
- for &(ref f, ref stdout) in &state.not_failures {
+ for (f, stdout) in &state.not_failures {
successes.push(f.name.to_string());
if !stdout.is_empty() {
stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
self.write_plain("\nfailures:\n")?;
let mut failures = Vec::new();
let mut fail_out = String::new();
- for &(ref f, ref stdout) in &state.failures {
+ for (f, stdout) in &state.failures {
failures.push(f.name.to_string());
if !stdout.is_empty() {
fail_out.push_str(&format!("---- {} stdout ----\n", f.name));
fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
let name = desc.padded_name(self.max_name_len, desc.name.padding());
if let Some(test_mode) = desc.test_mode() {
- self.write_plain(&format!("test {name} - {test_mode} ... "))?;
+ self.write_plain(format!("test {name} - {test_mode} ... "))?;
} else {
- self.write_plain(&format!("test {name} ... "))?;
+ self.write_plain(format!("test {name} ... "))?;
}
Ok(())
} else {
String::new()
};
- self.write_plain(&format!("\nrunning {test_count} {noun}{shuffle_seed_msg}\n"))
+ self.write_plain(format!("\nrunning {test_count} {noun}{shuffle_seed_msg}\n"))
}
fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
self.write_test_name(desc)?;
}
self.write_bench()?;
- self.write_plain(&format!(": {}\n", fmt_bench_samples(bs)))
+ self.write_plain(format!(": {}\n", fmt_bench_samples(bs)))
}
}
}
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
- self.write_plain(&format!(
+ self.write_plain(format!(
"test {} has been running for over {} seconds\n",
desc.name,
time::TEST_WARN_TIMEOUT_S
state.passed, state.failed, state.ignored, state.measured, state.filtered_out
);
- self.write_plain(&s)?;
+ self.write_plain(s)?;
if let Some(ref exec_time) = state.exec_time {
let time_str = format!("; finished in {exec_time}");
- self.write_plain(&time_str)?;
+ self.write_plain(time_str)?;
}
self.write_plain("\n\n")?;
}
});
let record_result2 = record_result.clone();
- panic::set_hook(Box::new(move |info| record_result2(Some(&info))));
+ panic::set_hook(Box::new(move |info| record_result2(Some(info))));
if let Err(message) = testfn() {
panic!("{}", message);
}
// are there any terminals that have color/attrs and not sgr0?
// Try falling back to sgr, then op
let cmd = match ["sgr0", "sgr", "op"].iter().find_map(|cap| self.ti.strings.get(*cap)) {
- Some(op) => match expand(&op, &[], &mut Variables::new()) {
+ Some(op) => match expand(op, &[], &mut Variables::new()) {
Ok(cmd) => cmd,
Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidData, e)),
},
}
fn dim_if_necessary(&self, color: color::Color) -> color::Color {
- if color >= self.num_colors && color >= 8 && color < 16 { color - 8 } else { color }
+ if color >= self.num_colors && (8..16).contains(&color) { color - 8 } else { color }
}
fn apply_cap(&mut self, cmd: &str, params: &[Param]) -> io::Result<bool> {
match self.ti.strings.get(cmd) {
- Some(cmd) => match expand(&cmd, params, &mut Variables::new()) {
+ Some(cmd) => match expand(cmd, params, &mut Variables::new()) {
Ok(s) => self.out.write_all(&s).and(Ok(true)),
Err(e) => Err(io::Error::new(io::ErrorKind::InvalidData, e)),
},
);
}
SetVar => {
- if cur >= 'A' && cur <= 'Z' {
+ if cur.is_ascii_uppercase() {
if let Some(arg) = stack.pop() {
let idx = (cur as u8) - b'A';
vars.sta_va[idx as usize] = arg;
} else {
return Err("stack is empty".to_string());
}
- } else if cur >= 'a' && cur <= 'z' {
+ } else if cur.is_ascii_lowercase() {
if let Some(arg) = stack.pop() {
let idx = (cur as u8) - b'a';
vars.dyn_va[idx as usize] = arg;
}
}
GetVar => {
- if cur >= 'A' && cur <= 'Z' {
+ if cur.is_ascii_uppercase() {
let idx = (cur as u8) - b'A';
stack.push(vars.sta_va[idx as usize].clone());
- } else if cur >= 'a' && cur <= 'z' {
+ } else if cur.is_ascii_lowercase() {
let idx = (cur as u8) - b'a';
stack.push(vars.dyn_va[idx as usize].clone());
} else {
if let Ok(dirs) = env::var("TERMINFO_DIRS") {
for i in dirs.split(':') {
- if i == "" {
+ if i.is_empty() {
dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
} else {
dirs_to_search.push(PathBuf::from(i));
for mut p in dirs_to_search {
if fs::metadata(&p).is_ok() {
p.push(&first_char.to_string());
- p.push(&term);
+ p.push(term);
if fs::metadata(&p).is_ok() {
return Some(p);
}
) -> TestResult {
let result = match (&desc.should_panic, task_result) {
(&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TestResult::TrOk,
- (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => {
+ (&ShouldPanic::YesWithMessage(msg), Err(err)) => {
let maybe_panic_str = err
.downcast_ref::<String>()
.map(|e| &**e)
r#"expected panic with string value,
found non-string value: `{:?}`
expected substring: `{:?}`"#,
- (**err).type_id(),
+ (*err).type_id(),
msg
))
}
match *self {
StaticTestName(s) => s,
DynTestName(ref s) => s,
- AlignedTestName(ref s, _) => &*s,
+ AlignedTestName(ref s, _) => s,
}
}
extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception);
// FIXME: The `#[link]` attributes on `extern "C"` block marks those symbols declared in
-// the block are reexported in dylib build of libstd. This is needed when build rustc with
+// the block are reexported in dylib build of std. This is needed when build rustc with
// feature `llvm-libunwind', as no other cdylib will provided those _Unwind_* symbols.
// However the `link` attribute is duplicated multiple times and does not just export symbol,
// a better way to manually export symbol would be another attribute like `#[export]`.
- Several unsupported `./configure` options have been removed: `optimize`, `parallel-compiler`. These can still be enabled with `--set`, although it isn't recommended.
- `remote-test-server`'s `verbose` argument has been removed in favor of the `--verbose` flag
- `remote-test-server`'s `remote` argument has been removed in favor of the `--bind` flag. Use `--bind 0.0.0.0:12345` to replicate the behavior of the `remote` argument.
+- `x.py fmt` now formats only files modified between the merge-base of HEAD and the last commit in the master branch of the rust-lang repository and the current working directory. To restore old behaviour, use `x.py fmt .`. The check mode is not affected by this change. [#105702](https://github.com/rust-lang/rust/pull/105702)
### Non-breaking changes
name = "bootstrap"
version = "0.0.0"
dependencies = [
+ "build_helper",
"cc",
"cmake",
"fd-lock",
"regex-automata",
]
+[[package]]
+name = "build_helper"
+version = "0.1.0"
+
[[package]]
name = "cc"
version = "1.0.73"
test = false
[dependencies]
+build_helper = { path = "../tools/build_helper" }
cmake = "0.1.38"
fd-lock = "3.0.8"
filetime = "0.2"
target_features += ["-crt-static"]
if target_features:
env["RUSTFLAGS"] += " -C target-feature=" + (",".join(target_features))
+ target_linker = self.get_toml("linker", build_section)
+ if target_linker is not None:
+ env["RUSTFLAGS"] += " -C linker=" + target_linker
env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes"
env["RUSTFLAGS"] += " -Wsemicolon_in_expressions_from_macros"
if self.get_toml("deny-warnings", "rust") != "false":
if len(sys.argv) > 1 and sys.argv[1] == 'help':
sys.argv = [sys.argv[0], '-h'] + sys.argv[2:]
- help_triggered = (
- '-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1)
+ help_triggered = len(sys.argv) == 1 or any(x in ["-h", "--help", "--version"] for x in sys.argv)
try:
bootstrap(help_triggered)
if not help_triggered:
use crate::cache::{Cache, Interned, INTERNER};
use crate::config::{SplitDebuginfo, TargetSelection};
-use crate::dist;
use crate::doc;
use crate::flags::{Color, Subcommand};
use crate::install;
use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t};
use crate::EXTRA_CHECK_CFGS;
use crate::{check, compile, Crate};
+use crate::{clean, dist};
use crate::{Build, CLang, DocTests, GitRepo, Mode};
pub use crate::Compiler;
pub fn build_triple(&self) -> TargetSelection {
self.builder.build.build
}
+
+ /// Return a list of crate names selected by `run.paths`.
+ pub fn cargo_crates_in_set(&self) -> Interned<Vec<String>> {
+ let mut crates = Vec::new();
+ for krate in &self.paths {
+ let path = krate.assert_single_path();
+ let crate_name = self.builder.crate_paths[&path.path];
+ crates.push(crate_name.to_string());
+ }
+ INTERNER.intern_list(crates)
+ }
+}
+
+/// A description of the crates in this set, suitable for passing to `builder.info`.
+///
+/// `crates` should be generated by [`RunConfig::cargo_crates_in_set`].
+pub fn crate_description(crates: &[impl AsRef<str>]) -> String {
+ if crates.is_empty() {
+ return "".into();
+ }
+
+ let mut descr = String::from(" {");
+ descr.push_str(crates[0].as_ref());
+ for krate in &crates[1..] {
+ descr.push_str(", ");
+ descr.push_str(krate.as_ref());
+ }
+ descr.push('}');
+ descr
}
struct StepDescription {
crate::toolstate::ToolStateCheck,
test::ExpandYamlAnchors,
test::Tidy,
+ test::TidySelfTest,
test::Ui,
test::RunPassValgrind,
test::MirOpt,
run::GenerateCopyright,
),
Kind::Setup => describe!(setup::Profile),
- // These commands either don't use paths, or they're special-cased in Build::build()
- Kind::Clean | Kind::Format => vec![],
+ Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std),
+ // special-cased in Build::build()
+ Kind::Format => vec![],
}
}
Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
Subcommand::Run { ref paths, .. } => (Kind::Run, &paths[..]),
+ Subcommand::Clean { ref paths, .. } => (Kind::Clean, &paths[..]),
Subcommand::Format { .. } => (Kind::Format, &[][..]),
Subcommand::Setup { profile: ref path } => (
Kind::Setup,
path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)),
),
- Subcommand::Clean { .. } => {
- panic!()
- }
};
Self::new_internal(build, kind, paths.to_owned())
None
}
+ /// Like `cargo`, but only passes flags that are valid for all commands.
+ pub fn bare_cargo(
+ &self,
+ compiler: Compiler,
+ mode: Mode,
+ target: TargetSelection,
+ cmd: &str,
+ ) -> Command {
+ let mut cargo = Command::new(&self.initial_cargo);
+ // Run cargo from the source root so it can find .cargo/config.
+ // This matters when using vendoring and the working directory is outside the repository.
+ cargo.current_dir(&self.src);
+
+ let out_dir = self.stage_out(compiler, mode);
+ cargo.env("CARGO_TARGET_DIR", &out_dir).arg(cmd);
+
+ // Found with `rg "init_env_logger\("`. If anyone uses `init_env_logger`
+ // from out of tree it shouldn't matter, since x.py is only used for
+ // building in-tree.
+ let color_logs = ["RUSTDOC_LOG_COLOR", "RUSTC_LOG_COLOR", "RUST_LOG_COLOR"];
+ match self.build.config.color {
+ Color::Always => {
+ cargo.arg("--color=always");
+ for log in &color_logs {
+ cargo.env(log, "always");
+ }
+ }
+ Color::Never => {
+ cargo.arg("--color=never");
+ for log in &color_logs {
+ cargo.env(log, "never");
+ }
+ }
+ Color::Auto => {} // nothing to do
+ }
+
+ if cmd != "install" {
+ cargo.arg("--target").arg(target.rustc_target_arg());
+ } else {
+ assert_eq!(target, compiler.host);
+ }
+
+ if self.config.rust_optimize {
+ // FIXME: cargo bench/install do not accept `--release`
+ if cmd != "bench" && cmd != "install" {
+ cargo.arg("--release");
+ }
+ }
+
+ // Remove make-related flags to ensure Cargo can correctly set things up
+ cargo.env_remove("MAKEFLAGS");
+ cargo.env_remove("MFLAGS");
+
+ cargo
+ }
+
/// Prepares an invocation of `cargo` to be run.
///
/// This will create a `Command` that represents a pending execution of
target: TargetSelection,
cmd: &str,
) -> Cargo {
- let mut cargo = Command::new(&self.initial_cargo);
+ let mut cargo = self.bare_cargo(compiler, mode, target, cmd);
let out_dir = self.stage_out(compiler, mode);
- // Run cargo from the source root so it can find .cargo/config.
- // This matters when using vendoring and the working directory is outside the repository.
- cargo.current_dir(&self.src);
// Codegen backends are not yet tracked by -Zbinary-dep-depinfo,
// so we need to explicitly clear out if they've been updated.
self.clear_if_dirty(&my_out, &rustdoc);
}
- cargo.env("CARGO_TARGET_DIR", &out_dir).arg(cmd);
-
let profile_var = |name: &str| {
let profile = if self.config.rust_optimize { "RELEASE" } else { "DEV" };
format!("CARGO_PROFILE_{}_{}", profile, name)
cargo.env("REAL_LIBRARY_PATH", e);
}
- // Found with `rg "init_env_logger\("`. If anyone uses `init_env_logger`
- // from out of tree it shouldn't matter, since x.py is only used for
- // building in-tree.
- let color_logs = ["RUSTDOC_LOG_COLOR", "RUSTC_LOG_COLOR", "RUST_LOG_COLOR"];
- match self.build.config.color {
- Color::Always => {
- cargo.arg("--color=always");
- for log in &color_logs {
- cargo.env(log, "always");
- }
- }
- Color::Never => {
- cargo.arg("--color=never");
- for log in &color_logs {
- cargo.env(log, "never");
- }
- }
- Color::Auto => {} // nothing to do
- }
-
- if cmd != "install" {
- cargo.arg("--target").arg(target.rustc_target_arg());
- } else {
- assert_eq!(target, compiler.host);
- }
-
// Set a flag for `check`/`clippy`/`fix`, so that certain build
// scripts can do less work (i.e. not building/requiring LLVM).
if cmd == "check" || cmd == "clippy" || cmd == "fix" {
}
cargo.arg("-j").arg(self.jobs().to_string());
- // Remove make-related flags to ensure Cargo can correctly set things up
- cargo.env_remove("MAKEFLAGS");
- cargo.env_remove("MFLAGS");
// FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
// Force cargo to output binaries with disambiguating hashes in the name
}
}
- if self.config.rust_optimize {
- // FIXME: cargo bench/install do not accept `--release`
- if cmd != "bench" && cmd != "install" {
- cargo.arg("--release");
- }
- }
-
if self.config.locked_deps {
cargo.arg("--locked");
}
cargo_subcommand(builder.kind),
);
std_cargo(builder, target, compiler.stage, &mut cargo);
+ cargo.args(args(builder));
builder.info(&format!(
- "Checking stage{} std artifacts ({} -> {})",
+ "Checking stage{} library artifacts ({} -> {})",
builder.top_stage, &compiler.host, target
));
- run_cargo(
- builder,
- cargo,
- args(builder),
- &libstd_stamp(builder, compiler, target),
- vec![],
- true,
- );
+ run_cargo(builder, cargo, &libstd_stamp(builder, compiler, target), vec![], true, false);
// We skip populating the sysroot in non-zero stage because that'll lead
// to rlib/rmeta conflicts if std gets built during this session.
for krate in builder.in_tree_crates("test", Some(target)) {
cargo.arg("-p").arg(krate.name);
}
+ cargo.args(args(builder));
builder.info(&format!(
- "Checking stage{} std test/bench/example targets ({} -> {})",
+ "Checking stage{} library test/bench/example targets ({} -> {})",
builder.top_stage, &compiler.host, target
));
run_cargo(
builder,
cargo,
- args(builder),
&libstd_test_stamp(builder, compiler, target),
vec![],
true,
+ false,
);
}
}
for krate in builder.in_tree_crates("rustc-main", Some(target)) {
cargo.arg("-p").arg(krate.name);
}
+ cargo.args(args(builder));
builder.info(&format!(
"Checking stage{} compiler artifacts ({} -> {})",
builder.top_stage, &compiler.host, target
));
- run_cargo(
- builder,
- cargo,
- args(builder),
- &librustc_stamp(builder, compiler, target),
- vec![],
- true,
- );
+ run_cargo(builder, cargo, &librustc_stamp(builder, compiler, target), vec![], true, false);
let libdir = builder.sysroot_libdir(compiler, target);
let hostdir = builder.sysroot_libdir(compiler, compiler.host);
.arg("--manifest-path")
.arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
rustc_cargo_env(builder, &mut cargo, target);
+ cargo.args(args(builder));
builder.info(&format!(
"Checking stage{} {} artifacts ({} -> {})",
run_cargo(
builder,
cargo,
- args(builder),
&codegen_backend_stamp(builder, compiler, target, backend),
vec![],
true,
+ false,
);
}
}
cargo.arg("--benches");
}
+ cargo.args(args(builder));
+
builder.info(&format!(
"Checking stage{} {} artifacts ({} -> {})",
compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple
));
- run_cargo(builder, cargo, args(builder), &stamp(builder, compiler, target), vec![], true);
+ run_cargo(builder, cargo, &stamp(builder, compiler, target), vec![], true, false);
/// Cargo's output path in a given stage, compiled by a particular
/// compiler for the specified target.
cargo.arg("--all-targets");
}
+ cargo.args(args(builder));
+
// Enable internal lints for clippy and rustdoc
// NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
// See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
run_cargo(
builder,
cargo,
- args(builder),
&stamp(builder, compiler, target),
vec![],
true,
+ false,
);
/// Cargo's output path in a given stage, compiled by a particular
use std::io::{self, ErrorKind};
use std::path::Path;
+use crate::builder::{crate_description, Builder, RunConfig, ShouldRun, Step};
+use crate::cache::Interned;
use crate::util::t;
-use crate::Build;
+use crate::{Build, Compiler, Mode, Subcommand};
-pub fn clean(build: &Build, all: bool) {
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct CleanAll {}
+
+impl Step for CleanAll {
+ const DEFAULT: bool = true;
+ type Output = ();
+
+ fn make_run(run: RunConfig<'_>) {
+ run.builder.ensure(CleanAll {})
+ }
+
+ fn run(self, builder: &Builder<'_>) -> Self::Output {
+ let Subcommand::Clean { all, .. } = builder.config.cmd else { unreachable!("wrong subcommand?") };
+ clean_default(builder.build, all)
+ }
+
+ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+ run.never() // handled by DEFAULT
+ }
+}
+
+macro_rules! clean_crate_tree {
+ ( $( $name:ident, $mode:path, $root_crate:literal);+ $(;)? ) => { $(
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+ pub struct $name {
+ compiler: Compiler,
+ crates: Interned<Vec<String>>,
+ }
+
+ impl Step for $name {
+ type Output = ();
+
+ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+ let crates = run.builder.in_tree_crates($root_crate, None);
+ run.crates(crates)
+ }
+
+ fn make_run(run: RunConfig<'_>) {
+ let builder = run.builder;
+ let compiler = builder.compiler(builder.top_stage, run.target);
+ builder.ensure(Self { crates: run.cargo_crates_in_set(), compiler });
+ }
+
+ fn run(self, builder: &Builder<'_>) -> Self::Output {
+ let compiler = self.compiler;
+ let target = compiler.host;
+ let mut cargo = builder.bare_cargo(compiler, $mode, target, "clean");
+ for krate in &*self.crates {
+ cargo.arg(krate);
+ }
+
+ builder.info(&format!(
+ "Cleaning{} stage{} {} artifacts ({} -> {})",
+ crate_description(&self.crates), compiler.stage, stringify!($name).to_lowercase(), &compiler.host, target,
+ ));
+
+ // NOTE: doesn't use `run_cargo` because we don't want to save a stamp file,
+ // and doesn't use `stream_cargo` to avoid passing `--message-format` which `clean` doesn't accept.
+ builder.run(&mut cargo);
+ }
+ }
+ )+ }
+}
+
+clean_crate_tree! {
+ Rustc, Mode::Rustc, "rustc-main";
+ Std, Mode::Std, "test";
+}
+
+fn clean_default(build: &Build, all: bool) {
rm_rf("tmp".as_ref());
if all {
rm_rf(&build.out.join("tmp"));
rm_rf(&build.out.join("dist"));
rm_rf(&build.out.join("bootstrap"));
+ rm_rf(&build.out.join("rustfmt.stamp"));
for host in &build.hosts {
let entries = match build.out.join(host.triple).read_dir() {
use serde::Deserialize;
+use crate::builder::crate_description;
use crate::builder::Cargo;
use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
use crate::cache::{Interned, INTERNER};
}
}
-/// Return a `-p=x -p=y` string suitable for passing to a cargo invocation.
-fn build_crates_in_set(run: &RunConfig<'_>) -> Interned<Vec<String>> {
- let mut crates = Vec::new();
- for krate in &run.paths {
- let path = krate.assert_single_path();
- let crate_name = run.builder.crate_paths[&path.path];
- crates.push(format!("-p={crate_name}"));
- }
- INTERNER.intern_list(crates)
-}
-
impl Step for Std {
type Output = ();
const DEFAULT: bool = true;
// Build all crates anyway, as if they hadn't passed the other args.
let has_library =
run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library"));
- let crates = if has_library { Default::default() } else { build_crates_in_set(&run) };
+ let crates = if has_library { Default::default() } else { run.cargo_crates_in_set() };
run.builder.ensure(Std {
compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
target: run.target,
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
if compiler_to_use != compiler {
builder.ensure(Std::new(compiler_to_use, target));
- builder.info(&format!("Uplifting stage1 std ({} -> {})", compiler_to_use.host, target));
+ builder.info(&format!(
+ "Uplifting stage1 library ({} -> {})",
+ compiler_to_use.host, target
+ ));
// Even if we're not building std this stage, the new sysroot must
// still contain the third party objects needed by various targets.
let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "build");
std_cargo(builder, target, compiler.stage, &mut cargo);
+ for krate in &*self.crates {
+ cargo.arg("-p").arg(krate);
+ }
builder.info(&format!(
- "Building stage{} std artifacts ({} -> {})",
- compiler.stage, &compiler.host, target
+ "Building{} stage{} library artifacts ({} -> {})",
+ crate_description(&self.crates),
+ compiler.stage,
+ &compiler.host,
+ target,
));
run_cargo(
builder,
cargo,
- self.crates.to_vec(),
&libstd_stamp(builder, compiler, target),
target_deps,
false,
+ false,
);
builder.ensure(StdLink::from_std(
let target_compiler = self.target_compiler;
let target = self.target;
builder.info(&format!(
- "Copying stage{} std from stage{} ({} -> {} / {})",
+ "Copying stage{} library from stage{} ({} -> {} / {})",
target_compiler.stage, compiler.stage, &compiler.host, target_compiler.host, target
));
let libdir = builder.sysroot_libdir(target_compiler, target);
}
fn make_run(run: RunConfig<'_>) {
- let crates = build_crates_in_set(&run);
+ let crates = run.cargo_crates_in_set();
run.builder.ensure(Rustc {
compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
target: run.target,
));
}
- // cfg(bootstrap): remove if condition once the bootstrap compiler supports dylib LTO
+ // We currently don't support cross-crate LTO in stage0. This also isn't hugely necessary
+ // and may just be a time sink.
if compiler.stage != 0 {
match builder.config.rust_lto {
RustcLto::Thin | RustcLto::Fat => {
}
}
+ for krate in &*self.crates {
+ cargo.arg("-p").arg(krate);
+ }
+
builder.info(&format!(
- "Building stage{} compiler artifacts ({} -> {})",
- compiler.stage, &compiler.host, target
+ "Building{} stage{} compiler artifacts ({} -> {})",
+ crate_description(&self.crates),
+ compiler.stage,
+ &compiler.host,
+ target,
));
run_cargo(
builder,
cargo,
- self.crates.to_vec(),
&librustc_stamp(builder, compiler, target),
vec![],
false,
+ true, // Only ship rustc_driver.so and .rmeta files, not all intermediate .rlib files.
);
builder.ensure(RustcLink::from_rustc(
"Building stage{} codegen backend {} ({} -> {})",
compiler.stage, backend, &compiler.host, target
));
- let files = run_cargo(builder, cargo, vec![], &tmp_stamp, vec![], false);
+ let files = run_cargo(builder, cargo, &tmp_stamp, vec![], false, false);
if builder.config.dry_run() {
return;
}
pub fn run_cargo(
builder: &Builder<'_>,
cargo: Cargo,
- tail_args: Vec<String>,
stamp: &Path,
additional_target_deps: Vec<(PathBuf, DependencyType)>,
is_check: bool,
+ rlib_only_metadata: bool,
) -> Vec<PathBuf> {
if builder.config.dry_run() {
return Vec::new();
// files we need to probe for later.
let mut deps = Vec::new();
let mut toplevel = Vec::new();
- let ok = stream_cargo(builder, cargo, tail_args, &mut |msg| {
+ let ok = stream_cargo(builder, cargo, &mut |msg| {
let (filenames, crate_types) = match msg {
CargoMessage::CompilerArtifact {
filenames,
};
for filename in filenames {
// Skip files like executables
- if !(filename.ends_with(".rlib")
- || filename.ends_with(".lib")
+ let mut keep = false;
+ if filename.ends_with(".lib")
|| filename.ends_with(".a")
|| is_debug_info(&filename)
|| is_dylib(&filename)
- || (is_check && filename.ends_with(".rmeta")))
{
+ // Always keep native libraries, rust dylibs and debuginfo
+ keep = true;
+ }
+ if is_check && filename.ends_with(".rmeta") {
+ // During check builds we need to keep crate metadata
+ keep = true;
+ } else if rlib_only_metadata {
+ if filename.contains("jemalloc_sys") || filename.contains("rustc_smir") {
+ // jemalloc_sys and rustc_smir are not linked into librustc_driver.so,
+ // so we need to distribute them as rlib to be able to use them.
+ keep |= filename.ends_with(".rlib");
+ } else {
+ // Distribute the rest of the rustc crates as rmeta files only to reduce
+ // the tarball sizes by about 50%. The object files are linked into
+ // librustc_driver.so, so it is still possible to link against them.
+ keep |= filename.ends_with(".rmeta");
+ }
+ } else {
+ // In all other cases keep all rlibs
+ keep |= filename.ends_with(".rlib");
+ }
+
+ if !keep {
continue;
}
pub fn stream_cargo(
builder: &Builder<'_>,
cargo: Cargo,
- tail_args: Vec<String>,
cb: &mut dyn FnMut(CargoMessage<'_>),
) -> bool {
let mut cargo = Command::from(cargo);
}
cargo.arg("--message-format").arg(message_format).stdout(Stdio::piped());
- for arg in tail_args {
- cargo.arg(arg);
- }
-
builder.verbose(&format!("running: {:?}", cargo));
let mut child = match cargo.spawn() {
Ok(child) => child,
configured_targets.append(target)
for target in configured_targets:
targets[target] = sections['target'][:]
- targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target))
+ # For `.` to be valid TOML, it needs to be quoted. But `bootstrap.py` doesn't use a proper TOML parser and fails to parse the target.
+ # Avoid using quotes unless it's necessary.
+ targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target) if "." in target else target)
def is_number(value):
builder.ensure(crate::native::Llvm { target });
+ // We want to package `lld` to use it with `download-ci-llvm`.
+ builder.ensure(crate::native::Lld { target });
+
let src_bindir = builder.llvm_out(target).join("bin");
// If updating this list, you likely want to change
// src/bootstrap/download-ci-llvm-stamp as well, otherwise local users
use std::io;
use std::path::{Path, PathBuf};
+use crate::builder::crate_description;
use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
use crate::cache::{Interned, INTERNER};
use crate::compile;
// Look for library/std, library/core etc in the `x.py doc` arguments and
// open the corresponding rendered docs.
for requested_crate in requested_crates {
- if STD_PUBLIC_CRATES.iter().any(|k| *k == requested_crate.as_str()) {
+ if requested_crate == "library" {
+ // For `x.py doc library --open`, open `std` by default.
+ let index = out.join("std").join("index.html");
+ builder.open_in_browser(index);
+ } else if STD_PUBLIC_CRATES.iter().any(|&k| k == requested_crate) {
let index = out.join(requested_crate).join("index.html");
builder.open_in_browser(index);
}
requested_crates: &[String],
) {
builder.info(&format!(
- "Documenting stage{} std ({}) in {} format",
+ "Documenting{} stage{} library ({}) in {} format",
+ crate_description(requested_crates),
stage,
target,
format.as_str()
Change this file to make users of the `download-ci-llvm` configuration download
a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
-Last change is for: https://github.com/rust-lang/rust/pull/102790
+Last change is for: https://github.com/rust-lang/rust/pull/104748
test_args: Vec<String>,
},
Clean {
+ paths: Vec<PathBuf>,
all: bool,
},
Dist {
// fn usage()
let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! {
- let config = Config::parse(&["setup".to_string()]);
- let build = Build::new(config);
- let paths = Builder::get_help(&build, subcommand);
-
println!("{}", opts.usage(subcommand_help));
- if let Some(s) = paths {
- if verbose {
+ if verbose {
+ // We have an unfortunate situation here: some Steps use `builder.in_tree_crates` to determine their paths.
+ // To determine those crates, we need to run `cargo metadata`, which means we need all submodules to be checked out.
+ // That takes a while to run, so only do it when paths were explicitly requested, not on all CLI errors.
+ // `Build::new` won't load submodules for the `setup` command.
+ let cmd = if verbose {
+ println!("note: updating submodules before printing available paths");
+ "build"
+ } else {
+ "setup"
+ };
+ let config = Config::parse(&[cmd.to_string()]);
+ let build = Build::new(config);
+ let paths = Builder::get_help(&build, subcommand);
+
+ if let Some(s) = paths {
println!("{}", s);
} else {
- println!(
- "Run `./x.py {} -h -v` to see a list of available paths.",
- subcommand.as_str()
- );
+ panic!("No paths available for subcommand `{}`", subcommand.as_str());
}
- } else if verbose {
- panic!("No paths available for subcommand `{}`", subcommand.as_str());
+ } else {
+ println!(
+ "Run `./x.py {} -h -v` to see a list of available paths.",
+ subcommand.as_str()
+ );
}
crate::detail_exit(exit_code);
};
open: matches.opt_present("open"),
json: matches.opt_present("json"),
},
- Kind::Clean => {
- if !paths.is_empty() {
- println!("\nclean does not take a path argument\n");
- usage(1, &opts, verbose, &subcommand_help);
- }
-
- Subcommand::Clean { all: matches.opt_present("all") }
- }
+ Kind::Clean => Subcommand::Clean { all: matches.opt_present("all"), paths },
Kind::Format => Subcommand::Format { check: matches.opt_present("check"), paths },
Kind::Dist => Subcommand::Dist { paths },
Kind::Install => Subcommand::Install { paths },
//! Runs rustfmt on the repository.
use crate::builder::Builder;
-use crate::util::{output, t};
+use crate::util::{output, output_result, program_out_of_date, t};
+use build_helper::git::updated_master_branch;
use ignore::WalkBuilder;
use std::collections::VecDeque;
use std::path::{Path, PathBuf};
}
}
+fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, PathBuf)> {
+ let stamp_file = build.out.join("rustfmt.stamp");
+
+ let mut cmd = Command::new(match build.initial_rustfmt() {
+ Some(p) => p,
+ None => return None,
+ });
+ cmd.arg("--version");
+ let output = match cmd.output() {
+ Ok(status) => status,
+ Err(_) => return None,
+ };
+ if !output.status.success() {
+ return None;
+ }
+ Some((String::from_utf8(output.stdout).unwrap(), stamp_file))
+}
+
+/// Return whether the format cache can be reused.
+fn verify_rustfmt_version(build: &Builder<'_>) -> bool {
+ let Some((version, stamp_file)) = get_rustfmt_version(build) else {return false;};
+ !program_out_of_date(&stamp_file, &version)
+}
+
+/// Updates the last rustfmt version used
+fn update_rustfmt_version(build: &Builder<'_>) {
+ let Some((version, stamp_file)) = get_rustfmt_version(build) else {return;};
+ t!(std::fs::write(stamp_file, version))
+}
+
+/// Returns the Rust files modified between the `merge-base` of HEAD and
+/// rust-lang/master and what is now on the disk.
+///
+/// Returns `None` if all files should be formatted.
+fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, String> {
+ let Ok(updated_master) = updated_master_branch(Some(&build.config.src)) else { return Ok(None); };
+
+ if !verify_rustfmt_version(build) {
+ return Ok(None);
+ }
+
+ let merge_base =
+ output_result(build.config.git().arg("merge-base").arg(&updated_master).arg("HEAD"))?;
+ Ok(Some(
+ output_result(
+ build.config.git().arg("diff-index").arg("--name-only").arg(merge_base.trim()),
+ )?
+ .lines()
+ .map(|s| s.trim().to_owned())
+ .filter(|f| Path::new(f).extension().map_or(false, |ext| ext == "rs"))
+ .collect(),
+ ))
+}
+
#[derive(serde::Deserialize)]
struct RustfmtConfig {
ignore: Vec<String>,
Ok(status) => status.success(),
Err(_) => false,
};
+
+ let mut paths = paths.to_vec();
+
if git_available {
let in_working_tree = match build
.config
// preventing the latter from being formatted.
ignore_fmt.add(&format!("!/{}", untracked_path)).expect(&untracked_path);
}
+ if !check && paths.is_empty() {
+ match get_modified_rs_files(build) {
+ Ok(Some(files)) => {
+ for file in files {
+ println!("formatting modified file {file}");
+ ignore_fmt.add(&format!("/{file}")).expect(&file);
+ }
+ }
+ Ok(None) => {}
+ Err(err) => {
+ println!(
+ "WARN: Something went wrong when running git commands:\n{err}\n\
+ Falling back to formatting all files."
+ );
+ // Something went wrong when getting the version. Just format all the files.
+ paths.push(".".into());
+ }
+ }
+ }
} else {
println!("Not in git tree. Skipping git-aware format checks");
}
} else {
println!("Could not find usable git. Skipping git-aware format checks");
}
+
let ignore_fmt = ignore_fmt.build().unwrap();
let rustfmt_path = build.initial_rustfmt().unwrap_or_else(|| {
drop(tx);
thread.join().unwrap();
+ if !check {
+ update_rustfmt_version(build);
+ }
}
use std::process::Command;
use std::str;
+use build_helper::ci::CiEnv;
use channel::GitInfo;
use config::{DryRun, Target};
use filetime::FileTime;
use crate::builder::Kind;
use crate::config::{LlvmLibunwind, TargetSelection};
use crate::util::{
- exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed, CiEnv,
+ exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed,
};
mod bolt;
return format::format(&builder::Builder::new(&self), *check, &paths);
}
- if let Subcommand::Clean { all } = self.config.cmd {
- return clean::clean(self, all);
- }
-
// Download rustfmt early so that it can be used in rust-analyzer configs.
let _ = &builder::Builder::new(&self).initial_rustfmt();
let mut list = vec![INTERNER.intern_str(root)];
let mut visited = HashSet::new();
while let Some(krate) = list.pop() {
- let krate = &self.crates[&krate];
+ let krate = self
+ .crates
+ .get(&krate)
+ .unwrap_or_else(|| panic!("metadata missing for {krate}: {:?}", self.crates));
ret.push(krate);
for dep in &krate.deps {
if !self.crates.contains_key(dep) {
use crate::util::{self, exe, output, t, up_to_date};
use crate::{CLang, GitRepo};
+use build_helper::ci::CiEnv;
+
#[derive(Clone)]
pub struct LlvmResult {
/// Path to llvm-config binary.
}
}
-// This returns whether we've already previously built LLVM.
-//
-// It's used to avoid busting caches during x.py check -- if we've already built
-// LLVM, it's fine for us to not try to avoid doing so.
-//
-// This will return the llvm-config if it can get it (but it will not build it
-// if not).
+/// This returns whether we've already previously built LLVM.
+///
+/// It's used to avoid busting caches during x.py check -- if we've already built
+/// LLVM, it's fine for us to not try to avoid doing so.
+///
+/// This will return the llvm-config if it can get it (but it will not build it
+/// if not).
pub fn prebuilt_llvm_config(
builder: &Builder<'_>,
target: TargetSelection,
return false;
}
- if crate::util::CiEnv::is_ci() {
+ if CiEnv::is_ci() {
// We assume we have access to git, so it's okay to unconditionally pass
// `true` here.
let llvm_sha = detect_llvm_sha(config, true);
}
let target = self.target;
- let LlvmResult { llvm_config, llvm_cmake_dir } =
- builder.ensure(Llvm { target: self.target });
+ let LlvmResult { llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target });
+
+ // The `dist` step packages LLD next to LLVM's binaries for download-ci-llvm. The root path
+ // we usually expect here is `./build/$triple/ci-llvm/`, with the binaries in its `bin`
+ // subfolder. We check if that's the case, and if LLD's binary already exists there next to
+ // `llvm-config`: if so, we can use it instead of building LLVM/LLD from source.
+ let ci_llvm_bin = llvm_config.parent().unwrap();
+ if ci_llvm_bin.is_dir() && ci_llvm_bin.file_name().unwrap() == "bin" {
+ let lld_path = ci_llvm_bin.join(exe("lld", target));
+ if lld_path.exists() {
+ // The following steps copying `lld` as `rust-lld` to the sysroot, expect it in the
+ // `bin` subfolder of this step's out dir.
+ return ci_llvm_bin.parent().unwrap().to_path_buf();
+ }
+ }
let out_dir = builder.lld_out(target);
let done_stamp = out_dir.join("lld-finished-building");
match &*target.triple {
"aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
- "aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
+ "aarch64-unknown-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
"aarch64-unknown-linux-gnu" => {
common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
}
"x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
- "x86_64-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
+ "x86_64-unknown-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
"x86_64-unknown-freebsd" => common_libs("freebsd", "x86_64", &["asan", "msan", "tsan"]),
"x86_64-unknown-netbsd" => {
common_libs("netbsd", "x86_64", &["asan", "lsan", "msan", "tsan"])
fn run(self, builder: &Builder<'_>) -> Self::Output {
let mut cmd = builder.tool_cmd(Tool::BumpStage0);
+ cmd.args(builder.config.cmd.args());
builder.run(&mut cmd);
}
}
Ok(template)
}
-// install a git hook to automatically run tidy --bless, if they want
+// install a git hook to automatically run tidy, if they want
fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
let git = t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
assert!(output.status.success(), "failed to run `git`");
println!();
println!(
"Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
-If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` before
+If you'd like, x.py can install a git hook for you that will automatically run `test tidy` before
pushing your code to ensure your code is up to par. If you decide later that this behavior is
undesirable, simply delete the `pre-push` file from .git/hooks."
);
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
+use crate::builder::crate_description;
use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
use crate::cache::Interned;
use crate::compile;
if entry.file_name() == "link_to_definition" {
cargo.env("RUSTDOCFLAGS", "-Zunstable-options --generate-link-to-definition");
} else if entry.file_name() == "scrape_examples" {
- cargo.arg("-Zrustdoc-scrape-examples=examples");
+ cargo.arg("-Zrustdoc-scrape-examples");
}
builder.run(&mut cargo);
}
}
}
+/// Runs tidy's own tests.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct TidySelfTest;
+
+impl Step for TidySelfTest {
+ type Output = ();
+ const DEFAULT: bool = true;
+ const ONLY_HOSTS: bool = true;
+
+ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+ run.alias("tidyselftest")
+ }
+
+ fn make_run(run: RunConfig<'_>) {
+ run.builder.ensure(TidySelfTest);
+ }
+
+ fn run(self, builder: &Builder<'_>) {
+ let bootstrap_host = builder.config.build;
+ let compiler = builder.compiler(0, bootstrap_host);
+ let cargo = tool::prepare_tool_cargo(
+ builder,
+ compiler,
+ Mode::ToolBootstrap,
+ bootstrap_host,
+ "test",
+ "src/tools/tidy",
+ SourceType::InTree,
+ &[],
+ );
+ try_run(builder, &mut cargo.into());
+ }
+}
+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ExpandYamlAnchors;
}
builder.info(&format!(
- "{} {:?} stage{} ({} -> {})",
- test_kind, self.crates, compiler.stage, &compiler.host, target
+ "{}{} stage{} ({} -> {})",
+ test_kind,
+ crate_description(&self.crates),
+ compiler.stage,
+ &compiler.host,
+ target
));
let _time = util::timeit(&builder);
try_run(builder, &mut cargo.into());
builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target));
let mut duplicates = Vec::new();
- let is_expected = compile::stream_cargo(builder, cargo, vec![], &mut |msg| {
+ let is_expected = compile::stream_cargo(builder, cargo, &mut |msg| {
// Only care about big things like the RLS/Cargo for now
match tool {
"rls" | "cargo" | "clippy-driver" | "miri" | "rustfmt" => {}
GitHubActions,
}
-impl CiEnv {
- /// Obtains the current CI environment.
- pub fn current() -> CiEnv {
- if env::var("TF_BUILD").map_or(false, |e| e == "True") {
- CiEnv::AzurePipelines
- } else if env::var("GITHUB_ACTIONS").map_or(false, |e| e == "true") {
- CiEnv::GitHubActions
- } else {
- CiEnv::None
- }
- }
-
- pub fn is_ci() -> bool {
- Self::current() != CiEnv::None
- }
-
- /// If in a CI environment, forces the command to run with colors.
- pub fn force_coloring_in_ci(self, cmd: &mut Command) {
- if self != CiEnv::None {
- // Due to use of stamp/docker, the output stream of rustbuild is not
- // a TTY in CI, so coloring is by-default turned off.
- // The explicit `TERM=xterm` environment is needed for
- // `--color always` to actually work. This env var was lost when
- // compiling through the Makefile. Very strange.
- cmd.env("TERM", "xterm").args(&["--color", "always"]);
- }
- }
-}
-
pub fn forcing_clang_based_tests() -> bool {
if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") {
match &var.to_string_lossy().to_lowercase()[..] {
String::from_utf8(output.stdout).unwrap()
}
+pub fn output_result(cmd: &mut Command) -> Result<String, String> {
+ let output = match cmd.stderr(Stdio::inherit()).output() {
+ Ok(status) => status,
+ Err(e) => return Err(format!("failed to run command: {:?}: {}", cmd, e)),
+ };
+ if !output.status.success() {
+ return Err(format!(
+ "command did not execute successfully: {:?}\n\
+ expected success, got: {}\n{}",
+ cmd,
+ output.status,
+ String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
+ ));
+ }
+ Ok(String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))?)
+}
+
/// Returns the last-modified time for `path`, or zero if it doesn't exist.
pub fn mtime(path: &Path) -> SystemTime {
fs::metadata(path).and_then(|f| f.modified()).unwrap_or(UNIX_EPOCH)
RUN add-apt-repository -y 'deb https://apt.dilos.org/dilos dilos2 main'
ENV \
- AR_x86_64_fuchsia=x86_64-fuchsia-ar \
- CC_x86_64_fuchsia=x86_64-fuchsia-clang \
- CFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
- CXX_x86_64_fuchsia=x86_64-fuchsia-clang++ \
- CXXFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
- LDFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib" \
- AR_aarch64_fuchsia=aarch64-fuchsia-ar \
- CC_aarch64_fuchsia=aarch64-fuchsia-clang \
- CFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
- CXX_aarch64_fuchsia=aarch64-fuchsia-clang++ \
- CXXFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
- LDFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib" \
+ AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \
+ CC_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang \
+ CFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
+ CXX_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang++ \
+ CXXFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
+ LDFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib" \
+ AR_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-ar \
+ CC_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang \
+ CFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
+ CXX_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang++ \
+ CXXFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
+ LDFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib" \
AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \
CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \
CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-ENV CARGO_TARGET_X86_64_FUCHSIA_AR /usr/local/bin/llvm-ar
-ENV CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS \
+ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_AR /usr/local/bin/llvm-ar
+ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS \
-C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot \
-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot/lib \
-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib
-ENV CARGO_TARGET_AARCH64_FUCHSIA_AR /usr/local/bin/llvm-ar
-ENV CARGO_TARGET_AARCH64_FUCHSIA_RUSTFLAGS \
+ENV CARGO_TARGET_AARCH64_UNKNOWN_FUCHSIA_AR /usr/local/bin/llvm-ar
+ENV CARGO_TARGET_AARCH64_UNKNOWN_FUCHSIA_RUSTFLAGS \
-C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot \
-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot/lib \
-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib
-ENV TARGETS=x86_64-fuchsia
-ENV TARGETS=$TARGETS,aarch64-fuchsia
+ENV TARGETS=x86_64-unknown-fuchsia
+ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia
ENV TARGETS=$TARGETS,wasm32-unknown-unknown
ENV TARGETS=$TARGETS,wasm32-wasi
ENV TARGETS=$TARGETS,sparcv9-sun-solaris
# CFLAGS and CXXFLAGS env variables in main Dockerfile handle sysroot linking
for arch in x86_64 aarch64; do
for tool in clang clang++; do
- ln -s /usr/local/bin/${tool} /usr/local/bin/${arch}-fuchsia-${tool}
+ ln -s /usr/local/bin/${tool} /usr/local/bin/${arch}-unknown-fuchsia-${tool}
done
- ln -s /usr/local/bin/llvm-ar /usr/local/bin/${arch}-fuchsia-ar
+ ln -s /usr/local/bin/llvm-ar /usr/local/bin/${arch}-unknown-fuchsia-ar
done
popd > /dev/null
COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
-ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
-ENV SCRIPT python3 ../x.py test --stage 0 src/tools/tidy
+ENV SCRIPT python3 ../x.py test --stage 0 src/tools/tidy tidyselftest
-0.13.4
\ No newline at end of file
+0.14.1
\ No newline at end of file
The Rust toolchain test runner for Fuchsia.
For instructions on running the compiler test suite, see
-https://doc.rust-lang.org/stable/rustc/platform-support/fuchsia.html#aarch64-fuchsia-and-x86_64-fuchsia
+https://doc.rust-lang.org/stable/rustc/platform-support/fuchsia.html#aarch64-unknown-fuchsia-and-x86_64-unknown-fuchsia
"""
import argparse
def rustlib_dir(self):
if self.target_arch == "x64":
- return "x86_64-fuchsia"
+ return "x86_64-unknown-fuchsia"
if self.target_arch == "arm64":
- return "aarch64-fuchsia"
+ return "aarch64-unknown-fuchsia"
raise Exception(f"Unrecognized target architecture {self.target_arch}")
def libs_dir(self):
ci_dir=`cd $(dirname $0) && pwd`
source "$ci_dir/shared.sh"
-if command -v python > /dev/null; then
- PYTHON="python"
-elif command -v python3 > /dev/null; then
- PYTHON="python3"
-else
- PYTHON="python2"
-fi
-
if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try || isCiBranch try-perf; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.metrics"
$SRC/configure --set rust.parallel-compiler
# Save the build metrics before we wipe the directory
- if [ $HAS_METRICS = 1 ]; then
+ if [ "$HAS_METRICS" = 1 ]; then
mv build/metrics.json .
fi
rm -rf build
- if [ $HAS_METRICS = 1 ]; then
+ if [ "$HAS_METRICS" = 1 ]; then
mkdir build
mv metrics.json build
fi
- CARGO_INCREMENTAL=0 $PYTHON ../x.py check
+ CARGO_INCREMENTAL=0 ../x check
fi
sccache --show-stats || true
-Subproject commit a60f4316ec923a5ac2ed6a2eba6960edb832d855
+Subproject commit 2bd5d42c9956369132228da6409f0e68da56c51a
-Subproject commit dd37e21ccee43918ed18a71581bb2af537ffe4fc
+Subproject commit 8ca261268068d80c0969260fff15199bad87b587
-Subproject commit 995df09b65c582eb6290ab7ea5d9485983eb4c37
+Subproject commit 8888f9428fe9a48f31de6bd2cef9b9bf80791edc
-Subproject commit 8b42eb5f57d3d8ed2257a22d0e850d9db52afed3
+Subproject commit b3e2a6e6c8a3aae5b5d950c63046f23bae07096d
- [armv4t-none-eabi](platform-support/armv4t-none-eabi.md)
- [armv5te-none-eabi](platform-support/armv5te-none-eabi.md)
- [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
+ - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md)
- [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
- [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
- [\*-android and \*-androideabi](platform-support/android.md)
- - [\*-fuchsia](platform-support/fuchsia.md)
+ - [\*-unknown-fuchsia](platform-support/fuchsia.md)
- [\*-kmc-solid_\*](platform-support/kmc-solid.md)
- [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md)
- [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md)
-------|:---:|-------
`aarch64-apple-ios` | ✓ | ARM64 iOS
[`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ | Apple iOS Simulator on ARM64
-`aarch64-fuchsia` | ✓ | ARM64 Fuchsia
+`aarch64-unknown-fuchsia` | ✓ | ARM64 Fuchsia
[`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android
`aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat
`aarch64-unknown-none` | * | Bare ARM64, hardfloat
`wasm32-wasi` | ✓ | WebAssembly with WASI
`x86_64-apple-ios` | ✓ | 64-bit x86 iOS
[`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX
-`x86_64-fuchsia` | ✓ | 64-bit Fuchsia
+`x86_64-unknown-fuchsia` | ✓ | 64-bit Fuchsia
[`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android
`x86_64-pc-solaris` | ✓ | 64-bit Solaris 10/11, illumos
`x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
`armv6-unknown-netbsd-eabihf` | ? | |
[`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? | | ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain)
`armv7-apple-ios` | ✓ | | ARMv7 iOS, Cortex-a8
+[`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ? | | ARM Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)
[`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | ARMv7 Linux with uClibc, softfloat
[`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7 Linux with uClibc, hardfloat
`armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD
--- /dev/null
+# armv7-sony-vita-eabihf
+
+**Tier: 3**
+
+This tier supports the ARM Cortex A9 processor running on a PlayStation Vita console. `armv7-vita-newlibeabihf` aims to have support for `std` crate using `newlib` as a bridge.
+
+## Designated Developers
+
+* [@amg98](https://github.com/amg98)
+
+## Requirements
+
+This target is cross compiled, and requires installing [VITASDK](https://vitasdk.org/) toolchain on your system.
+
+## Building
+
+You can build Rust with support for the target by adding it to the `target`
+list in `config.toml`:
+
+```toml
+[build]
+build-stage = 1
+target = ["armv7-sony-vita-newlibeabihf"]
+```
+
+## Cross-compilation
+
+This target can be cross-compiled from `x86_64` on either Windows, MacOS or Linux systems. Other hosts are not supported for cross-compilation.
+
+## Testing
+
+Currently there is no support to run the rustc test suite for this target.
+
+## Building and Running Rust Programs
+
+To test your developed rust programs for PlayStation Vita, first you have to prepare a proper executable for the device using the resulting ELF file you get from compilation step. The needed steps can be automated using tools like `cargo-make`. Use the example below as a template for your project:
+
+```toml
+[env]
+TITLE = "Rust Hello World"
+TITLEID = "RUST00001"
+# At least a "sce_sys" folder should be place there for app metadata (title, icons, description...)
+# You can find sample assets for that on $VITASDK/share/gcc-arm-vita-eabi/samples/hello_world/sce_sys/
+STATIC_DIR = "static" # Folder where static assets should be placed (sce_sys folder is at $STATIC_DIR/sce_sys)
+CARGO_TARGET_DIR = { script = ["echo ${CARGO_TARGET_DIR:=target}"] }
+RUST_TARGET_PATH = { script = ["echo $(pwd)"]}
+RUST_TARGET = "armv7-sony-vita-newlibeabihf"
+CARGO_OUT_DIR = "${CARGO_TARGET_DIR}/${RUST_TARGET}/release"
+
+[tasks.xbuild]
+# This is the command where you get the ELF executable file (e.g. call to cargo build)
+
+[tasks.strip]
+description = "Strip the produced ELF executable."
+dependencies = ["xbuild"]
+command = "arm-vita-eabi-strip"
+args = ["-g", '${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_FS_NAME}.elf']
+
+[tasks.velf]
+description = "Build an VELF executable from the obtained ELF file."
+dependencies = ["strip"]
+command = "vita-elf-create"
+args = ['${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_NAME}.elf', '${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_NAME}.velf']
+
+[tasks.eboot-bin]
+description = "Build an `eboot.bin` file from the obtained VELF file."
+dependencies = ["velf"]
+command = "vita-make-fself"
+args = ["-s", '${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_NAME}.velf', '${CARGO_OUT_DIR}/eboot.bin']
+
+[tasks.param-sfo]
+description = "Build the `param.sfo` manifest using with given TITLE and TITLEID."
+command = "vita-mksfoex"
+args = ["-s", 'TITLE_ID=${TITLEID}', '${TITLE}', '${CARGO_OUT_DIR}/param.sfo']
+
+[tasks.manifest]
+description = "List all static resources into a manifest file."
+script = [
+ 'mkdir -p "${CARGO_OUT_DIR}"',
+ '''
+ if [ -d "${STATIC_DIR}" ]; then
+ find "${STATIC_DIR}" -type f > "${CARGO_OUT_DIR}/MANIFEST"
+ else
+ touch "${CARGO_OUT_DIR}/MANIFEST"
+ fi
+ '''
+]
+
+[tasks.vpk]
+description = "Build a VPK distribution of the project executable and resources."
+dependencies = ["eboot-bin", "param-sfo", "manifest"]
+script_runner = "@rust"
+script = [
+ '''
+ use std::io::BufRead;
+ use std::fs::File;
+
+ fn main() {
+
+ let crate_name = env!("CARGO_MAKE_CRATE_NAME");
+ let static_dir = env!("STATIC_DIR");
+ let out_dir = std::path::PathBuf::from(env!("CARGO_OUT_DIR"));
+
+ let mut cmd = ::std::process::Command::new("vita-pack-vpk");
+ cmd.arg("-s").arg(out_dir.join("param.sfo"));
+ cmd.arg("-b").arg(out_dir.join("eboot.bin"));
+
+ // Add files from MANIFEST
+ if let Ok(file) = File::open(out_dir.join("MANIFEST")) {
+ let mut reader = ::std::io::BufReader::new(file);
+ let mut lines = reader.lines();
+ while let Some(Ok(line)) = lines.next() {
+ let p1 = ::std::path::PathBuf::from(line); // path on FS
+ let p2 = p1.strip_prefix(static_dir).unwrap(); // path in VPK
+ cmd.arg("--add").arg(format!("{}={}", p1.display(), p2.display()));
+ }
+ }
+
+ cmd.arg(out_dir.join(format!("{}.vpk", crate_name)))
+ .output()
+ .expect("command failed.");
+ }
+ '''
+]
+```
+
+After running the above script, you should be able to get a *.vpk file in the same folder your *.elf executable resides. Now you can pick it and install it on your own PlayStation Vita using, for example, [VitaShell](https://github.com/TheOfficialFloW/VitaShell/releases) or you can use an emulator. For the time being, the most mature emulator for PlayStation Vita is [Vita3K](https://vita3k.org/), although I personally recommend testing your programs in real hardware, as the emulator is quite experimental.
-# `aarch64-fuchsia` and `x86_64-fuchsia`
+# `aarch64-unknown-fuchsia` and `x86_64-unknown-fuchsia`
**Tier: 2**
1. Building a Fuchsia package.
1. Publishing and running a Fuchsia package to a Fuchsia emulator.
-For the purposes of this walkthrough, we will only target `x86_64-fuchsia`.
+For the purposes of this walkthrough, we will only target `x86_64-unknown-fuchsia`.
## Compiling a Rust binary targeting Fuchsia
the following commands:
```sh
-rustup target add x86_64-fuchsia
-rustup target add aarch64-fuchsia
+rustup target add x86_64-unknown-fuchsia
+rustup target add aarch64-unknown-fuchsia
```
After installing our Fuchsia targets, we can now compile a Rust binary that targets
**`.cargo/config.toml`**
```txt
-[target.x86_64-fuchsia]
+[target.x86_64-unknown-fuchsia]
rustflags = [
"-Lnative=<SDK_PATH>/arch/x64/lib",
Finally, we can build our rust binary as:
```sh
-cargo build --target x86_64-fuchsia
+cargo build --target x86_64-unknown-fuchsia
```
-Now we have a Rust binary at `target/x86_64-fuchsia/debug/hello_fuchsia`,
+Now we have a Rust binary at `target/x86_64-unknown-fuchsia/debug/hello_fuchsia`,
targeting our desired Fuchsia target.
**Current directory structure**
┣━ src/
┃ ┗━ main.rs
┣━ target/
-┃ ┗━ x86_64-fuchsia/
+┃ ┗━ x86_64-unknown-fuchsia/
┃ ┗━ debug/
┃ ┗━ hello_fuchsia
┣━ Cargo.toml
```toml
[build]
-target = ["<host_platform>", "aarch64-fuchsia", "x86_64-fuchsia"]
+target = ["<host_platform>", "aarch64-unknown-fuchsia", "x86_64-unknown-fuchsia"]
[rust]
lld = true
-[target.x86_64-fuchsia]
+[llvm]
+download-ci-llvm = false
+
+[target.x86_64-unknown-fuchsia]
cc = "clang"
cxx = "clang++"
-[target.aarch64-fuchsia]
+[target.aarch64-unknown-fuchsia]
cc = "clang"
cxx = "clang++"
```
# Configure this environment variable to be the path to the downloaded SDK
export SDK_PATH="<SDK path goes here>"
-export CFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -I${SDK_PATH}/pkg/fdio/include"
-export CXXFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -I${SDK_PATH}/pkg/fdio/include"
-export LDFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -L${SDK_PATH}/arch/arm64/lib"
-export CARGO_TARGET_AARCH64_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/arm64/sysroot -Lnative=${SDK_PATH}/arch/arm64/sysroot/lib -Lnative=${SDK_PATH}/arch/arm64/lib"
-export CFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include"
-export CXXFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include"
-export LDFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -L${SDK_PATH}/arch/x64/lib"
-export CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/x64/sysroot -Lnative=${SDK_PATH}/arch/x64/sysroot/lib -Lnative=${SDK_PATH}/arch/x64/lib"
+export CFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -I${SDK_PATH}/pkg/fdio/include"
+export CXXFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -I${SDK_PATH}/pkg/fdio/include"
+export LDFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -L${SDK_PATH}/arch/arm64/lib"
+export CARGO_TARGET_AARCH64_UNKNOWN_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/arm64/sysroot -Lnative=${SDK_PATH}/arch/arm64/sysroot/lib -Lnative=${SDK_PATH}/arch/arm64/lib"
+export CFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include"
+export CXXFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include"
+export LDFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -L${SDK_PATH}/arch/x64/lib"
+export CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/x64/sysroot -Lnative=${SDK_PATH}/arch/x64/sysroot/lib -Lnative=${SDK_PATH}/arch/x64/lib"
```
Finally, the Rust compiler can be built and installed:
Using your freshly installed `rustc`, you can compile a binary for Fuchsia using
the following options:
-* `--target x86_64-fuchsia`/`--target aarch64-fuchsia`: Targets the Fuchsia
+* `--target x86_64-unknown-fuchsia`/`--target aarch64-unknown-fuchsia`: Targets the Fuchsia
platform of your choice
* `-Lnative ${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from
the SDK
```sh
# Configure these for the Fuchsia target of your choice
-TARGET_ARCH="<x86_64-fuchsia|aarch64-fuchsia>"
+TARGET_ARCH="<x86_64-unknown-fuchsia|aarch64-unknown-fuchsia>"
ARCH="<x64|aarch64>"
rustc \
**Current directory structure**
```txt
hello_fuchsia/
-┣━ src/ (if using rustc)
-┃ ┗━ hello_fuchsia.rs ...
-┣━ bin/ ...
-┃ ┗━ hello_fuchsia ...
-┣━ src/ (if using cargo)
-┃ ┗━ main.rs ...
-┗━ target/ ...
- ┗━ x86_64-fuchsia/ ...
- ┗━ debug/ ...
- ┗━ hello_fuchsia ...
+┣━ src/ (if using rustc)
+┃ ┗━ hello_fuchsia.rs ...
+┣━ bin/ ...
+┃ ┗━ hello_fuchsia ...
+┣━ src/ (if using cargo)
+┃ ┗━ main.rs ...
+┗━ target/ ...
+ ┗━ x86_64-unknown-fuchsia/ ...
+ ┗━ debug/ ...
+ ┗━ hello_fuchsia ...
```
With our Rust binary built, we can move to creating a Fuchsia package.
**`pkg/hello_fuchsia.manifest` if using cargo**
```txt
-bin/hello_fuchsia=target/x86_64-fuchsia/debug/hello_fuchsia
+bin/hello_fuchsia=target/x86_64-unknown-fuchsia/debug/hello_fuchsia
lib/ld.so.1=<SDK_PATH>/arch/x64/sysroot/dist/lib/ld.so.1
lib/libfdio.so=<SDK_PATH>/arch/x64/dist/libfdio.so
meta/package=pkg/meta/package
**Final directory structure**
```txt
hello_fuchsia/
-┣━ src/ (if using rustc)
-┃ ┗━ hello_fuchsia.rs ...
-┣━ bin/ ...
-┃ ┗━ hello_fuchsia ...
-┣━ src/ (if using cargo)
-┃ ┗━ main.rs ...
-┣━ target/ ...
-┃ ┗━ x86_64-fuchsia/ ...
-┃ ┗━ debug/ ...
-┃ ┗━ hello_fuchsia ...
+┣━ src/ (if using rustc)
+┃ ┗━ hello_fuchsia.rs ...
+┣━ bin/ ...
+┃ ┗━ hello_fuchsia ...
+┣━ src/ (if using cargo)
+┃ ┗━ main.rs ...
+┣━ target/ ...
+┃ ┗━ x86_64-unknown-fuchsia/ ...
+┃ ┗━ debug/ ...
+┃ ┗━ hello_fuchsia ...
┗━ pkg/
┣━ meta/
┃ ┣━ package
* If using `cargo`, you can simply pass `test --no-run`
to the `cargo` invocation and then repackage and rerun the Fuchsia package. From our previous example,
-this would look like `cargo test --target x86_64-fuchsia --no-run`, and moving the executable
-binary path found from the line `Executable unittests src/main.rs (target/x86_64-fuchsia/debug/deps/hello_fuchsia-<HASH>)`
+this would look like `cargo test --target x86_64-unknown-fuchsia --no-run`, and moving the executable
+binary path found from the line `Executable unittests src/main.rs (target/x86_64-unknown-fuchsia/debug/deps/hello_fuchsia-<HASH>)`
into `pkg/hello_fuchsia.manifest`.
* If using the compiled `rustc`, you can simply pass `--test`
--config config.toml \
--stage=2 \
test src/test/ui \
- --target x86_64-fuchsia \
+ --target x86_64-unknown-fuchsia \
--run=always --jobs 1 \
--test-args --target-rustcflags \
--test-args -L \
**In separate terminal**
```sh
${SDK_PATH}/tools/${ARCH}/ffx debug connect -- \
- --symbol-path target/x86_64-fuchsia/debug
+ --symbol-path target/x86_64-unknown-fuchsia/debug
```
* `--symbol-path` gets required symbol paths, which are
```sh
${SDK_PATH}/tools/${ARCH}/ffx debug connect -- \
- --symbol-path target/x86_64-fuchsia/debug \
+ --symbol-path target/x86_64-unknown-fuchsia/debug \
--build-dir ${RUST_SRC_PATH}/rust \
--build-dir ${FUCHSIA_SRC_PATH}/fuchsia/out/default
```
# Targets
`rustc` is a cross-compiler by default. This means that you can use any compiler to build for any
-architecture. The list of *targets* are the possible architectures that you can build for.
+architecture. The list of *targets* are the possible architectures that you can build for. See
+the [Platform Support](../platform-support.md) page for a detailed list of targets, or
+[Built-in Targets](built-in.md) for instructions on how to view what is available for your version
+of `rustc`.
To see all the options that you can set with a target, see the docs
[here](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.Target.html).
```rust,no_run
/// This is a doc comment.
-#[doc = " This is a doc comment."]
+#[doc = r" This is a doc comment."]
# fn f() {}
```
-(Note the leading space in the attribute version.)
+(Note the leading space and the raw string literal in the attribute version.)
In most cases, `///` is easier to use than `#[doc]`. One case where the latter is easier is
when generating documentation in macros; the `collapse-docs` pass will combine multiple
--- /dev/null
+# `dump-mono-stats-format`
+
+--------------------
+
+The `-Z dump-mono-stats-format` compiler flag controls what file format to use for `-Z dump-mono-stats`.
+The default is markdown; currently JSON is also supported. JSON can be useful for programatically manipulating the results (e.g. to find the item that took the longest to compile).
--- /dev/null
+# `dump-mono-stats`
+
+--------------------
+
+The `-Z dump-mono-stats` compiler flag generates a file with a list of the monomorphized items in the current crate.
+It is useful for investigating compile times.
+
+It accepts an optional directory where the file will be located. If no directory is specified, the file will be placed in the current directory.
+
+See also `-Z dump-mono-stats-format` and `-Z print-mono-items`. Unlike `print-mono-items`,
+`dump-mono-stats` aggregates monomorphized items by definition and includes a size estimate of how
+large the item is when codegened.
+
+See <https://rustc-dev-guide.rust-lang.org/backend/monomorph.html> for an overview of monomorphized items.
AddressSanitizer is supported on the following targets:
* `aarch64-apple-darwin`
-* `aarch64-fuchsia`
+* `aarch64-unknown-fuchsia`
* `aarch64-unknown-linux-gnu`
* `x86_64-apple-darwin`
-* `x86_64-fuchsia`
+* `x86_64-unknown-fuchsia`
* `x86_64-unknown-freebsd`
* `x86_64-unknown-linux-gnu`
#!/usr/bin/env bash
#
-# Call `tidy --bless` before git push
+# Call `tidy` before git push
# Copy this script to .git/hooks to activate,
# and remove it from .git/hooks to deactivate.
#
match ty.kind {
TyKind::Never => Primitive(PrimitiveType::Never),
TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(clean_ty(m.ty, cx))),
- TyKind::Rptr(ref l, ref m) => {
+ TyKind::Ref(ref l, ref m) => {
let lifetime = if l.is_anonymous() { None } else { Some(clean_lifetime(*l, cx)) };
BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
}
ty::Placeholder(..) => panic!("Placeholder"),
ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
ty::Infer(..) => panic!("Infer"),
- ty::Error(_) => panic!("Error"),
+ ty::Error(_) => rustc_errors::FatalError.raise(),
}
}
}
pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
+ let discriminant = match variant.discr {
+ ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
+ ty::VariantDiscr::Relative(_) => None,
+ };
+
let kind = match variant.ctor_kind() {
- Some(CtorKind::Const) => Variant::CLike(match variant.discr {
- ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
- ty::VariantDiscr::Relative(_) => None,
- }),
- Some(CtorKind::Fn) => Variant::Tuple(
+ Some(CtorKind::Const) => VariantKind::CLike,
+ Some(CtorKind::Fn) => VariantKind::Tuple(
variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
),
- None => Variant::Struct(VariantStruct {
- ctor_kind: None,
+ None => VariantKind::Struct(VariantStruct {
fields: variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
}),
};
- Item::from_def_id_and_parts(variant.def_id, Some(variant.name), VariantItem(kind), cx)
+
+ Item::from_def_id_and_parts(
+ variant.def_id,
+ Some(variant.name),
+ VariantItem(Variant { kind, discriminant }),
+ cx,
+ )
}
fn clean_variant_data<'tcx>(
disr_expr: &Option<hir::AnonConst>,
cx: &mut DocContext<'tcx>,
) -> Variant {
- match variant {
- hir::VariantData::Struct(..) => Variant::Struct(VariantStruct {
- ctor_kind: None,
+ let discriminant = disr_expr.map(|disr| Discriminant {
+ expr: Some(disr.body),
+ value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
+ });
+
+ let kind = match variant {
+ hir::VariantData::Struct(..) => VariantKind::Struct(VariantStruct {
fields: variant.fields().iter().map(|x| clean_field(x, cx)).collect(),
}),
hir::VariantData::Tuple(..) => {
- Variant::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
+ VariantKind::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
}
- hir::VariantData::Unit(..) => Variant::CLike(disr_expr.map(|disr| Discriminant {
- expr: Some(disr.body),
- value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
- })),
- }
+ hir::VariantData::Unit(..) => VariantKind::CLike,
+ };
+
+ Variant { discriminant, kind }
}
fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
match self {
StructItem(s) => s.fields.iter(),
UnionItem(u) => u.fields.iter(),
- VariantItem(Variant::Struct(v)) => v.fields.iter(),
- VariantItem(Variant::Tuple(v)) => v.iter(),
+ VariantItem(v) => match &v.kind {
+ VariantKind::CLike => [].iter(),
+ VariantKind::Tuple(t) => t.iter(),
+ VariantKind::Struct(s) => s.fields.iter(),
+ },
EnumItem(e) => e.variants.iter(),
TraitItem(t) => t.items.iter(),
ImplItem(i) => i.items.iter(),
| TyMethodItem(_)
| MethodItem(_, _)
| StructFieldItem(_)
- | VariantItem(_)
| ForeignFunctionItem(_)
| ForeignStaticItem(_)
| ForeignTypeItem
fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
let t: PrimitiveType = match *self {
Type::Path { ref path } => return Some(path.def_id()),
- DynTrait(ref bounds, _) => return Some(bounds[0].trait_.def_id()),
+ DynTrait(ref bounds, _) => return bounds.get(0).map(|b| b.trait_.def_id()),
Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
/// only as a variant in an enum.
#[derive(Clone, Debug)]
pub(crate) struct VariantStruct {
- pub(crate) ctor_kind: Option<CtorKind>,
pub(crate) fields: Vec<Item>,
}
}
#[derive(Clone, Debug)]
-pub(crate) enum Variant {
- CLike(Option<Discriminant>),
+pub(crate) struct Variant {
+ pub kind: VariantKind,
+ pub discriminant: Option<Discriminant>,
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum VariantKind {
+ CLike,
Tuple(Vec<Item>),
Struct(VariantStruct),
}
impl Variant {
pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
- match *self {
- Self::Struct(ref struct_) => Some(struct_.has_stripped_entries()),
- Self::CLike(..) | Self::Tuple(_) => None,
+ match &self.kind {
+ VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
+ VariantKind::CLike | VariantKind::Tuple(_) => None,
}
}
}
pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
Self { kind: ImportKind::Glob, source, should_be_displayed }
}
+
+ pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
+ match self.source.did {
+ Some(did) => tcx
+ .get_attrs(did, sym::doc)
+ .filter_map(ast::Attribute::meta_item_list)
+ .flatten()
+ .has_word(sym::hidden),
+ None => false,
+ }
+ }
}
#[derive(Clone, Debug)]
i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
ImplItem(i)
}
- VariantItem(i) => match i {
- Variant::Struct(mut j) => {
- j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
- VariantItem(Variant::Struct(j))
- }
- Variant::Tuple(fields) => {
- let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
- VariantItem(Variant::Tuple(fields))
- }
- Variant::CLike(disr) => VariantItem(Variant::CLike(disr)),
- },
+ VariantItem(Variant { kind, discriminant }) => {
+ let kind = match kind {
+ VariantKind::Struct(mut j) => {
+ j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+ VariantKind::Struct(j)
+ }
+ VariantKind::Tuple(fields) => {
+ let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+ VariantKind::Tuple(fields)
+ }
+ VariantKind::CLike => VariantKind::CLike,
+ };
+
+ VariantItem(Variant { kind, discriminant })
+ }
ExternCrateItem { src: _ }
| ImportItem(_)
| FunctionItem(_)
pub(crate) fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Option<String> {
let mut root = self.root_path();
- let mut path = String::new();
+ let mut path: String;
let cnum = span.cnum(self.sess());
// We can safely ignore synthetic `SourceFile`s.
ExternalLocation::Unknown => return None,
};
- sources::clean_path(&src_root, file, false, |component| {
- path.push_str(&component.to_string_lossy());
+ let href = RefCell::new(PathBuf::new());
+ sources::clean_path(
+ &src_root,
+ file,
+ |component| {
+ href.borrow_mut().push(component);
+ },
+ || {
+ href.borrow_mut().pop();
+ },
+ );
+
+ path = href.into_inner().to_string_lossy().to_string();
+
+ if let Some(c) = path.as_bytes().last() && *c != b'/' {
path.push('/');
- });
+ }
+
let mut fname = file.file_name().expect("source has no filename").to_os_string();
fname.push(".html");
path.push_str(&fname.to_string_lossy());
w.write_str(" ");
let name = v.name.unwrap();
match *v.kind {
- clean::VariantItem(ref var) => match var {
- // FIXME(#101337): Show discriminant
- clean::Variant::CLike(..) => write!(w, "{}", name),
- clean::Variant::Tuple(ref s) => {
+ // FIXME(#101337): Show discriminant
+ clean::VariantItem(ref var) => match var.kind {
+ clean::VariantKind::CLike => write!(w, "{}", name),
+ clean::VariantKind::Tuple(ref s) => {
write!(w, "{}(", name);
print_tuple_struct_fields(w, cx, s);
w.write_str(")");
}
- clean::Variant::Struct(ref s) => {
- render_struct(
- w,
- v,
- None,
- s.ctor_kind,
- &s.fields,
- " ",
- false,
- cx,
- );
+ clean::VariantKind::Struct(ref s) => {
+ render_struct(w, v, None, None, &s.fields, " ", false, cx);
}
},
_ => unreachable!(),
" rightside",
);
write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap());
- if let clean::VariantItem(clean::Variant::Tuple(ref s)) = *variant.kind {
+
+ let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() };
+
+ if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
w.write_str("(");
print_tuple_struct_fields(w, cx, s);
w.write_str(")");
}
w.write_str("</h3></section>");
- use crate::clean::Variant;
-
- let heading_and_fields = match &*variant.kind {
- clean::VariantItem(Variant::Struct(s)) => Some(("Fields", &s.fields)),
- // Documentation on tuple variant fields is rare, so to reduce noise we only emit
- // the section if at least one field is documented.
- clean::VariantItem(Variant::Tuple(fields))
- if fields.iter().any(|f| f.doc_value().is_some()) =>
- {
- Some(("Tuple Fields", fields))
+ let heading_and_fields = match &variant_data.kind {
+ clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)),
+ clean::VariantKind::Tuple(fields) => {
+ // Documentation on tuple variant fields is rare, so to reduce noise we only emit
+ // the section if at least one field is documented.
+ if fields.iter().any(|f| f.doc_value().is_some()) {
+ Some(("Tuple Fields", fields))
+ } else {
+ None
+ }
}
- _ => None,
+ clean::VariantKind::CLike => None,
};
if let Some((heading, fields)) = heading_and_fields {
match *clean_type {
clean::Type::Path { ref path, .. } => Some(RenderTypeId::DefId(path.def_id())),
clean::DynTrait(ref bounds, _) => {
- let path = &bounds[0].trait_;
- Some(RenderTypeId::DefId(path.def_id()))
+ bounds.get(0).map(|b| RenderTypeId::DefId(b.trait_.def_id()))
}
clean::Primitive(p) => Some(RenderTypeId::Primitive(p)),
clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => {
+use std::cell::RefCell;
use std::fs::{self, File};
use std::io::prelude::*;
use std::io::{self, BufReader};
use std::path::{Component, Path};
-use std::rc::Rc;
+use std::rc::{Rc, Weak};
use itertools::Itertools;
use rustc_data_structures::flock;
use std::ffi::OsString;
- #[derive(Debug)]
+ #[derive(Debug, Default)]
struct Hierarchy {
+ parent: Weak<Self>,
elem: OsString,
- children: FxHashMap<OsString, Hierarchy>,
- elems: FxHashSet<OsString>,
+ children: RefCell<FxHashMap<OsString, Rc<Self>>>,
+ elems: RefCell<FxHashSet<OsString>>,
}
impl Hierarchy {
- fn new(elem: OsString) -> Hierarchy {
- Hierarchy { elem, children: FxHashMap::default(), elems: FxHashSet::default() }
+ fn with_parent(elem: OsString, parent: &Rc<Self>) -> Self {
+ Self { elem, parent: Rc::downgrade(parent), ..Self::default() }
}
fn to_json_string(&self) -> String {
- let mut subs: Vec<&Hierarchy> = self.children.values().collect();
+ let borrow = self.children.borrow();
+ let mut subs: Vec<_> = borrow.values().collect();
subs.sort_unstable_by(|a, b| a.elem.cmp(&b.elem));
let mut files = self
.elems
+ .borrow()
.iter()
.map(|s| format!("\"{}\"", s.to_str().expect("invalid osstring conversion")))
.collect::<Vec<_>>();
files = files
)
}
- }
- if cx.include_sources {
- let mut hierarchy = Hierarchy::new(OsString::new());
- for source in cx
- .shared
- .local_sources
- .iter()
- .filter_map(|p| p.0.strip_prefix(&cx.shared.src_root).ok())
- {
- let mut h = &mut hierarchy;
- let mut elems = source
+ fn add_path(self: &Rc<Self>, path: &Path) {
+ let mut h = Rc::clone(&self);
+ let mut elems = path
.components()
.filter_map(|s| match s {
Component::Normal(s) => Some(s.to_owned()),
+ Component::ParentDir => Some(OsString::from("..")),
_ => None,
})
.peekable();
loop {
let cur_elem = elems.next().expect("empty file path");
+ if cur_elem == ".." {
+ if let Some(parent) = h.parent.upgrade() {
+ h = parent;
+ }
+ continue;
+ }
if elems.peek().is_none() {
- h.elems.insert(cur_elem);
+ h.elems.borrow_mut().insert(cur_elem);
break;
} else {
- let e = cur_elem.clone();
- h = h.children.entry(cur_elem.clone()).or_insert_with(|| Hierarchy::new(e));
+ let entry = Rc::clone(
+ h.children
+ .borrow_mut()
+ .entry(cur_elem.clone())
+ .or_insert_with(|| Rc::new(Self::with_parent(cur_elem, &h))),
+ );
+ h = entry;
}
}
}
+ }
+ if cx.include_sources {
+ let hierarchy = Rc::new(Hierarchy::default());
+ for source in cx
+ .shared
+ .local_sources
+ .iter()
+ .filter_map(|p| p.0.strip_prefix(&cx.shared.src_root).ok())
+ {
+ hierarchy.add_path(source);
+ }
+ let hierarchy = Rc::try_unwrap(hierarchy).unwrap();
let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix));
let make_sources = || {
let (mut all_sources, _krates) =
use rustc_session::Session;
use rustc_span::source_map::FileName;
+use std::cell::RefCell;
use std::ffi::OsStr;
use std::fs;
use std::path::{Component, Path, PathBuf};
return;
}
- let mut href = String::new();
- clean_path(self.src_root, &p, false, |component| {
- href.push_str(&component.to_string_lossy());
- href.push('/');
- });
+ let href = RefCell::new(PathBuf::new());
+ clean_path(
+ &self.src_root,
+ &p,
+ |component| {
+ href.borrow_mut().push(component);
+ },
+ || {
+ href.borrow_mut().pop();
+ },
+ );
+ let mut href = href.into_inner().to_string_lossy().to_string();
+ if let Some(c) = href.as_bytes().last() && *c != b'/' {
+ href.push('/');
+ }
let mut src_fname = p.file_name().expect("source has no filename").to_os_string();
src_fname.push(".html");
href.push_str(&src_fname.to_string_lossy());
let shared = Rc::clone(&self.cx.shared);
// Create the intermediate directories
- let mut cur = self.dst.clone();
- let mut root_path = String::from("../../");
- clean_path(&shared.src_root, &p, false, |component| {
- cur.push(component);
- root_path.push_str("../");
- });
+ let cur = RefCell::new(PathBuf::new());
+ let root_path = RefCell::new(PathBuf::new());
+
+ clean_path(
+ &shared.src_root,
+ &p,
+ |component| {
+ cur.borrow_mut().push(component);
+ root_path.borrow_mut().push("..");
+ },
+ || {
+ cur.borrow_mut().pop();
+ root_path.borrow_mut().pop();
+ },
+ );
+ let root_path = PathBuf::from("../../").join(root_path.into_inner());
+ let mut root_path = root_path.to_string_lossy();
+ if let Some(c) = root_path.as_bytes().last() && *c != b'/' {
+ root_path += "/";
+ }
+ let mut cur = self.dst.join(cur.into_inner());
shared.ensure_dir(&cur)?;
let src_fname = p.file_name().expect("source has no filename").to_os_string();
/// Takes a path to a source file and cleans the path to it. This canonicalizes
/// things like ".." to components which preserve the "top down" hierarchy of a
/// static HTML tree. Each component in the cleaned path will be passed as an
-/// argument to `f`. The very last component of the path (ie the file name) will
-/// be passed to `f` if `keep_filename` is true, and ignored otherwise.
-pub(crate) fn clean_path<F>(src_root: &Path, p: &Path, keep_filename: bool, mut f: F)
+/// argument to `f`. The very last component of the path (ie the file name) is ignored.
+/// If a `..` is encountered, the `parent` closure will be called to allow the callee to
+/// handle it.
+pub(crate) fn clean_path<F, P>(src_root: &Path, p: &Path, mut f: F, mut parent: P)
where
F: FnMut(&OsStr),
+ P: FnMut(),
{
// make it relative, if possible
let p = p.strip_prefix(src_root).unwrap_or(p);
let mut iter = p.components().peekable();
while let Some(c) = iter.next() {
- if !keep_filename && iter.peek().is_none() {
+ if iter.peek().is_none() {
break;
}
match c {
- Component::ParentDir => f("up".as_ref()),
+ Component::ParentDir => parent(),
Component::Normal(c) => f(c),
_ => continue,
}
}
* {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
box-sizing: border-box;
}
/* Then override it with `anywhere`, which is required to make non-Safari browsers break
more aggressively when we want them to. */
overflow-wrap: anywhere;
-
- -webkit-font-feature-settings: "kern", "liga";
- -moz-font-feature-settings: "kern", "liga";
font-feature-settings: "kern", "liga";
-
background-color: var(--main-background-color);
color: var(--main-color);
}
max-width: 100%;
}
-.source .content {
- overflow: visible;
-}
-
.sub-logo-container, .logo-container {
/* zero text boxes so that computed line height = image height exactly */
line-height: 0;
+ display: block;
}
.sub-logo-container {
filter: var(--rust-logo-filter);
}
-.sidebar, .mobile-topbar, .sidebar-menu-toggle {
- background-color: var(--sidebar-background-color);
-}
-
.sidebar {
font-size: 0.875rem;
flex: 0 0 200px;
overflow-y: hidden;
}
-.source .sidebar, #src-sidebar-toggle, #source-sidebar {
+.sidebar, .mobile-topbar, .sidebar-menu-toggle,
+#src-sidebar-toggle, #source-sidebar {
background-color: var(--sidebar-background-color);
}
color: var(--sidebar-link-color);
}
.sidebar .current,
-.sidebar a:hover {
+.sidebar a:hover:not(.logo-container) {
background-color: var(--sidebar-current-link-background-color);
}
overflow: initial;
text-align: right;
-webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
user-select: none;
padding: 14px 8px;
color: var(--src-line-numbers-span-color);
}
.example-wrap .tooltip:hover::after {
- text-align: center;
padding: 5px 3px 3px 3px;
border-radius: 6px;
margin-left: 5px;
-webkit-appearance: none;
opacity: 1;
}
+
#settings-menu, #help-button {
margin-left: 4px;
display: flex;
}
-
-#settings-menu > a, #help-button > a, #copy-path {
- width: 33px;
-}
-
#settings-menu > a, #help-button > a {
display: flex;
align-items: center;
/* Rare exception to specifying font sizes in rem. Since this is acting
as an icon, it's okay to specify their sizes in pixels. */
font-size: 20px;
+ width: 33px;
}
#settings-menu > a:hover, #settings-menu > a:focus,
padding: 0;
padding-left: 2px;
border: 0;
+ width: 33px;
}
#copy-path > img {
filter: var(--copy-path-img-filter);
vertical-align: middle;
border: solid 1px var(--border-color);
border-radius: 3px;
- color: var(--kbd--color);
+ color: var(--kbd-color);
background-color: var(--kbd-background);
box-shadow: inset 0 -1px 0 var(--kbd-box-shadow-color);
}
padding-left: 4px;
}
-details.dir-entry > summary::after {
- content: " ►";
- position: absolute;
- left: -15px;
- top: 0px;
- font-size: 80%;
- padding: 2px 0px;
- /* set width to cover gap between arrow and text */
- width: 25px;
-}
-
-details[open].dir-entry > summary::after {
- content: " ▼";
-}
-
-details.dir-entry > summary::-webkit-details-marker,
-details.dir-entry > summary::marker {
- display: none;
-}
-
details.dir-entry > summary {
- margin: 0 0 0 13px;
- list-style: none;
+ margin: 0 0 0 -4px;
+ padding: 0 0 0 4px;
cursor: pointer;
- position: relative;
}
details.dir-entry div.folders, details.dir-entry div.files {
/* Hide the logo and item name from the sidebar. Those are displayed
in the mobile-topbar instead. */
- .sidebar .sidebar-logo,
+ .sidebar .logo-container,
.sidebar .location {
display: none;
}
.sidebar.shown,
.source-sidebar-expanded .source .sidebar,
- .sidebar:focus-within {
+ .rustdoc:not(.source) .sidebar:focus-within {
left: 0;
}
- .rustdoc.source > .sidebar {
- width: 0;
- }
-
.mobile-topbar h2 {
padding-bottom: 0;
margin: auto 0.5em auto auto;
margin-top: 1em;
}
- .content {
- margin-left: 0px;
- }
-
.anchor {
display: none !important;
}
font-size: 12px;
position: relative;
bottom: 1px;
- border-width: 1px;
- border-style: solid;
+ border: 1px solid var(--scrape-example-help-border-color);
border-radius: 50px;
+ color: var(--scrape-example-help-color);
+}
+.scraped-example-list .scrape-help:hover {
+ border-color: var(--scrape-example-help-hover-border-color);
+ color: var(--scrape-example-help-hover-color);
}
.scraped-example {
overflow-x: hidden;
}
+.scraped-example .example-wrap .rust span.highlight {
+ background: var(--scrape-example-code-line-highlight);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+ background: var(--scrape-example-code-line-highlight-focus);
+}
+
.more-examples-toggle {
max-width: calc(100% + 25px);
margin-top: 10px;
--codeblock-link-background: #333;
--scrape-example-toggle-line-background: #999;
--scrape-example-toggle-line-hover-background: #c5c5c5;
+ --scrape-example-code-line-highlight: rgb(91, 59, 1);
+ --scrape-example-code-line-highlight-focus: rgb(124, 75, 15);
+ --scrape-example-help-border-color: #aaa;
+ --scrape-example-help-color: #eee;
+ --scrape-example-help-hover-border-color: #fff;
+ --scrape-example-help-hover-color: #fff;
}
h1, h2, h3, h4 {
color: #788797;
}
-#titles > button.selected {
+#search-tabs > button.selected {
background-color: #141920 !important;
border-bottom: 1px solid #ffb44c !important;
border-top: none;
}
-#titles > button:not(.selected) {
+#search-tabs > button:not(.selected) {
background-color: transparent !important;
border: none;
}
-#titles > button:hover {
+#search-tabs > button:hover {
border-bottom: 1px solid rgba(242, 151, 24, 0.3);
}
/* FIXME: these rules should be at the bottom of the file but currently must be
above the `@media (max-width: 700px)` rules due to a bug in the css checker */
/* see https://github.com/rust-lang/rust/pull/71237#issuecomment-618170143 */
-pre.rust .lifetime {}
-pre.rust .kw {}
-#titles > button:hover, #titles > button.selected {}
-pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, pre.rust .attribute {}
-pre.rust .kw-2, pre.rust .prelude-ty {}
+#search-tabs > button:hover, #search-tabs > button.selected {}
#settings-menu > a img {
filter: invert(100);
color: #ffb44c;
}
-.scraped-example-list .scrape-help {
- border-color: #aaa;
- color: #eee;
-}
-.scraped-example-list .scrape-help:hover {
- border-color: white;
- color: white;
-}
-.scraped-example .example-wrap .rust span.highlight {
- background: rgb(91, 59, 1);
-}
-.scraped-example .example-wrap .rust span.highlight.focus {
- background: rgb(124, 75, 15);
-}
.scraped-example:not(.expanded) .code-wrapper::before {
background: linear-gradient(to bottom, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
}
--codeblock-link-background: #333;
--scrape-example-toggle-line-background: #999;
--scrape-example-toggle-line-hover-background: #c5c5c5;
+ --scrape-example-code-line-highlight: rgb(91, 59, 1);
+ --scrape-example-code-line-highlight-focus: rgb(124, 75, 15);
+ --scrape-example-help-border-color: #aaa;
+ --scrape-example-help-color: #eee;
+ --scrape-example-help-hover-border-color: #fff;
+ --scrape-example-help-hover-color: #fff;
}
-#titles > button:not(.selected) {
+#search-tabs > button:not(.selected) {
background-color: #252525;
border-top-color: #252525;
}
-#titles > button:hover, #titles > button.selected {
+#search-tabs > button:hover, #search-tabs > button.selected {
border-top-color: #0089ff;
background-color: #353535;
}
-.scraped-example-list .scrape-help {
- border-color: #aaa;
- color: #eee;
-}
-.scraped-example-list .scrape-help:hover {
- border-color: white;
- color: white;
-}
-.scraped-example .example-wrap .rust span.highlight {
- background: rgb(91, 59, 1);
-}
-.scraped-example .example-wrap .rust span.highlight.focus {
- background: rgb(124, 75, 15);
-}
.scraped-example:not(.expanded) .code-wrapper::before {
background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
}
--codeblock-link-background: #eee;
--scrape-example-toggle-line-background: #ccc;
--scrape-example-toggle-line-hover-background: #999;
+ --scrape-example-code-line-highlight: #fcffd6;
+ --scrape-example-code-line-highlight-focus: #f6fdb0;
+ --scrape-example-help-border-color: #555;
+ --scrape-example-help-color: #333;
+ --scrape-example-help-hover-border-color: #000;
+ --scrape-example-help-hover-color: #000;
}
-#titles > button:not(.selected) {
+#search-tabs > button:not(.selected) {
background-color: #e6e6e6;
border-top-color: #e6e6e6;
}
-#titles > button:hover, #titles > button.selected {
+#search-tabs > button:hover, #search-tabs > button.selected {
background-color: #ffffff;
border-top-color: #0089ff;
}
-.scraped-example-list .scrape-help {
- border-color: #555;
- color: #333;
-}
-.scraped-example-list .scrape-help:hover {
- border-color: black;
- color: black;
-}
-.scraped-example .example-wrap .rust span.highlight {
- background: #fcffd6;
-}
-.scraped-example .example-wrap .rust span.highlight.focus {
- background: #f6fdb0;
-}
.scraped-example:not(.expanded) .code-wrapper::before {
background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
}
onEachLazy(code.getElementsByTagName("a"), elem => {
const href = elem.getAttribute("href");
- if (href && href.indexOf("http") !== 0) {
+ if (href && !/^(?:[a-z+]+:)?\/\//.test(href)) {
elem.setAttribute("href", window.rootPath + href);
}
});
help_button.appendChild(container);
container.onblur = helpBlurHandler;
- container.onclick = event => {
- event.preventDefault();
- };
help_button.onblur = helpBlurHandler;
help_button.children[0].onblur = helpBlurHandler;
}
{%- if page.css_class != "source" -%}
<nav class="mobile-topbar"> {#- -#}
<button class="sidebar-menu-toggle">☰</button> {#- -#}
- <a class="sidebar-logo" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
- <div class="logo-container"> {#- -#}
- {%- if !layout.logo.is_empty() -%}
- <img src="{{layout.logo}}" alt="logo"> {#- -#}
- {%- else -%}
- <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
- {%- endif -%}
- </div> {#- -#}
+ <a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
+ {%- if !layout.logo.is_empty() -%}
+ <img src="{{layout.logo}}" alt="logo"> {#- -#}
+ {%- else -%}
+ <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
+ {%- endif -%}
</a> {#- -#}
<h2></h2> {#- -#}
</nav> {#- -#}
{%- endif -%}
<nav class="sidebar"> {#- -#}
{%- if page.css_class != "source" -%}
- <a class="sidebar-logo" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
- <div class="logo-container"> {#- -#}
- {%- if !layout.logo.is_empty() %}
- <img src="{{layout.logo}}" alt="logo"> {#- -#}
- {%- else -%}
- <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
- {%- endif -%}
- </div> {#- -#}
+ <a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
+ {%- if !layout.logo.is_empty() %}
+ <img src="{{layout.logo}}" alt="logo"> {#- -#}
+ {%- else -%}
+ <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
+ {%- endif -%}
</a> {#- -#}
{%- endif -%}
{{- sidebar|safe -}}
use std::fmt;
use rustc_ast::ast;
-use rustc_hir::{def::CtorKind, def_id::DefId};
+use rustc_hir::{def::CtorKind, def::DefKind, def_id::DefId};
use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::symbol::sym;
use rustc_span::{Pos, Symbol};
use rustc_target::spec::abi::Abi as RustcAbi;
impl<'a> fmt::Display for DisplayDefId<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let name = match self.2 {
+ let DisplayDefId(def_id, tcx, name) = self;
+ let name = match name {
Some(name) => format!(":{}", name.as_u32()),
- None => self
- .1
- .opt_item_name(self.0)
- .map(|n| format!(":{}", n.as_u32()))
- .unwrap_or_default(),
+ None => {
+ // We need this workaround because primitive types' DefId actually refers to
+ // their parent module, which isn't present in the output JSON items. So
+ // instead, we directly get the primitive symbol and convert it to u32 to
+ // generate the ID.
+ if matches!(tcx.def_kind(def_id), DefKind::Mod) &&
+ let Some(prim) = tcx.get_attrs(*def_id, sym::doc)
+ .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
+ .filter(|attr| attr.has_name(sym::primitive))
+ .find_map(|attr| attr.value_str()) {
+ format!(":{}", prim.as_u32())
+ } else {
+ tcx
+ .opt_item_name(*def_id)
+ .map(|n| format!(":{}", n.as_u32()))
+ .unwrap_or_default()
+ }
+ }
};
write!(f, "{}:{}{}", self.0.krate.as_u32(), u32::from(self.0.index), name)
}
ItemId::Auto { for_, trait_ } => {
Id(format!("a:{}-{}", DisplayDefId(trait_, tcx, None), DisplayDefId(for_, tcx, name)))
}
- ItemId::Primitive(ty, krate) => Id(format!("p:{}:{}", krate.as_u32(), ty.as_sym())),
+ ItemId::Primitive(_, _) => unreachable!(),
}
}
impl FromWithTcx<clean::Variant> for Variant {
fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
- use clean::Variant::*;
- match variant {
- CLike(disr) => Variant::Plain(disr.map(|disr| disr.into_tcx(tcx))),
- Tuple(fields) => Variant::Tuple(ids_keeping_stripped(fields, tcx)),
- Struct(s) => Variant::Struct {
+ use clean::VariantKind::*;
+
+ let discriminant = variant.discriminant.map(|d| d.into_tcx(tcx));
+
+ let kind = match variant.kind {
+ CLike => VariantKind::Plain,
+ Tuple(fields) => VariantKind::Tuple(ids_keeping_stripped(fields, tcx)),
+ Struct(s) => VariantKind::Struct {
fields_stripped: s.has_stripped_entries(),
fields: ids(s.fields, tcx),
},
- }
+ };
+
+ Variant { kind, discriminant }
}
}
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.item_id.expect_def_id().expect_local());
// check if parent is trait impl
- if let Some(parent_hir_id) = cx.tcx.hir().find_parent_node(hir_id) {
+ if let Some(parent_hir_id) = cx.tcx.hir().opt_parent_id(hir_id) {
if let Some(parent_node) = cx.tcx.hir().find(parent_hir_id) {
if matches!(
parent_node,
// implementations of traits are always public.
clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
// Variant fields have inherited visibility
- clean::VariantItem(clean::Variant::Struct(..) | clean::Variant::Tuple(..)) => true,
+ clean::VariantItem(clean::Variant {
+ kind: clean::VariantKind::Struct(..) | clean::VariantKind::Tuple(..),
+ ..
+ }) => true,
_ => false,
};
impl<'tcx> DocFolder for ImportStripper<'tcx> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
match *i.kind {
+ clean::ImportItem(imp) if imp.imported_item_is_doc_hidden(self.tcx) => None,
clean::ExternCrateItem { .. } | clean::ImportItem(..)
if i.visibility(self.tcx) != Some(Visibility::Public) =>
{
EnumItem(i) => i.variants.iter().for_each(|x| self.visit_item(x)),
TraitItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
ImplItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
- VariantItem(i) => match i {
- Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
- Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
- Variant::CLike(_) => {}
+ VariantItem(i) => match &i.kind {
+ VariantKind::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
+ VariantKind::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
+ VariantKind::CLike => {}
},
ExternCrateItem { src: _ }
| ImportItem(_)
/// This method will create a new module and push it onto the "modules stack" then call
/// `visit_mod_contents`. Once done, it'll remove it from the "modules stack" and instead
- /// add into into the list of modules of the current module.
+ /// add into the list of modules of the current module.
fn enter_mod(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>, name: Symbol) {
self.modules.push(Module::new(name, id, m.spans.inner_span));
-Subproject commit 3dfd4d93fa013e1c0578d3ceac5c8f4ebba4b6ec
+Subproject commit 9ad24035fea8d309753f5e39e6eb53d1d0eb39ce
use serde::{Deserialize, Serialize};
/// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 23;
+pub const FORMAT_VERSION: u32 = 24;
/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
/// about the language items in the local crate, as well as info about external items to allow
pub impls: Vec<Id>,
}
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Variant {
+ /// Whether the variant is plain, a tuple-like, or struct-like. Contains the fields.
+ pub kind: VariantKind,
+ /// The discriminant, if explicitly specified.
+ pub discriminant: Option<Discriminant>,
+}
+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
-#[serde(tag = "variant_kind", content = "variant_inner")]
-pub enum Variant {
- /// A variant with no parentheses, and possible discriminant.
+pub enum VariantKind {
+ /// A variant with no parentheses
///
/// ```rust
/// enum Demo {
/// PlainWithDiscriminant = 1,
/// }
/// ```
- Plain(Option<Discriminant>),
+ Plain,
/// A variant with unnamed fields.
///
/// Unlike most of json, `#[doc(hidden)]` fields will be given as `None`
"tool is executed."
],
"compiler": {
- "date": "2022-11-01",
+ "date": "2022-12-27",
"version": "beta"
},
"rustfmt": {
- "date": "2022-11-01",
+ "date": "2022-12-27",
"version": "nightly"
},
"checksums_sha256": {
- "dist/2022-11-01/cargo-beta-aarch64-apple-darwin.tar.gz": "ebc0b11a2af0385bf11a5183dc159d890161be45d231acc34c6326aa25b84b95",
- "dist/2022-11-01/cargo-beta-aarch64-apple-darwin.tar.xz": "a0e44bf77337518e2200c34cb297a91dd4db51f0d331ca4cc496989da61676b3",
- "dist/2022-11-01/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "a4beae1c53df4d35fe991ebc713e37246d4d89e5543ec740274605a7124806b3",
- "dist/2022-11-01/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "5f8ec5c8b012d7e6bc28ca3d700c1c7c742f6532adb044539cee3b2280c1056c",
- "dist/2022-11-01/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "54d8fc5ce70b1f06164e17e34d33abde7260c6b1f3356d98d77271ec89766fb1",
- "dist/2022-11-01/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "f2debb6ae264fefc49380997759bb0b5022ac1c65ced9bc17bc146671be37116",
- "dist/2022-11-01/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "7a8e10be17c8cd624fb3ae2bb7eaab3c493b637c2c1c1100b5333982d1dfd962",
- "dist/2022-11-01/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "553decfc64b56d9967ae067bc942ef7117c81d6976b5fa4cf8e5171397836af7",
- "dist/2022-11-01/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "64bdb603cdc05b983393d707e9e6e6cd1c71dd8213d08b3d0d1cdf168ceb165b",
- "dist/2022-11-01/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "0afe4ca54c65668257dcad5941c678498ab917bbf82a808f39c093719a53f2ed",
- "dist/2022-11-01/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "c7fe3bacc9c4acb9b42677281655904b5ed5aec27042b9a8cf9743b737b6b657",
- "dist/2022-11-01/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "57f985ccaa2452778c90733e2586a991969dc15697bdbc9547da8a62c871b674",
- "dist/2022-11-01/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "873b2a0c2990eef29d689984293394e6972b4659bd6e4c31fb9bc9c8f1c679f9",
- "dist/2022-11-01/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "f8a9e74159594d57ce8dda1f7ce7ee4e1d494b9135a0f32b3afc89a637cad8ae",
- "dist/2022-11-01/cargo-beta-i686-pc-windows-gnu.tar.gz": "9570141b118c2339237aac12c1e6d71c138ccef784db2effdfd9d02fb12d0d0d",
- "dist/2022-11-01/cargo-beta-i686-pc-windows-gnu.tar.xz": "183b63cded6c4cc26feaa14be036a619289b155a6718f4964f94c38a9208742b",
- "dist/2022-11-01/cargo-beta-i686-pc-windows-msvc.tar.gz": "9382bf364c5fc9400fb22b046c0a951001961efac221f5cd0f9bf45b1005d36e",
- "dist/2022-11-01/cargo-beta-i686-pc-windows-msvc.tar.xz": "aae0a58b9711365ce1d76966af7387f310b496859a9e02ddbff8e23da93226c7",
- "dist/2022-11-01/cargo-beta-i686-unknown-linux-gnu.tar.gz": "507727f9b5a920ea28e7104c9aae681c50fa8aaea446a3e10b991a9408adaefc",
- "dist/2022-11-01/cargo-beta-i686-unknown-linux-gnu.tar.xz": "4ebfaf11ffc346eec9f05b2d93123483b784b83a322cca6f5fd406066ecf0fcc",
- "dist/2022-11-01/cargo-beta-mips-unknown-linux-gnu.tar.gz": "6407889854bee2e45a00585abb4fc8b387103e33e3e67244dba4e140abe46480",
- "dist/2022-11-01/cargo-beta-mips-unknown-linux-gnu.tar.xz": "1aeba894f0ca756dd9c3d9b99c7c94bf1f49d5d87ea919249fd0fcf195eb9c52",
- "dist/2022-11-01/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "292a95a8de3387832173d9adde633b3d34a019879f97bf196cb41556c3909337",
- "dist/2022-11-01/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "872819f00ab0a848401d7dfbb18cf139f85b3d8e48eee0a034cf7f0b970bd865",
- "dist/2022-11-01/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "15eb49c334688e48e83f2565c620b3f1af29775599406efa1814c78ee80673cc",
- "dist/2022-11-01/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "e74f6884e71109d36d03f7147b7e506f374ba291aadbe4246f6c429bd6fffd1f",
- "dist/2022-11-01/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "7f3cf8b35465e4df5fc18cc7cb4f4db6e1b240a39f7583126d7f8ad6d18e8bf0",
- "dist/2022-11-01/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "c59f2893999dd88a55c0a5bdb4436640ae9c18f943baf48f63eff6069f7a3e8d",
- "dist/2022-11-01/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "566c315b6206a63bf33acf178547bb757a8803e3cfc71f1f63ee033eb6a17138",
- "dist/2022-11-01/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "814a8e8f8f5caf5bb4018e54ffc2c1bd9d23df94dcaffbc04881b91bb3c8aefe",
- "dist/2022-11-01/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "5db8a63532be5fb9511238d7976075496aba6c732302dcc27bed9ae61188f917",
- "dist/2022-11-01/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "6b95c8cc4dda3847f53fb62ea711ca99c1b1b1639249b8b01d54a9ecbc4421ec",
- "dist/2022-11-01/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "2ad497be28760f7e4ec6dfa6421a6c10ab049e0dbf45ecb3a2dbde5db7a959de",
- "dist/2022-11-01/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "6e9b982857c64518c10392779528e7065191262a95e091ee289c8668b6cbfc4c",
- "dist/2022-11-01/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "88a0751ef36816f9e26e9f6d72809687b1f6821b32a3a17c58feaa32f882aecf",
- "dist/2022-11-01/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "bd6f626002a0c5a3af975419a1258a77c9db91e0db5d4acccbc7dbf25ffd17c8",
- "dist/2022-11-01/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "69bad5758f27f53d3e48abcd5aa70b16eb29d5445233c65ab50a8ad0a1629077",
- "dist/2022-11-01/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "06212f4cb605fb79d811060d3096bc4b43cf00e1a4fe4a375154b56ff60c92f5",
- "dist/2022-11-01/cargo-beta-x86_64-apple-darwin.tar.gz": "741f3490b5562afd57cdda846ab322c69e20940bcc11f3ca5690d662d5de280b",
- "dist/2022-11-01/cargo-beta-x86_64-apple-darwin.tar.xz": "2d698df7c00b7c227ca388830732a8787b2a85b328b554c0f8c417813d97ef46",
- "dist/2022-11-01/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "9c22b476f25c3f0946cb834da3904516248137cf22c5eed30432401ff061a4cf",
- "dist/2022-11-01/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "1604c5d60379227d26d819bd2f7a57c79a9e000a6077ec06e95b418bb0351180",
- "dist/2022-11-01/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "673d8941202c2113a431fcef396e604d7ea79000c97a64ef6e93b26956f75fe7",
- "dist/2022-11-01/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "3d613d04b48a2eb8644e2bfbb07a88cefe02c7b5cc7bf061b8ef307980230d47",
- "dist/2022-11-01/cargo-beta-x86_64-unknown-freebsd.tar.gz": "e0ce6fa69af565e3b79f7059a4de88e39955d7ea6866d56c2b0946b47929192f",
- "dist/2022-11-01/cargo-beta-x86_64-unknown-freebsd.tar.xz": "de602b7802b1448a861df05c41430dcde4f07358a05711784a1ca37836525b74",
- "dist/2022-11-01/cargo-beta-x86_64-unknown-illumos.tar.gz": "c4eacf4821c126b321a67e0233d2f84571b3dcf25686165cad00d9645787f03d",
- "dist/2022-11-01/cargo-beta-x86_64-unknown-illumos.tar.xz": "01ec5ab637010498b784ea2fe6aacea626fc341792eaa5a50756f9b483a765e5",
- "dist/2022-11-01/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "2e6efadbcf138ab72750c1375bfeaf2d5102559aa9b745294b9973821e193703",
- "dist/2022-11-01/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "e089b1b4248ad8e05ba54cfb278101a74aa34154bd2d44dd50119026bf436d1d",
- "dist/2022-11-01/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "ca079fce260accce11c1fb27e550421cd0900027e29b18e24e54a298d78031c3",
- "dist/2022-11-01/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "ff33e9fd6f06e02277f580f13d82f753987f4dad7d7926405b63dcb362eec498",
- "dist/2022-11-01/cargo-beta-x86_64-unknown-netbsd.tar.gz": "46101fc5f53595ae53f3ceb755cc72c078471479a337b5319c85e629e5df3b28",
- "dist/2022-11-01/cargo-beta-x86_64-unknown-netbsd.tar.xz": "b063425ccc69284e8788211bbde5a7843bd16a3b9c779fab68a11d22ebdf319b",
- "dist/2022-11-01/rust-std-beta-aarch64-apple-darwin.tar.gz": "77bb5db904089e087032c24fa2e011536e13d3982299285a7515beb97f445078",
- "dist/2022-11-01/rust-std-beta-aarch64-apple-darwin.tar.xz": "63aae4b9f10f15fb48b2ac20aa7f112a685d49bdf94d8997d036472e928fcbde",
- "dist/2022-11-01/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "8f63b6be668e6a25411582db9145c9de8192d58acb42c490b0de89489a3e36c6",
- "dist/2022-11-01/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "d862bdeaf2c78b15babaf74cf1c6feaa5c4871a90095f3d4239d81f44217cff4",
- "dist/2022-11-01/rust-std-beta-aarch64-apple-ios.tar.gz": "e5b1e9420d387a1442c77bed10efebd7b0268713820a728a067bb4ead6088041",
- "dist/2022-11-01/rust-std-beta-aarch64-apple-ios.tar.xz": "569c667e422ca7ac373d59b6e13c299cdb7f334164c84e6f0c8d0f076352fbf0",
- "dist/2022-11-01/rust-std-beta-aarch64-fuchsia.tar.gz": "3f945c43c09704b3df6af66a2132da12243b13752094383965d6a8a83c6edb0a",
- "dist/2022-11-01/rust-std-beta-aarch64-fuchsia.tar.xz": "3662f02892ab184be99f93a9d0f99e030a73cc61447934b74fcba84e05b022b1",
- "dist/2022-11-01/rust-std-beta-aarch64-linux-android.tar.gz": "ab04a0228074e974d70a15e594d57479fe22ed37c8acfa5104201dbbe57747a7",
- "dist/2022-11-01/rust-std-beta-aarch64-linux-android.tar.xz": "fb96925878a24dc9e90d356e96cf4fd1fc9152c39f8914f9a9bb676d78069cba",
- "dist/2022-11-01/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "45e824f75ac530ee9eaf0b0a01cacd5b8dd64ddf5203c032c49fd2bc4fabb245",
- "dist/2022-11-01/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "a6488faf4c87cabb4467f4cbe7348d553045c2f10f450bc6e000fcf18ca9b073",
- "dist/2022-11-01/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "e2a66e04b24aad8a8898d6c0270d8dcff63205213cea3b893807ef186e8c0936",
- "dist/2022-11-01/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "a4244ac1600726b5abe6b5f9a171fc2e4cc57bbe7cecdeaf23b69e906f05e303",
- "dist/2022-11-01/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "9e3e0f675ca50b7a2a1afeacdaf5d7f2f4ec1536f596ff99aadacfcb59fd42f5",
- "dist/2022-11-01/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "7e7a8fb4fe0283b71deb79c5ccb1ae61b2099392b3c8e09d03d4a68fbab7a184",
- "dist/2022-11-01/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "7543df1d71d805b079d19ccd785f777918b3f11b131bca05d079cb5d3952a38b",
- "dist/2022-11-01/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "eb082e894047cd77ac3fcc9c03eaaef77e6bafbd075cb0d62ba3a3ba277f5d64",
- "dist/2022-11-01/rust-std-beta-aarch64-unknown-none.tar.gz": "144fc6973b06ffb12b5ad0bbfc9fcdcb2a0732de50bb140d62d6af3d6b462908",
- "dist/2022-11-01/rust-std-beta-aarch64-unknown-none.tar.xz": "8ee2ba2d4eca35a426fb089e0f0b50b2ac3ad1ab036c5f8f4786e2953405092f",
- "dist/2022-11-01/rust-std-beta-arm-linux-androideabi.tar.gz": "4a46d6591c1983d0853f7596f7b76e7c82b6b0cbfd97802b565a17aece0d13be",
- "dist/2022-11-01/rust-std-beta-arm-linux-androideabi.tar.xz": "3888fe036b5fa9a5dfa009462a002a05c70e56eb70db3a0c872fab1432e9c9ed",
- "dist/2022-11-01/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "529d668389506443f87bd93e98dc72d12be9a4ab41675dc6a1c7373e934ca017",
- "dist/2022-11-01/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "dffa1a94f4166435d6fe2a76a4d35deb8c128cc93146f181979416816e77e29a",
- "dist/2022-11-01/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "2913bc06d6b49c52804a8dc18d1d3cb1b564e0272cba93f8594747731d360f9c",
- "dist/2022-11-01/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "c12bb97fcbeeb0a9a71b2575b2d5113948c515616f720dae3891e2aa886d03a7",
- "dist/2022-11-01/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "a844ad8a80fa07b9196dc040d5171749daf94443c57348bca04e69b8dad37cba",
- "dist/2022-11-01/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "c261662fa988748ed03722d6034228c893e02a0e473f906bba61c1f43be7cd79",
- "dist/2022-11-01/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "1ae5967f4fb80047711519dafea21fed8d6afd308566033e468c11587073d216",
- "dist/2022-11-01/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "150393cde94d8349eb488a161572589c53fed456c8401e5b1a59d1dd87003f7c",
- "dist/2022-11-01/rust-std-beta-armebv7r-none-eabi.tar.gz": "b1777a389e4db0ccd80ece774865bc99731c4b483be80c909f1b5a2a185dc5a1",
- "dist/2022-11-01/rust-std-beta-armebv7r-none-eabi.tar.xz": "877a00491650bac92e93760c2457b644d2b5ee28d410c1e29fc4b40c05da493a",
- "dist/2022-11-01/rust-std-beta-armebv7r-none-eabihf.tar.gz": "3dfbf001db319a41874e2c0de2f55407285d88156fa0563cfe3c3bb1939998fb",
- "dist/2022-11-01/rust-std-beta-armebv7r-none-eabihf.tar.xz": "b2d6a543cdf64a5c147001ea30d07bd13b98e2918a343bff08bb57eed1f81462",
- "dist/2022-11-01/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "cd8f0803ef86052d09606601b09dde05d1997a93fad7a22604fda1176157040e",
- "dist/2022-11-01/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "748cef6595fcd30da6735c29476639ac80cba94eb627d6654665d656da2979ec",
- "dist/2022-11-01/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "1dcae3588a3e552778ff1079a92750bee15835f08f8b9ff1123e4e6c5a73c087",
- "dist/2022-11-01/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "3711105029d28fd91f413f488b7041ea42c70e5a244f992e9259b4e9d52abed1",
- "dist/2022-11-01/rust-std-beta-armv7-linux-androideabi.tar.gz": "a2af3f6d3681e1c545d0c21bf04fbfe3de1cdb2273fadcbbb4408f5590054d11",
- "dist/2022-11-01/rust-std-beta-armv7-linux-androideabi.tar.xz": "23e658070e1cbe8011d48678f57bedbbde819cd64f43509858af563a7073a3fd",
- "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "ff7b429d5a6d33f0e467b333225f7c42de279ccf3e91f3ef7c5463dc06939579",
- "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "8d41b293656c5cf93f46754499e5723a89dd997d3723bfbe56f953a7d864c435",
- "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "6dd89ed0f20a0ea4a279dd4f810c7908c3e8a377da8a2983f8890efeea169177",
- "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "504fb533fca6c46ad98c728781ab31170d65e5b35cbc9199aab97b1146a24702",
- "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "f9a731fd3ea961f0c5eff24e6290aed19d79d5444bf562670abc0cd46ee309fe",
- "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "825acb16e4bbba0c9b535e635b972ec581fe6ef115c5a41bace9b85c704eccad",
- "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "41da8404f0e3cef386f6efef9b27fde27de77de71140dceeaddd8e15260ce45d",
- "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "c8f81fa9cfb40ce92f2c95ef8b57e8a62d819628111e1dfe0c6760fb48802be3",
- "dist/2022-11-01/rust-std-beta-armv7a-none-eabi.tar.gz": "fa8c3168dff5c167c6ed25f9c605941ab51e73e70c0dd162a5fd17287c5fd5a5",
- "dist/2022-11-01/rust-std-beta-armv7a-none-eabi.tar.xz": "36a5ff7865f8a16b867ab3fff4ac32f0c62c260a5c27385098e67b75b21790fb",
- "dist/2022-11-01/rust-std-beta-armv7r-none-eabi.tar.gz": "0417cef6468fd66bf626729e7c0089b47b149cfc43e8e0d4281f76f73ed17edc",
- "dist/2022-11-01/rust-std-beta-armv7r-none-eabi.tar.xz": "1de6cb38a68ef336e1edf2c1c51d999482898df99e2bc078cafe6ac5380bf3f2",
- "dist/2022-11-01/rust-std-beta-armv7r-none-eabihf.tar.gz": "91003d4648fb01306d6e0a0214e089d444a57c5ff09138040f07cc81e89af639",
- "dist/2022-11-01/rust-std-beta-armv7r-none-eabihf.tar.xz": "884306ac77518ece0cb2f22d898e3d2aa50698bd4181ca23a1dada6d82778682",
- "dist/2022-11-01/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "f17ca8f54eca5d73006659fd08142d537eff23731b6e5a35bd67efafe0dc8cb1",
- "dist/2022-11-01/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "b04a17d33d7b9b1caae666dfa5ee9a98e5dc079773b6345f6c49733731e14bfe",
- "dist/2022-11-01/rust-std-beta-i586-pc-windows-msvc.tar.gz": "55e61aa74bdb50df54394a0f62b9edc88682c37b51fe9d8d5c05c0619eacd1e3",
- "dist/2022-11-01/rust-std-beta-i586-pc-windows-msvc.tar.xz": "ec3d887742289ef9c171ae56ca20c3e9cf1972cc3e6c511611404070c55dac8a",
- "dist/2022-11-01/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "a36444f0ba0e7e03d06fbf65d830cb7067c675ed061e8f6efd6ed445d5955e88",
- "dist/2022-11-01/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "dfc07297ee8cb63f76d2019ae822352e6b42e5cccd225eaa5597a63ecff3624f",
- "dist/2022-11-01/rust-std-beta-i586-unknown-linux-musl.tar.gz": "e8de9f830cf277be584b54d86d6621a249fb2987fdf32d5f16cde9b492722d45",
- "dist/2022-11-01/rust-std-beta-i586-unknown-linux-musl.tar.xz": "f9d8bd74788e2209ecb8d0cc49d94b4e2752c9239f89bcdff3e8fae315d1d923",
- "dist/2022-11-01/rust-std-beta-i686-linux-android.tar.gz": "b15636654925fdba1e9ec1704573e4af1fc5f1158a0657b245901e22c06cd378",
- "dist/2022-11-01/rust-std-beta-i686-linux-android.tar.xz": "9abbfcaa40d86e8a4cf49f2a58b1c7b2f422b6890303cb43feb83cfb8f650a42",
- "dist/2022-11-01/rust-std-beta-i686-pc-windows-gnu.tar.gz": "30953eb457a397966221dad058ff7ebd99ca4497f184016b5a61db0f122bdee9",
- "dist/2022-11-01/rust-std-beta-i686-pc-windows-gnu.tar.xz": "f9d6d266eb3bb46c058615786483d817138aa29efc3c62c3cd9c87e572956b12",
- "dist/2022-11-01/rust-std-beta-i686-pc-windows-msvc.tar.gz": "b55202c349a4e9a493a2de7a3d48788befce32274998d3dfc1d1b6f4a96ba9e3",
- "dist/2022-11-01/rust-std-beta-i686-pc-windows-msvc.tar.xz": "6dd8d42e5712d699704e85bb90cd42e0142a4fab7cf7f80132cb0902cc415ccb",
- "dist/2022-11-01/rust-std-beta-i686-unknown-freebsd.tar.gz": "d2a7c9e7f1dba3a317692a46f8efec8d7ba1e9e943c88d3f342a820c34829aa0",
- "dist/2022-11-01/rust-std-beta-i686-unknown-freebsd.tar.xz": "ecf6abb631dd6887b5630d1ea0b8778fc1539405e6c00d7585c8afa2230ef9ec",
- "dist/2022-11-01/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "93c5912258a49a003a12ca01101f5935d5894f9a133301a47047cca934a7439e",
- "dist/2022-11-01/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "f8a6e67723cb968e874827a6148a5e25d3d45c56577faee627010347d0f03d92",
- "dist/2022-11-01/rust-std-beta-i686-unknown-linux-musl.tar.gz": "8838592167a8d68f463dc18e55d5d2d55c474426e8a4ec0f28fd2cd4230cf638",
- "dist/2022-11-01/rust-std-beta-i686-unknown-linux-musl.tar.xz": "c8330a06862a7f375b57774b382a54a1280c33ddc1b94d5d5ec45eb6ff0de8cb",
- "dist/2022-11-01/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "4b50cc174eb1da9dc831de828e6ee2fc8a81abf8e6dd52b041e4ab00eaff73ac",
- "dist/2022-11-01/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "4820db058569be7350a81396fdedf9a28233b8061c9bcf607cf2d1058cbf437a",
- "dist/2022-11-01/rust-std-beta-mips-unknown-linux-musl.tar.gz": "dfbc460e8322114bde5614b0b45e90066805adbaca999ccdc4f2aae456fc3f1f",
- "dist/2022-11-01/rust-std-beta-mips-unknown-linux-musl.tar.xz": "d98c19268b0c84f44f1224f432847a93eb809a85ca48fbe2e4b68fb436bc36aa",
- "dist/2022-11-01/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "8617edc6d62591d50dbadc4a7bc41b31b66bee6fee830af46636c5206027217f",
- "dist/2022-11-01/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "98a6132c8dd7558eb5f44007fa681a3a91b2dfd98d1f68e59f0a4660dc37b500",
- "dist/2022-11-01/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "81f794c54d7a8c680c52a8fc1a0e479526744205d51266007fc3c542496957ba",
- "dist/2022-11-01/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "dedc5b1a76f8454d1b3d7fda0a05398e5a9ae4cf16ddc4b44477799217a1fb75",
- "dist/2022-11-01/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "6d9b3d469ae92e38144d9578de8cf0c891e4bf3e667e4e465eb6f0d498140c3c",
- "dist/2022-11-01/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "f9deb84c24bd0f21ed02d763d3ad8dd92c009de4ceb2b78ec06d90d66609c5f6",
- "dist/2022-11-01/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "073882815493668dd484b8f107efc047f6e07d8c563703d0e7f73ef33dae0efc",
- "dist/2022-11-01/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "d1ab3758d1b08937a3f98737ff9fad20377e5bc43d7ab3a9359b4131ea11dcbc",
- "dist/2022-11-01/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "bc82f3d23dfb7b331558180f474c334ca3798322e19cc64657cbe894d0682901",
- "dist/2022-11-01/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "fcc12f82ea0c02e8434420165f1ee072bf4587a82ff5ecf34d19f754ffc091ef",
- "dist/2022-11-01/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "1c4507c7824c02b1af2857c88ff1624e9ead3f38c1456aa031586b43223e9490",
- "dist/2022-11-01/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "932598fbcc35ee4958be4778450f5b809ce9eabb2aa3d7573fd79744ed4d18ad",
- "dist/2022-11-01/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "c17f11707c1edef2353fba7e3f4800cecb8a273233825817b6d07ed78d6acd50",
- "dist/2022-11-01/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "7e90a819b8887f0b1a3ab02fb9a56a9b9eb752408a7bb934c99c7f6ddda48a71",
- "dist/2022-11-01/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "c437a6fc7cd7869df7cdbb52c51ae1e602ed1206517c38689deb73da6d7b4877",
- "dist/2022-11-01/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "76c1fc55b16a809ab1c8dfce894899f40d24b20dc670d318a7679953beb6c3a1",
- "dist/2022-11-01/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "d62396390fb85d5543a80ffbeaf7c32b5297a513dce14790124c35835813032b",
- "dist/2022-11-01/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "4595485492c650aa53bb9deaeb425ea956f2052c5b5503bb477778f7bcaf6ac6",
- "dist/2022-11-01/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "ee841bb8fbb0075a0bf51db2007bee2962830a89649c00fd15c67b31fd9226a3",
- "dist/2022-11-01/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "cac036fafa93f2860a5a2622394e12938c35e629ff81d7cc5930d99c980f9321",
- "dist/2022-11-01/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "025d70e57d608b81d61799c84ccce9bca3603736c4d3e006fc662c3a7b39e8db",
- "dist/2022-11-01/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "9450b1b1f95e188bcb9050085d612c8bef36e819881255fc20d70da1f45fa61e",
- "dist/2022-11-01/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "ff707c6d209f9d8e421fc530a11d41a46daaebdb4aebd5cfbaab761b2cf192ff",
- "dist/2022-11-01/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "8eb48a94c58440e2afc8ef7bbdbc725f403fe38724c0afde4e7c29a1ba2c7591",
- "dist/2022-11-01/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "e921a841b7a9e02e28182e91c921746042330d90f0478fc7e01230cb1b881c1c",
- "dist/2022-11-01/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "122135e161a4cc7dd857e3cb35b64ff7db450dcc07cbb990c8aa83e06bb4b346",
- "dist/2022-11-01/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "084824d6daeca6a0662ef1e11df84c651138d8d4e7d5c8ef66c5811354b16211",
- "dist/2022-11-01/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "09e3df606e10a0a59a67bf7b49825a04c23062e6050cebed674e0bdb2c396fcc",
- "dist/2022-11-01/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "f9929f62ffec9c6b3342da8dd21b1c14526e033174a4f86015182acdbb93a985",
- "dist/2022-11-01/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "932450fc6b5e8fa4813886baa389b53c6ff1c5b1e71f7370017b9658b04fd13c",
- "dist/2022-11-01/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "e7776d188a04779e7f6a7257bf367d8671e7d5d804d74db426592f683cabf562",
- "dist/2022-11-01/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "bbc765adc116c6a1bcbf659853b7169d95b240ffc15227cbb1d60b46d63e120a",
- "dist/2022-11-01/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "a0ff6e9ea827d7f93563aaec213eacd00efe4be9c921b448405b2af8bbf0066e",
- "dist/2022-11-01/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "7603744cbbbbdec5b2a322aabe68751e848ac7379c710866c59dcc22e4b873bd",
- "dist/2022-11-01/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "1f67446eb09505e87a5218b8504dfc678d0a712a5add763362f3c74306010bea",
- "dist/2022-11-01/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "1baca6f0e7f18a8eb9efcf35bca4320a493d51f08e62bf96a31036e2f2c433fc",
- "dist/2022-11-01/rust-std-beta-sparcv9-sun-solaris.tar.gz": "455e52fa3f232c2239112030483c0a657e7f69754d8d36ab72423c76c056fb68",
- "dist/2022-11-01/rust-std-beta-sparcv9-sun-solaris.tar.xz": "913801ca45eb1d70c9ddfcdd66aa21edaafccc85acf9864e88991bf8a5a7cf25",
- "dist/2022-11-01/rust-std-beta-thumbv6m-none-eabi.tar.gz": "14e4f69fbf710f16275ccb582a90eee1399ea1226945c7c96f75335df9118966",
- "dist/2022-11-01/rust-std-beta-thumbv6m-none-eabi.tar.xz": "40549d9d9c923a73381b8e45628cfa1896d0e78caabf2aa921c767e0bc979136",
- "dist/2022-11-01/rust-std-beta-thumbv7em-none-eabi.tar.gz": "d40bd56883abc142155188674580c4e29100fd7303fccc70b0c55b964721a156",
- "dist/2022-11-01/rust-std-beta-thumbv7em-none-eabi.tar.xz": "874c97a01d06e1516a89797d7a6effeabf34afb4933956aa34e907a65ea78690",
- "dist/2022-11-01/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "cf7acd2b4a083522c01f1909891aaba27502ea0a3a5eff93dfb41971f832bba6",
- "dist/2022-11-01/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "e9544acbefa3effe55537de85311b00077a0567d64345aa80414752037212b5f",
- "dist/2022-11-01/rust-std-beta-thumbv7m-none-eabi.tar.gz": "247e9dae16f46c64da895528f3e902030110e2aad8270f169c636ca14bfc28aa",
- "dist/2022-11-01/rust-std-beta-thumbv7m-none-eabi.tar.xz": "b7de9e8bf7b7d04fc9575390d69eacbcc62a39c35c81f37d2170424cffe6a356",
- "dist/2022-11-01/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "bd3dc986a11967e8ed050a88d03d1c0814b08cc1ab0cf929561fbf5a941a335e",
- "dist/2022-11-01/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "262b4c4ccbe20c9e913a7417c8ca72c6fb7e71f187103929057dcd0fc0b49cea",
- "dist/2022-11-01/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "85f6a725e5a726afab9ae019944567b42ee769db98a8d3c335d449eca92344e0",
- "dist/2022-11-01/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "07e897f4320f249b3f458e44e5440591962105a3b6032b54f4448c0bd21da964",
- "dist/2022-11-01/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "e92855841ae93990f88f3893a1bf511853fc3f10938eda767d5c7ff7d310aa4f",
- "dist/2022-11-01/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "3c3412a67f769ead9e8bafbcb5ff6dfc8ef89f0d8234baee7b39ab9df9fadebf",
- "dist/2022-11-01/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "f3cd623fdd466e5c0b5749dc4e90a75122f1989f6fcae0ace8c76f3b394a0752",
- "dist/2022-11-01/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "3793ab2a42f1bc59ad560ad1af75ed90c49e25f665330b5b8ce50ed73ef88508",
- "dist/2022-11-01/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "cc6c715e320c7fc5fd90f446f7c2ce6b356e95934d05f79c4e2d0fc304f212bd",
- "dist/2022-11-01/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "42a47ce6768b24c2b40c6a724003a401bfb37201a773e3c31ee413cc559cda70",
- "dist/2022-11-01/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "4c09e5b03a921d8c1d8a10d9535e81be3b3bbed961d229311cc691396ae10cbb",
- "dist/2022-11-01/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "775f7223bc5d962b5356a4884565a948d3cb5289fafe3e2eb2b8ad67550d72b4",
- "dist/2022-11-01/rust-std-beta-wasm32-unknown-unknown.tar.gz": "bc027d9170132c36faa47da1ff8f26d26d383a5145cb9dd2dce20e769ea300ba",
- "dist/2022-11-01/rust-std-beta-wasm32-unknown-unknown.tar.xz": "9a721d3550132930820d9b809074535d2b63ecb91d5c061effded92b503bf0c2",
- "dist/2022-11-01/rust-std-beta-wasm32-wasi.tar.gz": "047d58ef5e10ab51a81dbc11646fca184945a1c52e7a91552449c67952c8d898",
- "dist/2022-11-01/rust-std-beta-wasm32-wasi.tar.xz": "a490ce6ebc77a4a49c2fdeec471dd9e586b2aa26f1e7f2fc1323cc06b2b336d5",
- "dist/2022-11-01/rust-std-beta-x86_64-apple-darwin.tar.gz": "df73bc81d446792d9366772944a04f69ad32f427e1949e05d4f7c202c350c269",
- "dist/2022-11-01/rust-std-beta-x86_64-apple-darwin.tar.xz": "450aec3ec53594869bbf16ffe1713dfa19b8dcadd812a4af811bd56f1f58c929",
- "dist/2022-11-01/rust-std-beta-x86_64-apple-ios.tar.gz": "fb698f63336a186983b09c2c49109dd080c22653f3367dabfcbae564144aff35",
- "dist/2022-11-01/rust-std-beta-x86_64-apple-ios.tar.xz": "0d475ba4a4444f4da5fb39d26c9cdbc0352ea799d7e30f57e2e79d8c3c7a7021",
- "dist/2022-11-01/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "137234fc37b93ef4fa543f4e33217079137b4dbb51efbea669b93e561932b5e9",
- "dist/2022-11-01/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "01e1978d9359a5112aa77409ff17c3d0e0dec774815f679065db6c6293aaa623",
- "dist/2022-11-01/rust-std-beta-x86_64-fuchsia.tar.gz": "662e62862b1586f29372339319680c88b7cebe41e98401b5dd62e320755f0d62",
- "dist/2022-11-01/rust-std-beta-x86_64-fuchsia.tar.xz": "4a644c6c85c8e427d68a669b0f598669023e2c0db2b69b94a7124c18772052dd",
- "dist/2022-11-01/rust-std-beta-x86_64-linux-android.tar.gz": "752a57eb3de0060c1ffc6eb0af71d88d5f881b543b11b209593be2b18af1f902",
- "dist/2022-11-01/rust-std-beta-x86_64-linux-android.tar.xz": "19effccfd9d63e955cb0736968c4c300c6d919217a64cde464c30a499ae9fd9c",
- "dist/2022-11-01/rust-std-beta-x86_64-pc-solaris.tar.gz": "aa8a36ec1892c68a1c1ea0d9ac1b92b03c975a0d8ee538aaee5d757ad84d5b2e",
- "dist/2022-11-01/rust-std-beta-x86_64-pc-solaris.tar.xz": "955ad79007d397a9e24d819e95017880b25424bdac01386cb8fc6d50247b1274",
- "dist/2022-11-01/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "9f15bf80a2384f2fd333dee41289fdd8529170192dcbdd8cba0a73d32715ccc3",
- "dist/2022-11-01/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "539bcefcd6b888c5f38abca47792dcff1676ef31eeb9a4a045703582262758c1",
- "dist/2022-11-01/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "748fd22a993be659f85c3799871c4de09a99fcd7805c6d0e9d5a18dddfd2e26b",
- "dist/2022-11-01/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "68c22dfa2ef5ecd2d43661716e8a8394eaa36e8e960d34dc421bbbe57c3e0d23",
- "dist/2022-11-01/rust-std-beta-x86_64-sun-solaris.tar.gz": "f06118445fc6671d491c61dd8e6ff83ca21fc1d692058eea072cbe01ff798fb2",
- "dist/2022-11-01/rust-std-beta-x86_64-sun-solaris.tar.xz": "b3fdd56baadf3a8bffd17730d61b2ccef25ffa25d5cd826bb9a45940bf573fb5",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "2dfab0336a523182d200c7a6096fb29c199339b282ba03b469a9a1e5c5a5bb0b",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "ee5b9158ca0c2e829bb79ac526d17a2ba27ca4e305e134241ba1f8347a9bace5",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-illumos.tar.gz": "fe62b766d11e9ac55db5011a63086af5d87ce560c0656dc214c668db752675e4",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-illumos.tar.xz": "e4b1068de2812c62e7ac0ec080f605fa90123a94563dc4f898221275fbd5178b",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "c5ce6885405ba4d1694a7eb767837320ece5a02133e94c1c22ac07143d6f752c",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "eac46cc9200125be2548d6b9f2c2d37b046b8b43b25dd7f7347d88ef6795a3c7",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "1b3d1d051cf355eb26bf9de5096d984f83dc92fdeab3bdcd18d88152c0e2a2bf",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "a17cf4a9df1b1be17f5163f05665bc40638e62210d8e0623fb1afeeb96acad2a",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "90a2e5712bc37f28a0d1f71c54cc04233049c638e4f0592b50adea352e21038f",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "ad76d090357f5e272b1598c35dd24137fb9950e1bdc50b9332fa1d2fcc33a00b",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "37e0954add559b24c08ad284fb80294e435491159db63ea78a6183af5926dcec",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "d6542bd592edd3924999e690416b6bc559486388add76fa77044114b70700fac",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-none.tar.gz": "d021e49b68b8321354d99ae0fe80a6b042ec798ca7fe37cc92d4f0c0480f7ebf",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-none.tar.xz": "f6202c50c6d3575fdb398a8c98adeb0d86794b60c3951887c90a9e4acb6a89c0",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-redox.tar.gz": "b8ca678975c0c18d0fda1bb118b35366d1261e366639b8bb455b6bc59388082f",
- "dist/2022-11-01/rust-std-beta-x86_64-unknown-redox.tar.xz": "119f9e65dc3484f677064e068da42a1e7b8dc0be21d0cbf5185c9836589b39be",
- "dist/2022-11-01/rustc-beta-aarch64-apple-darwin.tar.gz": "11aa79c56a9dea2d5305ed049485a1257912fc0dfca1feff37b768971f4c1701",
- "dist/2022-11-01/rustc-beta-aarch64-apple-darwin.tar.xz": "a031051ccf97100bd8b4d2e4df7a67371cdf300df4697e1d05a7cec33a7d8c09",
- "dist/2022-11-01/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "4d015042d7d06929488f607bc56d925002e6f352d74fe192dc30e7feebb9947c",
- "dist/2022-11-01/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "d72824112c96514d927df46f6e755898d26ddd5b805f6c2c0411c773105ad61f",
- "dist/2022-11-01/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "3e70261ed7c130cb7256717cec0c37476961932be228e46e028818f9076dfccf",
- "dist/2022-11-01/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "452f07f63888cf27ca2d061751602bb07a43348eca9cab30db27940a36f496e5",
- "dist/2022-11-01/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "995a6410305d43234eb94710ddc251bafd9f5fe4ecacc51c4dc1447f364be30a",
- "dist/2022-11-01/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "2d586e5d1a72194ce2798d4f07c873d52ea441cabe5040ff682664d618b98d4e",
- "dist/2022-11-01/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "65954bc862cd149cae2702f25b186fa2166d80cb45bfe6867d075381f2614464",
- "dist/2022-11-01/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "f3a5f8318efee7eb9ba4d861876b0a5415f308c9dc2cea751a10b2e259303627",
- "dist/2022-11-01/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "d4be89140f0bd4ef9f73a1b54f949973ce560c4dd62c664974f82278ca0d6079",
- "dist/2022-11-01/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "5b381b513c27f95f9d170e9c532839a27facfe6eb4dd215c078b44fde40e3ba3",
- "dist/2022-11-01/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "ffdf714a07408901962c861103b062adf334e0febc1abfa8c538c40b0070793e",
- "dist/2022-11-01/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "ada55533236ef8c629ca72f929bb87db4b68f8c3d4c6fb3e7001f892a84a2b82",
- "dist/2022-11-01/rustc-beta-i686-pc-windows-gnu.tar.gz": "b7e059973b61a4d7a0c96b4642629bf72668380a5ad8a2962181b1229ac2174c",
- "dist/2022-11-01/rustc-beta-i686-pc-windows-gnu.tar.xz": "9aa3bc05e1782b8ff5d278f5b5baac4b0ae523ad8bba2bacd46e1bca11cd38b9",
- "dist/2022-11-01/rustc-beta-i686-pc-windows-msvc.tar.gz": "acab77f5641be0d7102e6b911f134aa36b6fcad5ac594100889ed0e494eccca3",
- "dist/2022-11-01/rustc-beta-i686-pc-windows-msvc.tar.xz": "e9af106c009e5fa0da36450a7a89a148ec176bd672ff636010846ab978804e4a",
- "dist/2022-11-01/rustc-beta-i686-unknown-linux-gnu.tar.gz": "546e7b52f7f9e8c9a99163265dbc8a5ce65dac0fef4f6e1dc8b1bed79f0a24c3",
- "dist/2022-11-01/rustc-beta-i686-unknown-linux-gnu.tar.xz": "b5ea7fc6016a4abcae3337261724ca2bd21025856134e1c2a1a1922d12ec19a8",
- "dist/2022-11-01/rustc-beta-mips-unknown-linux-gnu.tar.gz": "0f3e0c8e7883dc7ebbec38e1f3446a33651ebba9a725443856b09ae7e8bcfec0",
- "dist/2022-11-01/rustc-beta-mips-unknown-linux-gnu.tar.xz": "42871f7f098008f61f6cfd3cf78240156280cc7f5e52860d8125e22b3733a207",
- "dist/2022-11-01/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "ded0d4da36a0658d46c6705c04fa40d0894b6e113776d2ef8e954e9675e98f9a",
- "dist/2022-11-01/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "2f9ec1ba69a7abbe4efbc5fa00715f520b4c69792b96e98ed8a72e3f798eb137",
- "dist/2022-11-01/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "090431409021fa0167576c717cf5daac750f9baf7badc3bc031547dad8dedb18",
- "dist/2022-11-01/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "0542d0336c8cdacf8a830d2a7c3218b76a00ae37db23fb2f12b928bb7b7dd488",
- "dist/2022-11-01/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "2d6db76bc5242af8c2199c5e74f152bbd8103477855379e7c5c200b498ccf901",
- "dist/2022-11-01/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "0dc803a305497cc905f3937691e4f1679c72a385b57ee931b19ac5347052c502",
- "dist/2022-11-01/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "809f547fb5c27c7d15816642839f9ff5fee20f03a3ce390d5b2bfdc983a7c7e2",
- "dist/2022-11-01/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "bd8403226676b78b40c7a494b3a89f9bed956e7eedf3a65a61cba41a6382f5b6",
- "dist/2022-11-01/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "12cd357dc72d67911a521dc0ea44a8d05bc4c214a7f6b9e88872ddc03811dc15",
- "dist/2022-11-01/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "d92f790cabb85373455b5adee9e692dc934dff60eccb70c077f29cde35e7cd00",
- "dist/2022-11-01/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "a175a2b7d948459c12f44592c1ee5c79825a120557ff0c488fb0bd4e45c7ee99",
- "dist/2022-11-01/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d047a4ed562cc91469785fed44d97061d60e1f9c677b5de05245648373df111f",
- "dist/2022-11-01/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "1b1f20032337e6a0b5e4745a3542a5638747bf2f3b62b2eb855c0ea1ac54d81c",
- "dist/2022-11-01/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "c8a46c9c002ce19e940a449a4787055b4ad45076a606bd68626a1c8d892d8191",
- "dist/2022-11-01/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "547c670fd6a5f38f98e7b47daaf6822fd5a1abd5a7c11b6f2b5838cb145c615e",
- "dist/2022-11-01/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "16a0783135c22b64541cbf9201e5f84ab4befbc9ec0117f3e9639cd42dcb81bf",
- "dist/2022-11-01/rustc-beta-x86_64-apple-darwin.tar.gz": "3121d060a0306c539334fb42c0c6edb6295eb4b5d05b63e55df98d5dc1cb0eba",
- "dist/2022-11-01/rustc-beta-x86_64-apple-darwin.tar.xz": "4697febb60fdecb5cd70bde0cffad77cdcf8cce057349b4e1f26e3dd4f2f4a51",
- "dist/2022-11-01/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "c33bb5e98d83f0a7393c631b6b53eb4a8517bdbf506e1ceb6f0bdd8493fa24b9",
- "dist/2022-11-01/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "167e1ab52c4478e6aa8b2bea563f2d8caf3605158731a892181f9d24b027ffff",
- "dist/2022-11-01/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "efbe536d85810f2edb6bb7232617f12d3f208e077d177c24f507ff02c8e83a11",
- "dist/2022-11-01/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "b6acaa3206a3af7fe0e97d4d9211fc76ba972afcdd188443a72027dd34236658",
- "dist/2022-11-01/rustc-beta-x86_64-unknown-freebsd.tar.gz": "8eb739094411afb56ad791b84aa2ddcd2c98b6ca5a4c1cd7fa631571702f1d67",
- "dist/2022-11-01/rustc-beta-x86_64-unknown-freebsd.tar.xz": "4572c19bf416c188a3691cc9542422b92a124594bdf83c82213d07a3aaeef465",
- "dist/2022-11-01/rustc-beta-x86_64-unknown-illumos.tar.gz": "eca080758173b3bee5a1ed7d04473a8334422fc58c762031877e690a255202c8",
- "dist/2022-11-01/rustc-beta-x86_64-unknown-illumos.tar.xz": "68b1ced7efbd6bb4cac647e7417b2ad982f58a1cc546b9391213e85e5852ce6c",
- "dist/2022-11-01/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "3a4870b33c0f223dc295fcf3f1c4e331a2631dbc07279f4ca7452d86c5f6e730",
- "dist/2022-11-01/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "556821823576a5c0387f0dc89139d3cddc2a17072199607c352fe4b190b7f02f",
- "dist/2022-11-01/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "4e1723c8f268eecc9bf3efb16241ce03bf109b9f7c6f4f62e430b7ccd1c092cb",
- "dist/2022-11-01/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "47bb3fb8f8529f19fa9725a43a57abd8bc3c7b2a30e17f86b137df0c57a3c549",
- "dist/2022-11-01/rustc-beta-x86_64-unknown-netbsd.tar.gz": "530c24d950028d0745110672fad230da8a2a0e4cd4e5ac5afcf1ff8562288925",
- "dist/2022-11-01/rustc-beta-x86_64-unknown-netbsd.tar.xz": "cd3654b33b3a8e7fbcde2e380bf2914cb07fe6f8355c8810a5bcfe3a05d63f84",
- "dist/2022-11-01/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "47527c62b813c0612b80c864b3720b7e0673eb2dd762887254fd6a80f11c94b0",
- "dist/2022-11-01/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "82248dd276ecc0fd45031ba131cb2c870a4b3c09b822d8ad4454f26f506d7810",
- "dist/2022-11-01/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "fdc9cc842850023e7c22ac22173a18aa5383a2e2fecb713c802e59d55cc5232d",
- "dist/2022-11-01/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "10ddbe6a89cadde47f6f52ef0c4f9ab08f4ced2281fadd1ecbc6a0e4736c9787",
- "dist/2022-11-01/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "2135c6d129fa7ecd831e451e173c38677ea39975a91cd6092252e4c0bd93eeaa",
- "dist/2022-11-01/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "387d43021bd0ec1586155d1b977470646a68e2625fc192331b76180755687d37",
- "dist/2022-11-01/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "41da916cbac667f5f238c3aee3bfb230c3345a4d625779c1fcf57813c9138696",
- "dist/2022-11-01/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "f28cf712bc617f1755e78a7a442633a7aff78857b98d9aae473effc5684ce8aa",
- "dist/2022-11-01/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "065fd7fdcb9f38a9c08b256b46627c8ce38a6433dc162034a306f4d4f4627a31",
- "dist/2022-11-01/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "1fc14261867b540e6d014cc5a21c557d0a4bb31d2619ae98a330585915365614",
- "dist/2022-11-01/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "1a9ebea072c333e99a3339a87ac3971deb4fe2baca9bd0e8429321a81cce847f",
- "dist/2022-11-01/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "1c7a72cf8e9cda52d02bd5f4244164aea829914087501cb0bedd75f05f464a91",
- "dist/2022-11-01/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "1f8405178138601f65dbe10f93d326c705ea91f9e7200f253d6123f618d09ad8",
- "dist/2022-11-01/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "00365767eb739ecd82c6264795768baba07a101aacec59e137a7495afd0b3288",
- "dist/2022-11-01/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "b2e4c4672f440e1f97913497ee158280cb8ed70c81cb47a85e5382cb3de0b03c",
- "dist/2022-11-01/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "01bea91a3ab8203b32cbd1fb2945a1eca68179e8f4011e387a230587fc2736a4",
- "dist/2022-11-01/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "2d0db2a9f187d300c183cfe2ac6778547ab6492720c0e9df3e78f5b06004e758",
- "dist/2022-11-01/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "b89b02b9fdedb9a93dee602dd9c818e97c397ef73c3f1d0164ddd2ab809cddc2",
- "dist/2022-11-01/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "4498a8e6d0ae7a793a9f3c84e3bbe9218c37053a1f3dd6a0b4ad7edd1a41493f",
- "dist/2022-11-01/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "27041aa61921b767be6670f0f08aad1a1ab8d09d0e86cd2e431e54744ed25d0b",
- "dist/2022-11-01/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "870923556049bd4be8da03fa6d876fa8249e4acf0ea2c83850c4e23a09fe577f",
- "dist/2022-11-01/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "8c05e1f60a59064c05db7522245d482b559ae858a5c9c772db81a05daa60a4c6",
- "dist/2022-11-01/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "1a88c20701cc6f7dd2b3e32bef72a78936c39095a35237fc4a4b5a497790a048",
- "dist/2022-11-01/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "9b5ccf5413650144a79f382efd12204aeddf3421ea6f06615afc489cdf30691e",
- "dist/2022-11-01/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "4bcf264ba7ce42aee79d76ba0f19818aff71ee666ac4ac417c2a60b0dafa8865",
- "dist/2022-11-01/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "fd6ff248063cd53ee6b0538c8b3c8af1758ae5c42cc2f5fc805ab96799033f7d",
- "dist/2022-11-01/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "a03cf4d831ba58d1e562d6fd48dd7558d9034046ae7050883eb1d0fc2cad6895",
- "dist/2022-11-01/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "30be7166fa091929d1a4b5eed4b72c4b5c94898861f4e91fb45a2b9ad4333ca6",
- "dist/2022-11-01/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "59f3910a559994863f1910ffcf34cae348d0c07128d00ce5ac085bbca349f7f5",
- "dist/2022-11-01/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "817df1ddab344e47df34c73918c5bbb3a7b33048f8ac5c5794cb35624f5bce24",
- "dist/2022-11-01/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "7825a5f19cb29245de96eb22183fbfc38b75eda0ba63d2255fa062f9c6764bbf",
- "dist/2022-11-01/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "0d6384aa1162d821edb6d22326b0a1d481e6735d4343a70df7bead694bb71567",
- "dist/2022-11-01/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "aef195c86920cfecafc29f80ce6a88c704f09d72011ad1fd462564bf858c75a6",
- "dist/2022-11-01/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "da43e621a113d88f7c4805f70cb5208bac66f97c68485a60f95cf11f5ae0f55c",
- "dist/2022-11-01/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "2603b5061d059655e3298df94875fa4876d5ea9af1e04dd197ec5cefa3e1eb4c",
- "dist/2022-11-01/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "f79606c20ce3bf64a9ede63e878cda199e7f1b0b13f40bd51d7108b3d4c72cb0",
- "dist/2022-11-01/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "f6c46ffbb38f8838c496e1eddea7d6f27392699abfafd0d13b234eee39238181",
- "dist/2022-11-01/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "9244fc29cd3c32c971f44fcdaa26623b8976efaf0a4705b573798af5b0b0896e",
- "dist/2022-11-01/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "bd502f9105d56af252da1038687a4e942a477c7047cac9730de7414cdbbfbc48",
- "dist/2022-11-01/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "426785558da44683a554c542475c9402932c72d63148c37917e8cc6e429ad413",
- "dist/2022-11-01/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "52646c86ad464c5803f74ab37166dc1692383bc5fd94818bd579e518c327251e",
- "dist/2022-11-01/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "67d1490a41932c2a89981e18c9735d4437faedd1e708e26f75dfd21d4709488b",
- "dist/2022-11-01/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "9feb7b704a6d3e6b019a99ecd033042ce81a4b126e4288e0b4772266c6e0a65e",
- "dist/2022-11-01/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "fba240009d3f27e04200133120c46112ac64281e99952da44d6fe8a01557f236",
- "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "ce15bda4992ada52f94dae6b1a0e220f26324acefb62094035abe112aa878fec",
- "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "189a8579cf3fe99b9c084821ce1ee9bec6977470341e2ae45b859dcdacf65d21",
- "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "15abcd9e43f2c87fc894b3e280a99865508f9079badcbe7be07c6b79e85f01b4",
- "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "f52dab31a428e568518b00d3afc1426569810bcd20a7db1c0093200c6db86d24",
- "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "57ec35b95a5fd803b2d4dacf7657847111a6cc9bda3cda962174965cd6005085",
- "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "96987349e20e3f602bb6f518924660c09a4575887730b1bbe36adee921921956",
- "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "76d6f5882573169985f5b8a9e13cee8bbe3bd3b423ad287280a0809c6a5efc5a",
- "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "9a2c79685b4ac57efea65e43dafa28b59cead1c14e98f10e0196cb2cfd2fa0b6",
- "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "0be98b45af7e666955e6e0adb5b4cc3f5517c8d144702b10daedd053450cd5d5",
- "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "ae9ac6e1c0e14bfba746f3a85bfa3f009113d0edbf880a2cf20ece6046ee27bb"
+ "dist/2022-12-27/cargo-beta-aarch64-apple-darwin.tar.gz": "00b7df89de07931d150940536a1e6c980897ed0e9880bb6f24d5ebbad896c8f2",
+ "dist/2022-12-27/cargo-beta-aarch64-apple-darwin.tar.xz": "17e1e9cf2c4dad4fec7f420f43cea21923d76ba2d6f87ad67c90ea9c8e4a04f6",
+ "dist/2022-12-27/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "783b7e2569490dffc953d4b24e659fec384739ceb8bad37e3a97df374945a91d",
+ "dist/2022-12-27/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "a9402480620b03c010cb18dacca9a95c82e7b6078d2c1163543bc4292d7dd300",
+ "dist/2022-12-27/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "7fa9aa92c2b1268420f60af2826dffa50b61c9926a2a1cd1c8273fe5861cde11",
+ "dist/2022-12-27/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "97d583ed82db1fd5a03ce44a660f1163d0812b6f352adc6d78e61d7ae4fbfe23",
+ "dist/2022-12-27/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "69236898b091d6ef31445eb1223acfc01adf21fb1aa277a7d441eaa300c0c9ad",
+ "dist/2022-12-27/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "4a92788cdba1705b79ce9999d45a62d4631dbc59cc980437e1635dc908458b66",
+ "dist/2022-12-27/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "b35b72b16c59b38e38acddf2c06c2c819ca78f146bbf4f3ce9d7ff982b86655e",
+ "dist/2022-12-27/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "81d7fbe3f50cbad04c2ad0e118001976a880d23ad2a894ee49c6f6c10583d10d",
+ "dist/2022-12-27/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "942f6860e2cf9da7c5399d308acad43f862750bf7d383444c2dd636b86553e14",
+ "dist/2022-12-27/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "5f2f3c7186a2cb28f96bba8db7d404b0f3338bbe57edd631bb16fe4d2c8d493a",
+ "dist/2022-12-27/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "f15932518f114587c3639ed270cab3e4ef4eb28e0abb6b59b5f63138fa43e829",
+ "dist/2022-12-27/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "41116748ab087e0c7a5354508fb95e1a966212ef5cac40da59e363108077c3a9",
+ "dist/2022-12-27/cargo-beta-i686-pc-windows-gnu.tar.gz": "37bbf0a9dcc1b3fbc11a5f72de922fb0f5dc80a632d803fa0a892d72bdd457c1",
+ "dist/2022-12-27/cargo-beta-i686-pc-windows-gnu.tar.xz": "7a8afd8a69e1e25e47122096920217bbe765e82e831583420487702831241d5c",
+ "dist/2022-12-27/cargo-beta-i686-pc-windows-msvc.tar.gz": "c40ec16780156f6568bf8f1353a3bb367d4bec09dc6e98b03de44bd2ed301ae8",
+ "dist/2022-12-27/cargo-beta-i686-pc-windows-msvc.tar.xz": "94320949f071236d828fb1252159f0f2b1f18030303af1ae0b7ca06cd9567de0",
+ "dist/2022-12-27/cargo-beta-i686-unknown-linux-gnu.tar.gz": "1fb3fc33289ae716f950feca832196bb32cde0556e41e501d05c84116836d916",
+ "dist/2022-12-27/cargo-beta-i686-unknown-linux-gnu.tar.xz": "4f112ea5a91abbf63db484368090fdf8fbc6b7abc1a5d7c8353df15e7908c2e3",
+ "dist/2022-12-27/cargo-beta-mips-unknown-linux-gnu.tar.gz": "b90f3c17c73f4dd7b36e0ff56b17be8e1c90f82b33c9be28b7b813fc5c788e05",
+ "dist/2022-12-27/cargo-beta-mips-unknown-linux-gnu.tar.xz": "8754bb3f116b09a8b38ac0684014532a19ccb57e4e94d1097a8484e8d67e31ce",
+ "dist/2022-12-27/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "549733dbbc3ec23976d6975e78ec8b8a30396eb45e4a8f5eef6d4c846cf04da1",
+ "dist/2022-12-27/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "f5997ebe7c67969b7d14a2233897b6014ebd9b38010eee101d9e484d42b220c9",
+ "dist/2022-12-27/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "3450c71c082bf84115fb035239453e39230afa0575dca0fc52586222b474a0c2",
+ "dist/2022-12-27/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "a16c397c5e980a926e0122cff5f8d30c4b54c2dba7f48ef00b587c5cda8f500d",
+ "dist/2022-12-27/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "62e025463eca2dac0547275c7827e6ecd109d1b84d056526e647abd220b3e1fc",
+ "dist/2022-12-27/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "99c5f5511b23d93707df394c2ab90ddd98e7876c9ee74c861dc919cdd498399b",
+ "dist/2022-12-27/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "eee574420f365d02d52f5f4754563bc1fe4f0b07d02a554f6aa886bccbe4c092",
+ "dist/2022-12-27/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "64e53a591e2d4dee9935fca4a2df18fbbed1b00b74dd6631473ba2d5b257891b",
+ "dist/2022-12-27/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "37d2a5f1c496c8ad8d2b5af5e89a4a325ddcef32ebd7087ef3cc9e653e5a8f4a",
+ "dist/2022-12-27/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "8753d9bfdda6decdcc4f58d2391956609e0aeb75ce4368c7ed52c23ed3f28943",
+ "dist/2022-12-27/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "303c63a294f2112fceb70cee063f35cbee3296b93ca91e43300e72b064d80da7",
+ "dist/2022-12-27/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "96b752dd307d2709dbf2b91c687a55992f4e0e5a143223a8c2a267883b4a2832",
+ "dist/2022-12-27/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "e5c279922e9adb47e6ecaee191ad291bfc627aa05e4c026628664bc47e5ce254",
+ "dist/2022-12-27/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "7e0145fe22bfca7070dcace196e3229a86f9f5b31ab1cfc4fd7ff158db5b1388",
+ "dist/2022-12-27/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "49df0b5774471ced53703942c6551c045ed56c92a3a224615f583511bc845a61",
+ "dist/2022-12-27/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "955e67ac19fc7a2a882f759339343c466da9658b2cd95799dd78328c13d6527e",
+ "dist/2022-12-27/cargo-beta-x86_64-apple-darwin.tar.gz": "a0e01a9ded551ea1f411da70d4481627579e870c2ff7592efde1d8be83ca46d5",
+ "dist/2022-12-27/cargo-beta-x86_64-apple-darwin.tar.xz": "a9205d81dff07cbf2468fa6f6999fd0f1266ad4faf84f5688e3e5cb330bdce0f",
+ "dist/2022-12-27/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "d6406b59361cdc97df606901beeafe6660a4cf557b9de4a313d4659c83f10255",
+ "dist/2022-12-27/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "ae15fd38cfcd149de306280a48785fe269ea36b1a958de6815adc7a80792d798",
+ "dist/2022-12-27/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "d75a793188af608b8bbd92907ff69294bc66b85b7ffe03882abcb661fd8c27f9",
+ "dist/2022-12-27/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "26f4ed51fc227dccc67d4c68fcac78374fb1441093d3524ec157b1b6b6e90012",
+ "dist/2022-12-27/cargo-beta-x86_64-unknown-freebsd.tar.gz": "6503b65a5258b5517c5213f0fb858aeff7e00c453a3633749d1a72f7f645050b",
+ "dist/2022-12-27/cargo-beta-x86_64-unknown-freebsd.tar.xz": "75ba61fe1670d0e4cf9f9f35460c663701c75ceca95917ed25e98f20cc2f0ef5",
+ "dist/2022-12-27/cargo-beta-x86_64-unknown-illumos.tar.gz": "e003c3a1ed8b57546e6ecdcbbcb58a97896a8e511b6a8fdc31100c24b8dd5a17",
+ "dist/2022-12-27/cargo-beta-x86_64-unknown-illumos.tar.xz": "b377d76b8fae7ebc607f33400cc0b37974fbf02a4d29187b1f0f6f668c12ff01",
+ "dist/2022-12-27/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "0dcfb9c65b5ad5c6af905c78d6914f5d7f8a62def817e64192b29c957b848783",
+ "dist/2022-12-27/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "1ca64be7777194c3191350723e8a909cce93d8ac28ceafb5df641f3066c6a8b9",
+ "dist/2022-12-27/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "9c24ff865929e88db27285fcb4a10adf97289a388f93ff5fa421211f35267047",
+ "dist/2022-12-27/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "b794e0397ca0ec274e307468ed56b8116438c0b8a444f593eb56350d687e8137",
+ "dist/2022-12-27/cargo-beta-x86_64-unknown-netbsd.tar.gz": "0fc5f8716933c46509cc05492e5bf75f6d06575dd6f803882397929b95394e12",
+ "dist/2022-12-27/cargo-beta-x86_64-unknown-netbsd.tar.xz": "0cfe7415cb4c0a96019eefe0363c1d61934d76f3b5fb72a113b9de1401ecfad9",
+ "dist/2022-12-27/rust-std-beta-aarch64-apple-darwin.tar.gz": "777b016bebe68ea79bfb336eedb595174466bfd54321523b9913f5c2741d0135",
+ "dist/2022-12-27/rust-std-beta-aarch64-apple-darwin.tar.xz": "c4ab94494052bf3fb37a226e1313886546bde1ec4d7188049cb95dbf2963e1fa",
+ "dist/2022-12-27/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "884004f47fea38414ed805abda4afce3adf5a83fcd072ddececfa888e55bdef4",
+ "dist/2022-12-27/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "db0858bd63fa8609ceb6ee42cbddc31f31b2a0ce0c02e1fe1c2d32f0c8d607c6",
+ "dist/2022-12-27/rust-std-beta-aarch64-apple-ios.tar.gz": "996c8612a39bddb3047ce0f23f761deeca61d15b36f2ea270f5a220d14c1ed27",
+ "dist/2022-12-27/rust-std-beta-aarch64-apple-ios.tar.xz": "c06360094800d069261d363b709ca552d3899d50c12d39c23eb58d75015c980a",
+ "dist/2022-12-27/rust-std-beta-aarch64-fuchsia.tar.gz": "891f1909fcc78019f77d704c3b3b1031c605dee01a116f04e7f4f402d6b9b2af",
+ "dist/2022-12-27/rust-std-beta-aarch64-fuchsia.tar.xz": "3033d409735b299b6754852c28c1dac378a94ad892144ed76199d542a265c8a7",
+ "dist/2022-12-27/rust-std-beta-aarch64-linux-android.tar.gz": "080c97ad158327dfdd24a3c17477614de1dfe27f1236c73ed43b1e7e881f6b06",
+ "dist/2022-12-27/rust-std-beta-aarch64-linux-android.tar.xz": "80b89416148f4ed917978686ba337ebdbb3d4a50903a792831fa3b83032c43cb",
+ "dist/2022-12-27/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "854badcf35650c196b2051be46254d2f4e86b4522dbfa9f1d1a64148cae7bf1e",
+ "dist/2022-12-27/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "e4ccf358da4cb13b281c999318816fc99948a3531e9ecd6d0abad9b819c117be",
+ "dist/2022-12-27/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "9473f12fc35106ab9144b38bddc3c35d56b0413bec06c2d1d5f43d4fde614331",
+ "dist/2022-12-27/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "5cb44be7d8adc0589afca90ef0669c42f03a61a622d856fb057d450554d24c01",
+ "dist/2022-12-27/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "25ebf045fc59488abc07ed24aa3364fb64cc186f6c852b12cb5c094f81d5fd69",
+ "dist/2022-12-27/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "d43bca65f55159d6eafb7e342ec5d4598d63bc8fad0c9fc15b6bd88743321d4e",
+ "dist/2022-12-27/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "91198741990d9300024da5113843cbeff02ed9ea344d9feb57736e9334136d27",
+ "dist/2022-12-27/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "0aee6204d34246480be1d0f6efd6a66eb10d83a9dd1c215433e840949687c598",
+ "dist/2022-12-27/rust-std-beta-aarch64-unknown-none.tar.gz": "97f3193bfde82b997346b49231a0f24a6960da88773bf27c73f57f40ec4f84e6",
+ "dist/2022-12-27/rust-std-beta-aarch64-unknown-none.tar.xz": "1d2122442cc0a6595c901831e8cbaaeafd2043fbc8c4b028265310d2086673cb",
+ "dist/2022-12-27/rust-std-beta-aarch64-unknown-uefi.tar.gz": "6d351f35cb9252c2825311eb22049283534cc2877cfd673fc1b5b3c94c6ef864",
+ "dist/2022-12-27/rust-std-beta-aarch64-unknown-uefi.tar.xz": "054bb5a98df25830201ab04e81f63630dc329f48daa0d715a3443f95d2c0f442",
+ "dist/2022-12-27/rust-std-beta-arm-linux-androideabi.tar.gz": "93b70e7c6b686ed5695bcf2f0b2da14e89a50e54304d445ebfc35107f689c442",
+ "dist/2022-12-27/rust-std-beta-arm-linux-androideabi.tar.xz": "9b8983be6089216428007e968844f57bd88e2371dd592b1ca06aed2aa6479d8c",
+ "dist/2022-12-27/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "753ef462dd47349fee5f45adadc073363250fbcbf566ff337250466d0ce73343",
+ "dist/2022-12-27/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "c19389db997fd0e158e5a5e847f566f6b03f06b3161ce5644ca0178fae25d0f5",
+ "dist/2022-12-27/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "c819d6a3de743f54e28eab0f2c7744dd5a5be7c6677bb712bfd3f93938435194",
+ "dist/2022-12-27/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "4ca09f9df5476449c3510c82e284026329411253e2a02c90e6239f30a9a6074a",
+ "dist/2022-12-27/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "f7994d565baee0fbdb010211fcd30398f7f90bd97770ce72e5ba34bf1f06a466",
+ "dist/2022-12-27/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "f54e1efdb9a088a13371e5fd7e1599a7bcadc5db4247e8811ab9d374c17fac8a",
+ "dist/2022-12-27/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "add3333e892ccfc31b8fa506e79d5633261daf13e7902549ac5ecfe8f3655bbd",
+ "dist/2022-12-27/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "bfa9a7cb0de16ecef093d593677e32164e4e68042806f543824c16f2a12b55ae",
+ "dist/2022-12-27/rust-std-beta-armebv7r-none-eabi.tar.gz": "81c958b4ba5933c02cb2872efc4d5de86a2bc1a1d326bf563256ec74e256fd8f",
+ "dist/2022-12-27/rust-std-beta-armebv7r-none-eabi.tar.xz": "634d2e35b2314826198eb2a7fd6f253cac5c2bbe7a5a7c7cdecc09949db23b3a",
+ "dist/2022-12-27/rust-std-beta-armebv7r-none-eabihf.tar.gz": "62dd020647cfa88c6719b4b9a803d07f3ccae7c2f94c924e1529def264db1be8",
+ "dist/2022-12-27/rust-std-beta-armebv7r-none-eabihf.tar.xz": "53a03694b610146cb80e0ef0033600ea4dd6f8b7d413c3ac675cb57c9b4c5cde",
+ "dist/2022-12-27/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "ac7c396d35406501eda50191b92abab74e19148ec6caa2d5171bba35f2d3ec96",
+ "dist/2022-12-27/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "058c514636a2063193d278e16fc683dbe9c1dadcbca45707152d150dba71065a",
+ "dist/2022-12-27/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "bc5400e734bc4747b3ea44bb5c3cf9af5f11d5b5f2e970bd4626a25a276f15f7",
+ "dist/2022-12-27/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "0079d1cb3d1fd5be99bed480e6ec0b451dd9e2a2299e3347cbee33344cd8c718",
+ "dist/2022-12-27/rust-std-beta-armv7-linux-androideabi.tar.gz": "9dbc9e97f9990f03efe67c817c9dda7fcdc931c7605742182f4d128859c1a53f",
+ "dist/2022-12-27/rust-std-beta-armv7-linux-androideabi.tar.xz": "d0119bed6cb41629aa65d83f7c1021e05e2f90bd21a28e6f0d3b6f0ea9127dd4",
+ "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "09cab74e4a6e38d07622fd80e97d424d7437d554c05ce1896acaaddad0e3b637",
+ "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "4602ca768e8ba85cfc5a4d4a2964cccd048ad82f349b7453f077e38de918cb0d",
+ "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "b983a7699fce4c6f9c7f16ea3fd2905a8ddf21623bae71a9e7515b5cd5b288ec",
+ "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "ca2d6d4c09326559a1528cf32c7a899f985c7e3b7751cec8911d0facac149e51",
+ "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "dfa375f608f297f4dd0fc39921609ecebb31101850d73a8bb8b67ce98e319f3d",
+ "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "3159afaebb2b17f6b12128e2829944f9406e26cc7019eb33839fda311ea0b809",
+ "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "5a2c2361c944d85455b7a037bc820fbfe824180106f5a6d6fbf4066ef78236a3",
+ "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "0bd7ac1cada0a3a3894d404ad5871ef3abc4963eeb5a1f05f59e6264b1e6cc3c",
+ "dist/2022-12-27/rust-std-beta-armv7a-none-eabi.tar.gz": "1f9daa0af4695c51e4cda38235497923b9adfefd1a6eb4be086d720cffab7594",
+ "dist/2022-12-27/rust-std-beta-armv7a-none-eabi.tar.xz": "b9e5b75720d71bc9e0e16b73b7cf04cd3e5a57da7a6b842926ffcf273308543b",
+ "dist/2022-12-27/rust-std-beta-armv7r-none-eabi.tar.gz": "4837b13f144f12e9edb5b49ddf5169d1cd13cff0a3ec3e54160714d45138448e",
+ "dist/2022-12-27/rust-std-beta-armv7r-none-eabi.tar.xz": "32a56e92757a9ee82ff71962c7c8144e4240133d44de77d5955510640a31061b",
+ "dist/2022-12-27/rust-std-beta-armv7r-none-eabihf.tar.gz": "d31ed0250a195a8043e71c8ae3b2e86111ec07b00892ae05c3783761b20774ee",
+ "dist/2022-12-27/rust-std-beta-armv7r-none-eabihf.tar.xz": "06b70c26d9161b17c2e4ca9255ae1a73f7bbeadb24d733c320875e3dbbc77caf",
+ "dist/2022-12-27/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "6271afcf4b05fb4de2ed08ba441b3ee0b476e2e33dbda8a5efa3d7540475bca5",
+ "dist/2022-12-27/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "131c51bb571df676dbafd84d5015888c4bc15130bd7300d4c53c1667907f7f51",
+ "dist/2022-12-27/rust-std-beta-i586-pc-windows-msvc.tar.gz": "d6bca2e8ba737a4704dc01dd6fca58a7c8dc8a065107f9fa98588c5fbdfe39a3",
+ "dist/2022-12-27/rust-std-beta-i586-pc-windows-msvc.tar.xz": "d64aa029d4209256e18d7bed6e0e28156a965b1d50cb3eb8d70abab57be55a97",
+ "dist/2022-12-27/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "f48248f5fedc961ea4050254cf9bdbbe70420ebdaf712847a5374a3c97e21df3",
+ "dist/2022-12-27/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "c9287bc9be332f084a2779803964ae374930d3bec787155ac3c8d1d6be6a587d",
+ "dist/2022-12-27/rust-std-beta-i586-unknown-linux-musl.tar.gz": "1914ba0edb77b0bc7cd83dd93d8a6ca53b29800844cdec9a976342982aad8b27",
+ "dist/2022-12-27/rust-std-beta-i586-unknown-linux-musl.tar.xz": "30d5d1bf54eb6758e0bd3a3f48f186a957fdb1310ba8b3625b5f33994c8a58fb",
+ "dist/2022-12-27/rust-std-beta-i686-linux-android.tar.gz": "6c05a59ff653bcde6a71dfcbd38718ca3cfeb89b7ec09d1cd380fdb589941d27",
+ "dist/2022-12-27/rust-std-beta-i686-linux-android.tar.xz": "80b6b57ff73a9483046380c0d4cfc8c090fca5fc4174d5c47f71fffccb7178a6",
+ "dist/2022-12-27/rust-std-beta-i686-pc-windows-gnu.tar.gz": "941bb6f5107630a0b26b8749be29c6df920ccb467df367a5f55491b062352f4a",
+ "dist/2022-12-27/rust-std-beta-i686-pc-windows-gnu.tar.xz": "f3f2ece3bb0080980e099c176a8a1366171741450fa8b8e515362572b519e19f",
+ "dist/2022-12-27/rust-std-beta-i686-pc-windows-msvc.tar.gz": "a94fcee79bd5941e718a112d855163563f6e5377b59a9c1405ac8804131b0383",
+ "dist/2022-12-27/rust-std-beta-i686-pc-windows-msvc.tar.xz": "4bea862e2d998e976526cb741b7d674a7d620fc7e4838955ef4c53d000cf24aa",
+ "dist/2022-12-27/rust-std-beta-i686-unknown-freebsd.tar.gz": "e5cc60f1c00d966809cd76fd452bbb03452c5cc94a487ef4ad14af12608ae5fa",
+ "dist/2022-12-27/rust-std-beta-i686-unknown-freebsd.tar.xz": "df8df7d1750cf9e92b3e4b57b83b195c1eea6ca62f38ad317882a69e2e813ba9",
+ "dist/2022-12-27/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "4ff8fc04b63f7a80587d4f75376c74ade7721369ad1508faf5c0f83930e1cf7a",
+ "dist/2022-12-27/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "4716141a8be8017adb8540c05f88e6463b2add95439320b0084ffb290bc0d943",
+ "dist/2022-12-27/rust-std-beta-i686-unknown-linux-musl.tar.gz": "d7cff128c80db94aaaa2bb708bafa3f857fe8b819ff21a85f7c6c7c5170576be",
+ "dist/2022-12-27/rust-std-beta-i686-unknown-linux-musl.tar.xz": "bc83b17627e87ee4b555e9cc5912dbfbba74586f46719994be6832e22f70424b",
+ "dist/2022-12-27/rust-std-beta-i686-unknown-uefi.tar.gz": "ec6723c138565c4d9ca87bcda199aceb7b3a42ddf979658cf9e8433a4dae9c70",
+ "dist/2022-12-27/rust-std-beta-i686-unknown-uefi.tar.xz": "0e67f10a29f2826399604839a4dcbd173f8de39a755283a0c245c54b8a658210",
+ "dist/2022-12-27/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "a78f899f6fae1671e41aa7d76b37d9041cc32dfa6e9315dabff3afe21f93700b",
+ "dist/2022-12-27/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "4c74cece45b9271c77c4b328d1b3d876b50429077074580d771fc2b03f0d4738",
+ "dist/2022-12-27/rust-std-beta-mips-unknown-linux-musl.tar.gz": "a854fbab503a0541d593cf9496a4e4cf8b9edb49422406b3a7f34e3fa21905f6",
+ "dist/2022-12-27/rust-std-beta-mips-unknown-linux-musl.tar.xz": "f42a81564e7366d5d630632af3113b99c5de6d147d7eb9e31da762bb9d35d4ea",
+ "dist/2022-12-27/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "de070d1ae3fb8a825092a9a78c26db553839c6d862e451a497d5f94230414bc5",
+ "dist/2022-12-27/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "0a7092c99c587ef69801af713ef834bae809e4868dfcff43babd44bec532717e",
+ "dist/2022-12-27/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "7077c20142082b0e2b8d6299ffcd8739c8295d315b917563cffe6d42e129cd08",
+ "dist/2022-12-27/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "86f0988f3baf0b5bbed81483e7d68004651f227ab22d1d36b34c73f132191dfb",
+ "dist/2022-12-27/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "536fe3059a8095bcc1c44391c27b7d9832d6a057388b4de089915810cbe1baae",
+ "dist/2022-12-27/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "6b4e397a3a175f4cbbddabb750df14d668c1f4c8520577d35fbcb9dfa8613097",
+ "dist/2022-12-27/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "30f42499ab4f21caf21551e0e92bb5db9a2e0f42fd0b3e59ee9789dd40d10391",
+ "dist/2022-12-27/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "1190cfa1023a8d35d202979a1070863bb713495c2c9b720d0371b6d70d23bd7c",
+ "dist/2022-12-27/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "4ac79a395ba5d70e1a09d0e1ce232b9405b9995f7c459d176be52eade40bbab7",
+ "dist/2022-12-27/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "42f3666885680cbb2d15ec85cfbc9103e5b170346a9b8cff63a2d15f78472c67",
+ "dist/2022-12-27/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "0b1c979205f8476ad6f0e35c05acb1976cb4c44006c25931e73c35025939f1ff",
+ "dist/2022-12-27/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "7b6c76ae46ca56746b0bdea404125256636f05c1354e5dcf32c2a487d25e0ee1",
+ "dist/2022-12-27/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "ad9cb2ec325e2a2f14ac4db6a5df53a7c06adfe8c4c58f0f2c83748a34d0c550",
+ "dist/2022-12-27/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "1d507bb0cd8c80ee4e9155a0740c2319027ee5280552c1056ee7921a82bb9aa7",
+ "dist/2022-12-27/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "e8d3b7bb483d7b3b737840ddf7a27a28c216d9d0b3ffc7ccded547f76bc932c5",
+ "dist/2022-12-27/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "130edffa27b82def2876fb5562fc7a3971d33855e3ce023e18507b3e1bd47d10",
+ "dist/2022-12-27/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "b5659dcc18fb0e5849acb13df7153518c8df5ca9566852cabaeee33583321d1f",
+ "dist/2022-12-27/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "6bdfae3e9cf07608c862f4c042c47ed318c388bfcfb4cabfa233580b90c7a459",
+ "dist/2022-12-27/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "f28795f8c2823bd817df63486d8a11b6b7cfb9538110e87d8d008ed979a81a3c",
+ "dist/2022-12-27/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "695f6acb6ddb4c4a87515646157b88d2f58e2114b100f22bedcd4e2fa8de00b8",
+ "dist/2022-12-27/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "5f004e4b265efae872e8b0d8fda81f4e65cc50452d558ef90b9bef7639f6ba6d",
+ "dist/2022-12-27/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "c93c1cb534e83d43c40c62ed6623559e3e380f177c4bd151a0d1389a80a58139",
+ "dist/2022-12-27/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "79988bb7bfa27dcacae0c459143be6a34f328ec6bcb73c2267d41a6f022fc045",
+ "dist/2022-12-27/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "11235a96e7e8e14a173db0be71cd1ce7955c79f5a7d20b7436238256a06342fd",
+ "dist/2022-12-27/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "a315accc791f1247e92a6362eb7bd6ab899c4688db7decb36b8d892c200186b1",
+ "dist/2022-12-27/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "a4f6ac1d21ecda00c9d3e34d900771a4c5a50e3e5071d2eba837c9e4738edc80",
+ "dist/2022-12-27/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "06dd8941f63c3031fa0383dd34981c655b26fd10d5510cd06bdcabb4a592a435",
+ "dist/2022-12-27/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "882e464b44acb7e286f49d45a4f5a41fbf570ee0d78f1915fd6f94ac392fa928",
+ "dist/2022-12-27/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "734d6f54d143ddddc2141da72ee02a32d4d505e20eaf0041c86c89f8ad8730ea",
+ "dist/2022-12-27/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "be32ca1ddb2d48877c70c9a128dba02bfdca7a00e93c114c3c99127e7be04adf",
+ "dist/2022-12-27/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "a6c70d3715b7e50ff15f5473348d8e1c5a061036055a85784b5e84a99e4008ee",
+ "dist/2022-12-27/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "0dbbf637d310f7ef44cb1bc08122c172606c8ff1c886195eebbd52cad5789597",
+ "dist/2022-12-27/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "3e2f7751028f9123d94ff72b08f8ce0b40da36eada77e1414d4178756b46313a",
+ "dist/2022-12-27/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "382a35c79a03f7abebb9c5788f9dd19bd0973cb89e9b07a971eaafc611c3645a",
+ "dist/2022-12-27/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "3eb49f766b206966433eecc7cdbbf709e75991644eae6f44596e5ec893fb3e8b",
+ "dist/2022-12-27/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "9162e50f2ddb12fefecdc7c4c2d60e76874e78fd89b45d7fd81a6c95a856ee28",
+ "dist/2022-12-27/rust-std-beta-sparcv9-sun-solaris.tar.gz": "dbf20b8fd52e1b6a553369a1690344574e6c660996ddd5121d4a05bfb71c87aa",
+ "dist/2022-12-27/rust-std-beta-sparcv9-sun-solaris.tar.xz": "a40d8d444e57eabeecf8acf0b59f24b5d4e2c97ee538bfe38904a1f81a48fb14",
+ "dist/2022-12-27/rust-std-beta-thumbv6m-none-eabi.tar.gz": "1e63244aa865e6a115e603f238b64410606453fb38802b1684fa6397660a1501",
+ "dist/2022-12-27/rust-std-beta-thumbv6m-none-eabi.tar.xz": "ecd94de3f4a3aff8f9f920ff68383e342dc293ad2fb2584c9d9e48bf60eb82d5",
+ "dist/2022-12-27/rust-std-beta-thumbv7em-none-eabi.tar.gz": "ad21ab2584999c7c528dcde2e435d0ee73686b9b94c4f31dfeb3abf3cf9b9821",
+ "dist/2022-12-27/rust-std-beta-thumbv7em-none-eabi.tar.xz": "9394854e14bc3e671060630c01b6977ab5afcf9022790986c492fe58f0509191",
+ "dist/2022-12-27/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "1cbabb457c0546da725a548a88b3268bb0feca4269af2b9cd0b98455c2e0c468",
+ "dist/2022-12-27/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "1bb23d8d2783554e2043ed71cf982d9750bafa3ccac6e387b25d279137042867",
+ "dist/2022-12-27/rust-std-beta-thumbv7m-none-eabi.tar.gz": "076a918e524cc33a02ab2c94e3a607dd293d5d6d63e0797b16f2246057d1082c",
+ "dist/2022-12-27/rust-std-beta-thumbv7m-none-eabi.tar.xz": "de8f3e8907fde91bfcbff0c353eb3d1cb9d06dec31142479ef1ad2c6c368d5c6",
+ "dist/2022-12-27/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "658d66031594324821649058e16e3e0b06542e8c9dd17c5fe705c487b5915ffe",
+ "dist/2022-12-27/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "56a9a0235c0aacf561cfc9e7981c57a4d174dbedf5ed943d266302662246b10e",
+ "dist/2022-12-27/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "3318c23ea42624e26cf2a25dd5fae206ccb96137d6833f28d7bfebe3ba7e327c",
+ "dist/2022-12-27/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "b91396e82a9c30711608c3650d637a3ad56ea90d682460c791210f8bfb5a6854",
+ "dist/2022-12-27/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "55b45e9863e197262bd97a9bcb80991c9c34385acaa228b062546b690621b530",
+ "dist/2022-12-27/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "dc0b7ed56a142475759164713bcdd7c64958c7e7febcafa5371414082ae495b2",
+ "dist/2022-12-27/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "b2bed92d03b295035e4bc4e0fd63b44ee1cc634edb394cfbd7afdc00353a73e9",
+ "dist/2022-12-27/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "bcce53fd7c0c494ea1c45227190a959e992f07851dd064b2a9c599fafb07077c",
+ "dist/2022-12-27/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "d6df9026c218b906671e89e433b165552a9486e41399a8f01a12d10495afc8dc",
+ "dist/2022-12-27/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "f5f2411e3ff94f6e524a14ee46e6e6bc2e9ec91e395b0382f7a40bc6e970d623",
+ "dist/2022-12-27/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "c766ec36907ce0a7e76ba9a227fdd57eae7a744bc5679b67a6ce1d6ab41ea19f",
+ "dist/2022-12-27/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "de5f398bc34fb22489e9f6f2a9847954d8231ff5732f2595e8be93eaf7849986",
+ "dist/2022-12-27/rust-std-beta-wasm32-unknown-unknown.tar.gz": "e3ed4bc39da4731443b3bbd584106444aceaf91720546ac66e98712fe65dfa93",
+ "dist/2022-12-27/rust-std-beta-wasm32-unknown-unknown.tar.xz": "704a65e4f3e1afea9d1bd6a60c4d3e5fd57e3e14ba0dd2e2b94305c3e1c92cb8",
+ "dist/2022-12-27/rust-std-beta-wasm32-wasi.tar.gz": "03e2ca41c758fb4f9a2ea562ac4ed7186e27607458bdd7b575d786368336ea11",
+ "dist/2022-12-27/rust-std-beta-wasm32-wasi.tar.xz": "1ebc2ac44181d6d26928cbd550c64c5b496008e97356c68497f15f8cc8351f37",
+ "dist/2022-12-27/rust-std-beta-x86_64-apple-darwin.tar.gz": "0f0520f7163ef3d659e5761b2f0c7a9f2de00b2f769eeec8d1e7e9b3b08daf6d",
+ "dist/2022-12-27/rust-std-beta-x86_64-apple-darwin.tar.xz": "25795f1876330666b7fd6dd724661b364643448d0688d479f492c02faf2f7a4a",
+ "dist/2022-12-27/rust-std-beta-x86_64-apple-ios.tar.gz": "014a022bbb524d8c550d5dc7d678b9764adcc9962538980e9596ebced9c5614d",
+ "dist/2022-12-27/rust-std-beta-x86_64-apple-ios.tar.xz": "9b38e214e203c959eba0e8d651410f6cafc9e4b5725228c2bb4ac8f562e6cfa7",
+ "dist/2022-12-27/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "afd9236304892945334183b31072b9b9f9b4faef8b7cdc4ad1f45a9b3e080a58",
+ "dist/2022-12-27/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "33a7e5fd18f2166fb2b6cbe7630d80915533d59afc0080f1370bcfad1114eaa1",
+ "dist/2022-12-27/rust-std-beta-x86_64-fuchsia.tar.gz": "7e91e1298da3676c4c051d7f34eec21f2fffa0a34af212c785b79c2d1048fe92",
+ "dist/2022-12-27/rust-std-beta-x86_64-fuchsia.tar.xz": "fff70ed752d0760990f7a90bc3c50ac6586e8b012e61a15b6dfb325dd081b9a9",
+ "dist/2022-12-27/rust-std-beta-x86_64-linux-android.tar.gz": "f9183794392422fbe8cfd61ea7bae0dadd8731e82b1d15a59f4e93acccd2048f",
+ "dist/2022-12-27/rust-std-beta-x86_64-linux-android.tar.xz": "4fce2ab0dacac153de7d9805786b17d517863b0ff04a8224540daee86eff4056",
+ "dist/2022-12-27/rust-std-beta-x86_64-pc-solaris.tar.gz": "d5b64111b3763063c38ae63915ca366a4fdb63f0dcf8121588a8953f01ebc669",
+ "dist/2022-12-27/rust-std-beta-x86_64-pc-solaris.tar.xz": "c396b086773dc06db2e59bcdaff8ffbb7069efee5841b9e3cdd4dfb05fd95ce4",
+ "dist/2022-12-27/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "e851812f69bcb2fe606bfbda125fa6b3f55752fd1a2330878c48ca99eedbb8b6",
+ "dist/2022-12-27/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "689738a0952a0eab27ba3d3f9bc9b531ec29f338ea373bfa783a83786d5c2885",
+ "dist/2022-12-27/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "b51f78199bfc1417f020e2d0dd16044f63f6b6675b2b6856f669f8604e44a6bf",
+ "dist/2022-12-27/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "7713269f3c51717f6231cf4100043eca2330512b602c2962da81af561e90193b",
+ "dist/2022-12-27/rust-std-beta-x86_64-sun-solaris.tar.gz": "9f0a129f4c2ea324e2dc94fad3f7acbc7bf2b988f66d9c42dd8abbc60c569acf",
+ "dist/2022-12-27/rust-std-beta-x86_64-sun-solaris.tar.xz": "6ca71851fd0a7879aa750a63deb4ee587f82c28b27486f716e4fae5ebe599086",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "6cfbf0f85757854fba1551c3312baac820e398b573d50b005cc3958723db7c82",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "2e2dfb82fa7e23f888ae9541a30d15ba978cb29bbdfec6afb00590a39c16df5d",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-illumos.tar.gz": "92650856a7e74c8b912d5c84cd1002a490f9c8e3fa4506733fcbedb3cd42792b",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-illumos.tar.xz": "3dd302996bd3fb9f8b077e6d5fe3dc6f7dd9590d5fc3eb3bab2cffaada4e99d3",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "3a1faf905ffc7263e725ce7571cb84dd8698adbc45b6902da86350299b2e3ccb",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "daef635cdf88c8d9c924c0d66e2b26db1f56bda9b48ca0c21e089060b07dc997",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "567bb99f67737cca721d1dc6975daefd3dad29b13d531d3b939405ef4e7aee84",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "aa218c4547e77f33ba4bc45bba0b6fcf3cce9355c2cf11d74a3a4c5e49f9b3cd",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "de43b04cccb3c2bdcd2a7993c391299a4bde5041102ce0eb5e32b6cfae86cd79",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "f99963704b4c3189361925ec8b53daa2ca15ae4af9215cbd87cfec23e044cefa",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "3d4949e63f137552e3b74e50b366f95d7a153e7c61cf5587634be51516fdc610",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "5b48095a35f862190536e64eff726327e25c23981c0bc1224c8c44bfccbb705d",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-none.tar.gz": "12b5c69138260daf976e963ba503c66ec4432f11cf7506bc9ba691ac2c1df4a1",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-none.tar.xz": "5c334a67f6586dc406b6e55c7f9d64b7701e1c7879bf5860b378069301c57854",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-redox.tar.gz": "58c15f9119e5f78d7c70b24e67af57ce10bb2d2cb1347b9b4631478665c624de",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-redox.tar.xz": "a2f8b635254d53ec5b902dbeb8ac63c6c3982f94dfbcaec3d093f17f0f5fa896",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-uefi.tar.gz": "1ce5c25480e97699b12c180ed6198766a0c12a3543dd317ba6f4a52538027b0d",
+ "dist/2022-12-27/rust-std-beta-x86_64-unknown-uefi.tar.xz": "e4d9ffe34ba40e5ccf87007085dc4daa20a8a52944f092e2a075527702b55072",
+ "dist/2022-12-27/rustc-beta-aarch64-apple-darwin.tar.gz": "f5c8dadb8eb0335a50326a94f858625e4f01e3159e933d58f9d24338d47943be",
+ "dist/2022-12-27/rustc-beta-aarch64-apple-darwin.tar.xz": "0a6eeb32e4d85b628044c3e075e5f1414a42bb582905b199d360addae466d3ae",
+ "dist/2022-12-27/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "0f7ce917f14a1d42637fbbbc343473596becceb22634cb7c7cdee6beaa2b9ca1",
+ "dist/2022-12-27/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "49667bd902fb5fb2855e843ca5c1dcd453171f164a3dee2dcd9e09b0d9e1e57e",
+ "dist/2022-12-27/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "d5a03695685afff4debff8e09f2d91db02d2ac29981a9ec230619c3e388ce1c9",
+ "dist/2022-12-27/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "db1aeb772a08f111d8f024164b570322f45ecab0f6db4e931b91971b2b982323",
+ "dist/2022-12-27/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "0e51f97b677b5c813862bba3e5a3b0884f0ecdf9b7c3676089625431a3d0cb2c",
+ "dist/2022-12-27/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "f88c6c33ac3682f340ed60b4f62ee8ed61eb21069a1f0a912024d19e41c0d5c7",
+ "dist/2022-12-27/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "25abe3158ec3ab7c064341247d78ea265ad7e0dc2063837fb5cf0a3bea9d011e",
+ "dist/2022-12-27/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "1d430b8e35ebd63a79b34917edacebb76b2fa8f1cea4772ba2c4ef0340485fb3",
+ "dist/2022-12-27/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "1858d5ed21a3132af4b56c841cbabc9fb834d501946956a0e9aeeddfa095344f",
+ "dist/2022-12-27/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "17cc52dbd6ccbed4677ad52fa666ea10295c11209528e78ac190f01b5d509f87",
+ "dist/2022-12-27/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "3440edd99025f24f2640528d2d1c10047c834b93cb09a935c65ecfb72012e7d0",
+ "dist/2022-12-27/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "7e1ff0a950db0ecbadef3a9ee55a593891f11a42c6c0ff59637074c8b5c4da74",
+ "dist/2022-12-27/rustc-beta-i686-pc-windows-gnu.tar.gz": "90487ff490c4e71ae62e28492cf49600f8f92e0f35f5d76a50eafcf4bbcf4bcb",
+ "dist/2022-12-27/rustc-beta-i686-pc-windows-gnu.tar.xz": "8b44fb934aba0eef296098bfc5a9f2994cdd595420ce10f4f310c5ee9d481071",
+ "dist/2022-12-27/rustc-beta-i686-pc-windows-msvc.tar.gz": "0fefda6b62234a43976ebf18d7cd62057cad5b494c750f2d9730f5df64cadb00",
+ "dist/2022-12-27/rustc-beta-i686-pc-windows-msvc.tar.xz": "c9eecbc06e7456bf5e383557a8e5720d00d09de640b8c46139121faadc354d74",
+ "dist/2022-12-27/rustc-beta-i686-unknown-linux-gnu.tar.gz": "8b17d032192aa17e52a3f08a074079561ad7ad6c439f9274aef228af93adacc3",
+ "dist/2022-12-27/rustc-beta-i686-unknown-linux-gnu.tar.xz": "c70638cad594097450a469837411b110e979c303727341623427e3c9e4e4f507",
+ "dist/2022-12-27/rustc-beta-mips-unknown-linux-gnu.tar.gz": "3669ff9024092ab467a1b95aec2cb1692810ee716739f31e3aee7d89e6bd6d7f",
+ "dist/2022-12-27/rustc-beta-mips-unknown-linux-gnu.tar.xz": "165859e42492e33bff634c80b6c96b13fd2252981b4be2821b96a6593933e22a",
+ "dist/2022-12-27/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "2ac418c0cdeb2382aea7296169d747f65349d7e6d5aebbdde7b377e985de354e",
+ "dist/2022-12-27/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "21ae51357508398527b6edd2e5fbb1745fda1c8db2683c40847216c0ce251d47",
+ "dist/2022-12-27/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "3eb68935676424aa8c68bc32b06c010c5c1302fa6f77e9b33e5543565562d176",
+ "dist/2022-12-27/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "0eeb58035b510a166b8506168f67850993e278888986773c779bee24d7a6ec11",
+ "dist/2022-12-27/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "f41d878b2e49beb9ee3a1bb8863ce1b81fae7100a786a78d9922bf8a4fd0dfc8",
+ "dist/2022-12-27/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "e0cd18973c7651cd2e1e041f92900375a045bef62754d432df539000aa5946c4",
+ "dist/2022-12-27/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "7206be82ba39971c6a734f4a89f7f750d581768d82253e31cd985fecd1d17c3e",
+ "dist/2022-12-27/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "f9ec2a3e98a3b94b170237386256c763d62925b430d0e12a289982c7c79d2bfc",
+ "dist/2022-12-27/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "32be7fe5f359cb2312c9bd966eb43b143b336b4acbdf118bf09221574f157b16",
+ "dist/2022-12-27/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "a8163a5b527b1ee932e06589d690c17d8848dbfa8504de6984a718579698abb2",
+ "dist/2022-12-27/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "3e875cb943dd0ffff907f6a582a64f923cb84a07ddd8b5e6f1ec2e1d4228342f",
+ "dist/2022-12-27/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "22537364de01be77a2a5d79486b1090dbee7b3273fc634073031f82576a61a14",
+ "dist/2022-12-27/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "230041ec7d0d4debc841abafe2f3314de51793d281a1077835d9190286a558f7",
+ "dist/2022-12-27/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "2dafdb1a97469737123149608476c248a77ccebeb22834b6a2166fc30551a7ce",
+ "dist/2022-12-27/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "0bd96121550321138dad9f74f331eaefd77ab388843e5561c5c0cb32e9d80072",
+ "dist/2022-12-27/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "ecb02c8535c1518e589eefb10be17830010c40be61f3184576abe93e098d793d",
+ "dist/2022-12-27/rustc-beta-x86_64-apple-darwin.tar.gz": "600b83ea5c832dc6ad9746d74b7dbc8ea566adb9208c4260b183ef05078d2bff",
+ "dist/2022-12-27/rustc-beta-x86_64-apple-darwin.tar.xz": "175930f3062b433fc0a2b959917933bf3347d3f3e0900684785493d0ee9dc6f3",
+ "dist/2022-12-27/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "d1701678ee1d2f2e91f3c1f898f852593ec1b109e430c53c13bc2898b08bca3f",
+ "dist/2022-12-27/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "3400e923af537d28139b9d5d780caa039828e06677cbf499322614006552778c",
+ "dist/2022-12-27/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "d462ca50803b13e136fbfd49ac4a6e186e416041f3cdaa8b4fe72e628cc10555",
+ "dist/2022-12-27/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "81ca0992ec8306ff67b00f5f85f31c6617f78b7350116dd56df082c477c9069d",
+ "dist/2022-12-27/rustc-beta-x86_64-unknown-freebsd.tar.gz": "65fe64154264ab76bb94aa7f107efa9b58cb801c9aaabcc7e6ffa0ce14319ef9",
+ "dist/2022-12-27/rustc-beta-x86_64-unknown-freebsd.tar.xz": "cd6e9bfb6e8c08a46dce7bc623cfdc5a04e55c8377eaa3a75fae0bfe8e00b43e",
+ "dist/2022-12-27/rustc-beta-x86_64-unknown-illumos.tar.gz": "a66bb4b0d9dd9a21b54857c4fa7eb48a88789f0414fec4a1e36c798546c4b71f",
+ "dist/2022-12-27/rustc-beta-x86_64-unknown-illumos.tar.xz": "b63e6299e961b75d9c9bcb46e1dbc22b8fec89292ee6c8758edd43f4b89cb12e",
+ "dist/2022-12-27/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "c768beca1350bdcbcc31c7d3f30c3ccec0ab2bea0c28bc4c89cdd32d9780cd00",
+ "dist/2022-12-27/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "62a675d74274ddb4d8a9146c20942cb91b86e0c94a902169c2cf77f4d471d645",
+ "dist/2022-12-27/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "8f2b81b37bc34291f3d90bb6aec621da0ac760c39727bfd24449c288cc8cb3c3",
+ "dist/2022-12-27/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "053c313c9a751bf0102448866fad2a80ca67b9f79afce82ce03805430e2e695b",
+ "dist/2022-12-27/rustc-beta-x86_64-unknown-netbsd.tar.gz": "a9f42eb0ffdc4bef87669d8fb5163e81a5d82ff6baf631f159b7bccafe9df453",
+ "dist/2022-12-27/rustc-beta-x86_64-unknown-netbsd.tar.xz": "d1ea529e56d57132de1782396a767f8f00f30e2b5f7c9a5fa96c3289b43e3515",
+ "dist/2022-12-27/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "411b96fddfbcc90b4522e3f4e2d6e174f3440960e89193c97fcd5ca8afd62809",
+ "dist/2022-12-27/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "29db6fb11b411dc8351a8a8d1b148e81d9c87f9fb234b3a18722ee470b4d36c0",
+ "dist/2022-12-27/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "32ab437117791eb7113ac522ee4119e2e43722528141302772adf9cda7306b24",
+ "dist/2022-12-27/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "4d892f3c65ef8e32670ab3c3e8fb39a2ae623c59d1ff555ec94644254e954474",
+ "dist/2022-12-27/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "8bff3a1591d25d3e1acb70600e6cd54d712772247376ac5eb90a4b2aafd21a6a",
+ "dist/2022-12-27/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "b81b094d128a37b178da1eda7c72399a9da4bd614e697c53e9c4d78589f859f5",
+ "dist/2022-12-27/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "b3a685d1abe4ac639a0a3ea187b83ec660cd838e7c5c010ed60f8620d17df906",
+ "dist/2022-12-27/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "10b7563202520708fd27cc221ee8db34b368563eb1586be1395955ebf4313d6e",
+ "dist/2022-12-27/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "34e5ca3d51b51ccd97ded5e0c31c999a84f9d5ca5ee3d010e15212a97ab40567",
+ "dist/2022-12-27/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "16638ba8478861276c10847b989fd23de942cb82a9d4da9d92858c6800a39a9e",
+ "dist/2022-12-27/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "13fa3bf29e9d20291703bf2c03bc97cd8e2081d1c747b6835eb0a06f94dd5d19",
+ "dist/2022-12-27/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "98dd01d90657e43ab3a2b91673137cd6ae4c171633db1f1e4b68b2e90bcb9bab",
+ "dist/2022-12-27/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "1370e4c8ad5bab425c02fc924d5ac079ac1387368a3ea5d22c1cdc2edc9c6ba0",
+ "dist/2022-12-27/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "8c312da4ccd992c303fa3f181dc46f9b01022f72061ef43b2fd5848736547870",
+ "dist/2022-12-27/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "0d7a87816f50452349bd26cefdd9f53f2d93a53243290ac59bd5de414407aa1e",
+ "dist/2022-12-27/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "982fc6783ad07235d375c4c8964104fdc64a009ea359cca532cc268a8249e88c",
+ "dist/2022-12-27/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "a5b76840e49a912a819809a2b4c73a0e750422fad4876d11b409a8ed49a77911",
+ "dist/2022-12-27/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "9566b6417a0bdb4c73272d167cc743b297db62f625449343a6f1ab60c52d5327",
+ "dist/2022-12-27/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "bf6cb5e886ce02a3f9b4b00a3696da0ee277af8f690f5a31119c5fce5779cd4d",
+ "dist/2022-12-27/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "7afa5129bc43346614869721e7094f65eba6681bb9b8ca8a3559925f29433f10",
+ "dist/2022-12-27/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "f9805697506a0c730299492fe04c53433c8c4deb70ca245ff1c2cf5151fe306e",
+ "dist/2022-12-27/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "f5d7d5a841a7e7a5d749e52cdb118d2f2cec09de68835a42748db4b3a0a79979",
+ "dist/2022-12-27/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "dc903c64c969a3c21664263c2a30e9cb0dc42069a95f755545ce9648240a376e",
+ "dist/2022-12-27/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "de6591cc73244d99b3469d88439ad442f00037a1cdcaf5fdc5a694b52e47b2fb",
+ "dist/2022-12-27/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "f4e8dba56a1b90d5871bf8722a5ecd2027a4f101299880a8689f5cf46df2606a",
+ "dist/2022-12-27/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "496c19042848726db446cd3df4c52f3e8a5527002ca5492e2d6ef72528d6887a",
+ "dist/2022-12-27/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "58742a5c8230e8749b01058acea639d92d45090bcec6fb7eb1d8f356b0f08631",
+ "dist/2022-12-27/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "bbbdaa32d8d29c407133b0ef2851970da884032effeb85c271d57e58b7d38a44",
+ "dist/2022-12-27/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "1a8a59193dc15d331c3243a2cfaf5c81c023464becc4da63201583d2d2cdc27d",
+ "dist/2022-12-27/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "ee86ae7621804a7b57ccab06dc73b7d87453b53814d482ea43dc26dd01dae1c5",
+ "dist/2022-12-27/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "21a79a050e4461305e280ed7de7c0ade2774ad5230f671c76667be7bdbdc47af",
+ "dist/2022-12-27/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "033afa47c24a4887d40d62391f9f66b76dffdc1bd8f1ad622bfb14db91d7df03",
+ "dist/2022-12-27/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "01cea51850a7f676803f5f8f9a556a71bfb8e7a7e04cc5fc0e7d1b706473338b",
+ "dist/2022-12-27/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "720bf138fb2c541d8d8d0c60d6584cff692c932c6f383901f999e7b3d4078770",
+ "dist/2022-12-27/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "8c3f3fd601bc7d8670f6acfcda29206fd5590fb3a2a6cbb3794ba29cf749144d",
+ "dist/2022-12-27/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "8f1b43479a724197c7ac051c6a6d2a10bd87c6b24fed1d38c9e93f503c87e5b6",
+ "dist/2022-12-27/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "b38b6dc1e65cc0f5031d2045a90404f3b2ce2648884db1f658641e76168d0109",
+ "dist/2022-12-27/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "ed635e2388fcd3bbe94f497404b6787edd5e7471d6c6471345386a43444f46d1",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "457995f055ef35a2491326f95caf31376b21e3cc4c0316cf4536cb7604e472d3",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "d80b01e8c007da58250f7affea8d034a536437efd766eeb8de6d5b7feba9b0d5",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "ee2ab7683e75fa68ad482c81e546cd71b9209497f16a0590507e5de884f1e627",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "d08326f42bf7f38855e37c624a38923d09cbf162b666e8058891aff06ec017c8",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "e42ee4dfdd0aa342dd8192204fd6cfb503eaa0069f70776adbbca352d7e7b661",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "76ec230ae507729fb4ced016a45b0020775a9eef068c2b2e5ae6e3fcb451d32d",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "55f5c89950a81b00efc542c19b42cbfeb9c969af63280106fc78e8893df3d568",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "5a4cf3589d06e562ebed70bf0015af3e80f83de1c4d311c810ebf09feac640bf",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "fb44bc69be6c89c7245b914324e23284dbd9887ac0c1c4a65379344ce78cfb28",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "8d34915b54cd8ea6abf0bff01546f31f74342e1d21128b1e14c32cdfd3505afd",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "d15403f81b36c0a2829ad2dee5c1edf39a993a13ccc57f01bb45c77898e3b9ec",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "4c0c61f404ec6bb87ab044c0850d116c577a2ff3cfda9ac1598a7858b4fe1a7d",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "8bc1fe0e2496769f52a576ccd13f706b26f706f060bebb2618e2c64c3831e2d3",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "bcb527bb736bea88bbbb6974ba388b11fe20596c2c178314bbfdad5e2db65fcc",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "8bffdf816b12c53d5443e2523c0960a37ab67c93590b0bb753fd5a026e67d368",
+ "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "bb5c947ab6dfa28fa7c3d7050e9c14c02eaedf2a4e06d290bee554f569be2c30"
}
}
// [r9] needs-llvm-components: aarch64
// [r10] compile-flags: --target aarch64-apple-ios
// [r10] needs-llvm-components: aarch64
-// [r11] compile-flags: --target aarch64-fuchsia
+// [r11] compile-flags: --target aarch64-unknown-fuchsia
// [r11] needs-llvm-components: aarch64
// [r12] compile-flags: --target aarch64-linux-android
// [r12] needs-llvm-components: aarch64
// [r74] needs-llvm-components: x86
// [r75] compile-flags:--target x86_64-fortanix-unknown-sgx
// [r75] needs-llvm-components: x86
-// [r76] compile-flags:--target x86_64-fuchsia
+// [r76] compile-flags:--target x86_64-unknown-fuchsia
// [r76] needs-llvm-components: x86
// [r77] compile-flags:--target x86_64-linux-android
// [r77] needs-llvm-components: x86
// Once we're done with llvm 14 and earlier, this test can be deleted.
-#![crate_type="lib"]
+#![crate_type = "lib"]
use std::mem::MaybeUninit;
Box::new(MaybeUninit::uninit())
}
-// FIXME: add a test for a bigger box. Currently broken, see
-// https://github.com/rust-lang/rust/issues/58201.
+// https://github.com/rust-lang/rust/issues/58201
+#[no_mangle]
+pub fn box_uninitialized2() -> Box<MaybeUninit<[usize; 1024 * 1024]>> {
+ // CHECK-LABEL: @box_uninitialized2
+ // CHECK-NOT: store
+ // CHECK-NOT: alloca
+ // CHECK-NOT: memcpy
+ // CHECK-NOT: memset
+ Box::new(MaybeUninit::uninit())
+}
// Hide the LLVM 15+ `allocalign` attribute in the declaration of __rust_alloc
// from the CHECK-NOT above. We don't check the attributes here because we can't rely
// compile-flags: -O
// min-llvm-version: 15.0
-#![crate_type="lib"]
+#![crate_type = "lib"]
use std::mem::MaybeUninit;
Box::new(MaybeUninit::uninit())
}
-// FIXME: add a test for a bigger box. Currently broken, see
-// https://github.com/rust-lang/rust/issues/58201.
+// https://github.com/rust-lang/rust/issues/58201
+#[no_mangle]
+pub fn box_uninitialized2() -> Box<MaybeUninit<[usize; 1024 * 1024]>> {
+ // CHECK-LABEL: @box_uninitialized2
+ // CHECK-NOT: store
+ // CHECK-NOT: alloca
+ // CHECK-NOT: memcpy
+ // CHECK-NOT: memset
+ Box::new(MaybeUninit::uninit())
+}
// Hide the `allocalign` attribute in the declaration of __rust_alloc
// from the CHECK-NOT above, and also verify the attributes got set reasonably.
// `Box` can get deallocated during execution of the function, so it should
// not get `dereferenceable`.
-// CHECK: noalias noundef nonnull align 4 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x)
+// CHECK: noundef nonnull align 4 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x)
#[no_mangle]
pub fn _box(x: Box<i32>) -> Box<i32> {
x
--- /dev/null
+// compile-flags: -O
+#![crate_type = "lib"]
+
+pub fn foo(t: &mut Vec<usize>) {
+ // CHECK-NOT: __rust_dealloc
+ let mut taken = std::mem::take(t);
+ taken.pop();
+ *t = taken;
+}
--- /dev/null
+// min-llvm-version: 15.0
+// compile-flags: -C opt-level=3 -Z merge-functions=disabled
+
+// The below two functions ensure that both `String::new()` and `"".to_string()`
+// produce the identical code.
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: define void @string_new
+#[no_mangle]
+pub fn string_new() -> String {
+ // CHECK-NOT: load i8
+ // CHECK: store i{{32|64}}
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store ptr
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store i{{32|64}}
+ // CHECK-NEXT: ret void
+ String::new()
+}
+
+// CHECK-LABEL: define void @empty_to_string
+#[no_mangle]
+pub fn empty_to_string() -> String {
+ // CHECK-NOT: load i8
+ // CHECK: store i{{32|64}}
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store ptr
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store i{{32|64}}
+ // CHECK-NEXT: ret void
+ "".to_string()
+}
+
+// The below two functions ensure that both `vec![]` and `vec![].clone()`
+// produce the identical code.
+
+// CHECK-LABEL: @empty_vec
+#[no_mangle]
+pub fn empty_vec() -> Vec<u8> {
+ // CHECK: store i{{32|64}}
+ // CHECK-NOT: load i8
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store ptr
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store i{{32|64}}
+ // CHECK-NEXT: ret void
+ vec![]
+}
+
+// CHECK-LABEL: @empty_vec_clone
+#[no_mangle]
+pub fn empty_vec_clone() -> Vec<u8> {
+ // CHECK: store i{{32|64}}
+ // CHECK-NOT: load i8
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store ptr
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store i{{32|64}}
+ // CHECK-NEXT: ret void
+ vec![].clone()
+}
--- /dev/null
+// compile-flags: -O -Zmutable-noalias=no
+
+#![crate_type = "lib"]
+
+// `-Zmutable-noalias=no` should disable noalias on mut refs...
+
+// CHECK-LABEL: @test_mut_ref(
+// CHECK-NOT: noalias
+// CHECK-SAME: %x
+#[no_mangle]
+pub fn test_mut_ref(x: &mut i32) -> &mut i32 {
+ x
+}
+
+// ...but not on shared refs
+
+// CHECK-LABEL: @test_ref(
+// CHECK-SAME: noalias
+// CHECK-SAME: %x
+#[no_mangle]
+pub fn test_ref(x: &i32) -> &i32 {
+ x
+}
member3: &'a Type13<'a>,
}
+// Helper type to allow `Type14<Bar>` to be a unique ID
+pub struct Bar;
+
+// repr(transparent) parameterized type
+#[repr(transparent)]
+pub struct Type14<T>(T);
+
pub fn foo0(_: ()) { }
// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]]
pub fn foo1(_: c_void, _: ()) { }
// CHECK: define{{.*}}foo145{{.*}}!type ![[TYPE145:[0-9]+]]
pub fn foo146(_: Type13, _: Type13, _: Type13) { }
// CHECK: define{{.*}}foo146{{.*}}!type ![[TYPE146:[0-9]+]]
+pub fn foo147(_: Type14<Bar>) { }
+// CHECK: define{{.*}}foo147{{.*}}!type ![[TYPE147:[0-9]+]]
+pub fn foo148(_: Type14<Bar>, _: Type14<Bar>) { }
+// CHECK: define{{.*}}foo148{{.*}}!type ![[TYPE148:[0-9]+]]
+pub fn foo149(_: Type14<Bar>, _: Type14<Bar>, _: Type14<Bar>) { }
+// CHECK: define{{.*}}foo149{{.*}}!type ![[TYPE149:[0-9]+]]
// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvvE"}
// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvvE"}
// CHECK: ![[TYPE141]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooE"}
// CHECK: ![[TYPE142]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_E"}
// CHECK: ![[TYPE143]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_S_E"}
-// CHECK: ![[TYPE144]] = !{i64 0, !"_ZTSFvu3refIu3refIvEEE"}
-// CHECK: ![[TYPE145]] = !{i64 0, !"_ZTSFvu3refIu3refIvEES0_E"}
-// CHECK: ![[TYPE146]] = !{i64 0, !"_ZTSFvu3refIu3refIvEES0_S0_E"}
+// CHECK: ![[TYPE144]] = !{i64 0, !"_ZTSFvu3refIvEE"}
+// CHECK: ![[TYPE145]] = !{i64 0, !"_ZTSFvu3refIvES_E"}
+// CHECK: ![[TYPE146]] = !{i64 0, !"_ZTSFvu3refIvES_S_E"}
+// CHECK: ![[TYPE147]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarE
+// CHECK: ![[TYPE148]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarS_E
+// CHECK: ![[TYPE149]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarS_S_E
pub fn scalar_layout(s: &(u64, ())) {
// CHECK: getelementptr i8, {{.+}}, [[USIZE]] 8
let x = &s.1;
- &x; // keep variable in an alloca
+ witness(&x); // keep variable in an alloca
}
// Check that we correctly generate a GEP for a ZST that is not included in ScalarPair layout
pub fn scalarpair_layout(s: &(u64, u32, ())) {
// CHECK: getelementptr i8, {{.+}}, [[USIZE]] 12
let x = &s.2;
- &x; // keep variable in an alloca
+ witness(&x); // keep variable in an alloca
}
#[repr(simd)]
pub fn vector_layout(s: &(U64x4, ())) {
// CHECK: getelementptr i8, {{.+}}, [[USIZE]] 32
let x = &s.1;
- &x; // keep variable in an alloca
+ witness(&x); // keep variable in an alloca
}
+
+#[inline(never)]
+fn witness(_: &impl Sized) {}
// compile-flags: -Zquery-dep-graph
// [rpass1]compile-flags: -Zincremental-ignore-spans
// [rpass2]compile-flags: -Zincremental-ignore-spans
-// [rpass3]compile-flags: -Zincremental-relative-spans
-// [rpass4]compile-flags: -Zincremental-relative-spans
#![feature(rustc_attrs)]
#![rustc_partition_reused(module = "change_symbol_export_status-mod1", cfg = "rpass2")]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
}
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, typeck")]
#[rustc_clean(cfg="cfail6")]
pub fn add_parameter() {
let x = 0u32;
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(linkage)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// This test makes sure that just changing a definition's location in the
// source file also changes its incr. comp. hash, if debuginfo is enabled.
-// revisions:rpass1 rpass2 rpass3 rpass4
+// revisions:rpass1 rpass2
// ignore-asmjs wasm2js does not support source maps yet
// compile-flags: -g -Z query-dep-graph
-// [rpass3]compile-flags: -Zincremental-relative-spans
-// [rpass4]compile-flags: -Zincremental-relative-spans
#![feature(rustc_attrs)]
#![rustc_partition_codegened(module = "spans_significant_w_debuginfo", cfg = "rpass2")]
-#![rustc_partition_codegened(module = "spans_significant_w_debuginfo", cfg = "rpass4")]
-#[cfg(any(rpass1, rpass3))]
+#[cfg(rpass1)]
pub fn main() {}
-#[cfg(any(rpass2, rpass4))]
-#[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir", cfg = "rpass2")]
-#[rustc_clean(cfg = "rpass4")]
+#[cfg(rpass2)]
+#[rustc_clean(cfg = "rpass2")]
pub fn main() {}
// This test makes sure that just changing a definition's location in the
// source file also changes its incr. comp. hash, if debuginfo is enabled.
-// revisions:rpass1 rpass2 rpass3 rpass4
-// [rpass3]compile-flags: -Zincremental-relative-spans
-// [rpass4]compile-flags: -Zincremental-relative-spans
+// revisions:rpass1 rpass2
// compile-flags: -C overflow-checks=on -Z query-dep-graph
#![feature(rustc_attrs)]
#![rustc_partition_codegened(module = "spans_significant_w_panic", cfg = "rpass2")]
-#![rustc_partition_codegened(module = "spans_significant_w_panic", cfg = "rpass4")]
-#[cfg(any(rpass1, rpass3))]
+#[cfg(rpass1)]
pub fn main() {
if std::hint::black_box(false) {
panic!()
}
}
-#[cfg(any(rpass2, rpass4))]
-#[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir", cfg = "rpass2")]
-#[rustc_clean(cfg = "rpass4")]
+#[cfg(rpass2)]
+#[rustc_clean(cfg = "rpass2")]
pub fn main() {
if std::hint::black_box(false) {
panic!()
-// revisions: cfail1 cfail2 cfail3 cfail4
+// revisions: cfail1 cfail2
// compile-flags: -Z query-dep-graph
-// [cfail3]compile-flags: -Zincremental-relative-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
// build-pass (FIXME(62277): could be check-pass?)
#![allow(warnings)]
// needed even for callers of `x`.
pub mod x {
- #[cfg(any(cfail1, cfail3))]
+ #[cfg(cfail1)]
pub fn x() {
println!("{}", "1");
}
- #[cfg(any(cfail2, cfail4))]
- #[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir,promoted_mir", cfg = "cfail2")]
- #[rustc_clean(except = "hir_owner_nodes,promoted_mir", cfg = "cfail4")]
+ #[cfg(cfail2)]
+ #[rustc_clean(except = "hir_owner_nodes,promoted_mir", cfg = "cfail2")]
pub fn x() {
println!("{}", "2");
}
use x;
#[rustc_clean(cfg = "cfail2")]
- #[rustc_clean(cfg = "cfail4")]
pub fn y() {
x::x();
}
use y;
#[rustc_clean(cfg = "cfail2")]
- #[rustc_clean(cfg = "cfail4")]
pub fn z() {
y::y();
}
// ends up with any spans in its LLVM bitecode, so LLVM is able to skip
// re-building any modules which import 'inlined_fn'
-// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
+// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph -O
// build-pass (FIXME(62277): could be check-pass?)
cfg = "cfail3",
kind = "post-lto"
)]
-#![rustc_expected_cgu_reuse(
- module = "cgu_keeps_identical_fn-foo",
- cfg = "cfail5",
- kind = "post-lto"
-)]
-#![rustc_expected_cgu_reuse(
- module = "cgu_keeps_identical_fn-foo",
- cfg = "cfail6",
- kind = "post-lto"
-)]
#![rustc_expected_cgu_reuse(
module = "cgu_keeps_identical_fn-bar",
cfg = "cfail2",
cfg = "cfail3",
kind = "post-lto"
)]
-#![rustc_expected_cgu_reuse(
- module = "cgu_keeps_identical_fn-bar",
- cfg = "cfail5",
- kind = "post-lto"
-)]
-#![rustc_expected_cgu_reuse(
- module = "cgu_keeps_identical_fn-bar",
- cfg = "cfail6",
- kind = "post-lto"
-)]
mod foo {
StorageLive(_2); // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8
_2 = const {alloc1: &&[(Option<i32>, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8
// mir::Constant
- // + span: $DIR/const_allocation.rs:8:5: 8:8
+ // + span: $DIR/const_allocation.rs:9:5: 9:8
// + literal: Const { ty: &&[(Option<i32>, &[&str])], val: Value(Scalar(alloc1)) }
_1 = (*_2); // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8
StorageDead(_2); // scope 0 at $DIR/const_allocation.rs:+1:8: +1:9
StorageDead(_1); // scope 0 at $DIR/const_allocation.rs:+1:8: +1:9
- nop; // scope 0 at $DIR/const_allocation.rs:+0:11: +2:2
+ _0 = const (); // scope 0 at $DIR/const_allocation.rs:+0:11: +2:2
return; // scope 0 at $DIR/const_allocation.rs:+2:2: +2:2
}
}
StorageLive(_2); // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8
_2 = const {alloc1: &&[(Option<i32>, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8
// mir::Constant
- // + span: $DIR/const_allocation.rs:8:5: 8:8
+ // + span: $DIR/const_allocation.rs:9:5: 9:8
// + literal: Const { ty: &&[(Option<i32>, &[&str])], val: Value(Scalar(alloc1)) }
_1 = (*_2); // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8
StorageDead(_2); // scope 0 at $DIR/const_allocation.rs:+1:8: +1:9
StorageDead(_1); // scope 0 at $DIR/const_allocation.rs:+1:8: +1:9
- nop; // scope 0 at $DIR/const_allocation.rs:+0:11: +2:2
+ _0 = const (); // scope 0 at $DIR/const_allocation.rs:+0:11: +2:2
return; // scope 0 at $DIR/const_allocation.rs:+2:2: +2:2
}
}
+// unit-test: ConstProp
// ignore-endian-big
// EMIT_MIR_FOR_EACH_BIT_WIDTH
static FOO: &[(Option<i32>, &[&str])] =
StorageLive(_2); // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8
_2 = const {alloc1: &&[(Option<i32>, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8
// mir::Constant
- // + span: $DIR/const_allocation2.rs:5:5: 5:8
+ // + span: $DIR/const_allocation2.rs:6:5: 6:8
// + literal: Const { ty: &&[(Option<i32>, &[&u8])], val: Value(Scalar(alloc1)) }
_1 = (*_2); // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8
StorageDead(_2); // scope 0 at $DIR/const_allocation2.rs:+1:8: +1:9
StorageDead(_1); // scope 0 at $DIR/const_allocation2.rs:+1:8: +1:9
- nop; // scope 0 at $DIR/const_allocation2.rs:+0:11: +2:2
+ _0 = const (); // scope 0 at $DIR/const_allocation2.rs:+0:11: +2:2
return; // scope 0 at $DIR/const_allocation2.rs:+2:2: +2:2
}
}
StorageLive(_2); // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8
_2 = const {alloc1: &&[(Option<i32>, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8
// mir::Constant
- // + span: $DIR/const_allocation2.rs:5:5: 5:8
+ // + span: $DIR/const_allocation2.rs:6:5: 6:8
// + literal: Const { ty: &&[(Option<i32>, &[&u8])], val: Value(Scalar(alloc1)) }
_1 = (*_2); // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8
StorageDead(_2); // scope 0 at $DIR/const_allocation2.rs:+1:8: +1:9
StorageDead(_1); // scope 0 at $DIR/const_allocation2.rs:+1:8: +1:9
- nop; // scope 0 at $DIR/const_allocation2.rs:+0:11: +2:2
+ _0 = const (); // scope 0 at $DIR/const_allocation2.rs:+0:11: +2:2
return; // scope 0 at $DIR/const_allocation2.rs:+2:2: +2:2
}
}
+// unit-test: ConstProp
// ignore-endian-big
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR const_allocation2.main.ConstProp.after.mir
StorageLive(_2); // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8
_2 = const {alloc1: &&Packed}; // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8
// mir::Constant
- // + span: $DIR/const_allocation3.rs:5:5: 5:8
+ // + span: $DIR/const_allocation3.rs:6:5: 6:8
// + literal: Const { ty: &&Packed, val: Value(Scalar(alloc1)) }
_1 = (*_2); // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8
StorageDead(_2); // scope 0 at $DIR/const_allocation3.rs:+1:8: +1:9
StorageDead(_1); // scope 0 at $DIR/const_allocation3.rs:+1:8: +1:9
- nop; // scope 0 at $DIR/const_allocation3.rs:+0:11: +2:2
+ _0 = const (); // scope 0 at $DIR/const_allocation3.rs:+0:11: +2:2
return; // scope 0 at $DIR/const_allocation3.rs:+2:2: +2:2
}
}
StorageLive(_2); // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8
_2 = const {alloc1: &&Packed}; // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8
// mir::Constant
- // + span: $DIR/const_allocation3.rs:5:5: 5:8
+ // + span: $DIR/const_allocation3.rs:6:5: 6:8
// + literal: Const { ty: &&Packed, val: Value(Scalar(alloc1)) }
_1 = (*_2); // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8
StorageDead(_2); // scope 0 at $DIR/const_allocation3.rs:+1:8: +1:9
StorageDead(_1); // scope 0 at $DIR/const_allocation3.rs:+1:8: +1:9
- nop; // scope 0 at $DIR/const_allocation3.rs:+0:11: +2:2
+ _0 = const (); // scope 0 at $DIR/const_allocation3.rs:+0:11: +2:2
return; // scope 0 at $DIR/const_allocation3.rs:+2:2: +2:2
}
}
+// unit-test: ConstProp
// ignore-endian-big
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR const_allocation3.main.ConstProp.after.mir
let mut _6: u8; // in scope 0 at $DIR/const_debuginfo.rs:+4:15: +4:16
let mut _7: u8; // in scope 0 at $DIR/const_debuginfo.rs:+4:19: +4:20
let mut _8: u8; // in scope 0 at $DIR/const_debuginfo.rs:+4:23: +4:24
- let mut _14: u32; // in scope 0 at $DIR/const_debuginfo.rs:+13:13: +13:16
- let mut _15: u32; // in scope 0 at $DIR/const_debuginfo.rs:+13:19: +13:22
+ let mut _12: u32; // in scope 0 at $DIR/const_debuginfo.rs:+13:13: +13:16
+ let mut _13: u32; // in scope 0 at $DIR/const_debuginfo.rs:+13:19: +13:22
scope 1 {
- debug x => _1; // in scope 1 at $DIR/const_debuginfo.rs:+1:9: +1:10
+ debug x => const 1_u8; // in scope 1 at $DIR/const_debuginfo.rs:+1:9: +1:10
scope 5 {
- debug s => _9; // in scope 5 at $DIR/const_debuginfo.rs:+6:9: +6:10
+ debug s => const "hello, world!"; // in scope 5 at $DIR/const_debuginfo.rs:+6:9: +6:10
- let _10: (bool, bool, u32); // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
- let _16: bool; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
- let _17: bool; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
- let _18: u32; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
+ let _14: bool; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
+ let _15: bool; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
+ let _16: u32; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
scope 6 {
- debug f => (bool, bool, u32){ .0 => _16, .1 => _17, .2 => _18, }; // in scope 6 at $DIR/const_debuginfo.rs:+8:9: +8:10
- let _11: std::option::Option<u16>; // in scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10
+ debug f => (bool, bool, u32){ .0 => _14, .1 => _15, .2 => _16, }; // in scope 6 at $DIR/const_debuginfo.rs:+8:9: +8:10
+ let _10: std::option::Option<u16>; // in scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10
scope 7 {
- debug o => _11; // in scope 7 at $DIR/const_debuginfo.rs:+10:9: +10:10
- let _12: Point; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
- let _19: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
- let _20: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
+ debug o => _10; // in scope 7 at $DIR/const_debuginfo.rs:+10:9: +10:10
+ let _17: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
+ let _18: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
scope 8 {
- debug p => Point{ .0 => _19, .1 => _20, }; // in scope 8 at $DIR/const_debuginfo.rs:+12:9: +12:10
- let _13: u32; // in scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10
+ debug p => Point{ .0 => _17, .1 => _18, }; // in scope 8 at $DIR/const_debuginfo.rs:+12:9: +12:10
+ let _11: u32; // in scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10
scope 9 {
-- debug a => _13; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10
+- debug a => _11; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10
+ debug a => const 64_u32; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10
}
}
// mir::Constant
// + span: $DIR/const_debuginfo.rs:14:13: 14:28
// + literal: Const { ty: &str, val: Value(Slice(..)) }
+ StorageLive(_14); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
+ StorageLive(_15); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
StorageLive(_16); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
- StorageLive(_17); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
- StorageLive(_18); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
+ Deinit(_14); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
+ Deinit(_15); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
Deinit(_16); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
- Deinit(_17); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
- Deinit(_18); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
- _16 = const true; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
- _17 = const false; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
- _18 = const 123_u32; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
- StorageLive(_11); // scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10
- Deinit(_11); // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
- ((_11 as Some).0: u16) = const 99_u16; // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
- discriminant(_11) = 1; // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
- StorageLive(_19); // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
- StorageLive(_20); // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
- Deinit(_19); // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
- Deinit(_20); // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
- _19 = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
- _20 = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
- StorageLive(_13); // scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10
- StorageLive(_14); // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16
- _14 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16
- StorageLive(_15); // scope 8 at $DIR/const_debuginfo.rs:+13:19: +13:22
- _15 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:19: +13:22
- _13 = const 64_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:22
- StorageDead(_15); // scope 8 at $DIR/const_debuginfo.rs:+13:21: +13:22
- StorageDead(_14); // scope 8 at $DIR/const_debuginfo.rs:+13:21: +13:22
- nop; // scope 0 at $DIR/const_debuginfo.rs:+0:11: +14:2
- StorageDead(_13); // scope 8 at $DIR/const_debuginfo.rs:+14:1: +14:2
- StorageDead(_19); // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2
- StorageDead(_20); // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2
- StorageDead(_11); // scope 6 at $DIR/const_debuginfo.rs:+14:1: +14:2
+ _14 = const true; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
+ _15 = const false; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
+ _16 = const 123_u32; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
+ StorageLive(_10); // scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10
+ Deinit(_10); // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
+ ((_10 as Some).0: u16) = const 99_u16; // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
+ discriminant(_10) = 1; // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
+ StorageLive(_17); // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
+ StorageLive(_18); // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
+ Deinit(_17); // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
+ Deinit(_18); // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
+ _17 = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
+ _18 = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
+ StorageLive(_11); // scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10
+ StorageLive(_12); // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16
+ _12 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16
+ StorageLive(_13); // scope 8 at $DIR/const_debuginfo.rs:+13:19: +13:22
+ _13 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:19: +13:22
+ _11 = const 64_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:22
+ StorageDead(_13); // scope 8 at $DIR/const_debuginfo.rs:+13:21: +13:22
+ StorageDead(_12); // scope 8 at $DIR/const_debuginfo.rs:+13:21: +13:22
+ StorageDead(_11); // scope 8 at $DIR/const_debuginfo.rs:+14:1: +14:2
+ StorageDead(_17); // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2
+ StorageDead(_18); // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2
+ StorageDead(_10); // scope 6 at $DIR/const_debuginfo.rs:+14:1: +14:2
+ StorageDead(_14); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
+ StorageDead(_15); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_16); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
- StorageDead(_17); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
- StorageDead(_18); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_9); // scope 4 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_4); // scope 3 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_3); // scope 2 at $DIR/const_debuginfo.rs:+14:1: +14:2
- _2 = Rem(const 1_i32, move _3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+ _2 = Rem(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
StorageDead(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
- nop; // scope 0 at $DIR/bad_op_mod_by_zero.rs:+0:11: +3:2
StorageDead(_2); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2
StorageDead(_1); // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2
return; // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:2: +3:2
let _1: *const [i32]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
let mut _2: *const [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
let _3: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
- let _4: [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:26: +1:35
- let _6: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
- let mut _7: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
- let mut _8: bool; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
- let mut _9: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+ let _5: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+ let mut _6: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+ let mut _7: bool; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+ let mut _8: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
scope 1 {
debug a => _1; // in scope 1 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
scope 2 {
- let _5: i32; // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+ let _4: i32; // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
scope 3 {
- debug _b => _5; // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+ debug _b => _4; // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
}
}
}
StorageLive(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
StorageLive(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
- _9 = const _; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+ _8 = const _; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
// mir::Constant
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
// + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
- _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+ _3 = _8; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
_2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
StorageDead(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35
StorageDead(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36
- StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
- StorageLive(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
- _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
- _7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-- _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+ _8 = Lt(const 3_usize, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+ StorageLive(_4); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+ StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+ _5 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+ _6 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+- _7 = Lt(_5, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++ _7 = Lt(const 3_usize, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++ assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
}
bb1: {
- _5 = (*_1)[_6]; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
- StorageDead(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
- nop; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+2:5: +4:6
- StorageDead(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
+ _4 = (*_1)[_5]; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+ StorageDead(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
+ StorageDead(_4); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
StorageDead(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:1: +5:2
return; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:2: +5:2
}
let _1: *const [i32]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
let mut _2: *const [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
let _3: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
- let _4: [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:26: +1:35
- let _6: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
- let mut _7: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
- let mut _8: bool; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
- let mut _9: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+ let _5: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+ let mut _6: usize; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+ let mut _7: bool; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+ let mut _8: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
scope 1 {
debug a => _1; // in scope 1 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
scope 2 {
- let _5: i32; // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+ let _4: i32; // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
scope 3 {
- debug _b => _5; // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+ debug _b => _4; // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
}
}
}
StorageLive(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
StorageLive(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
- _9 = const _; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+ _8 = const _; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
// mir::Constant
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
// + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
- _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+ _3 = _8; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
_2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
StorageDead(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35
StorageDead(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36
- StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
- StorageLive(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
- _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
- _7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-- _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+ _8 = Lt(const 3_usize, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+ StorageLive(_4); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+ StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+ _5 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+ _6 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+- _7 = Lt(_5, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++ _7 = Lt(const 3_usize, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++ assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
}
bb1: {
- _5 = (*_1)[_6]; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
- StorageDead(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
- nop; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+2:5: +4:6
- StorageDead(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
+ _4 = (*_1)[_5]; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+ StorageDead(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
+ StorageDead(_4); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
StorageDead(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:1: +5:2
return; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:2: +5:2
}
}
bb2: {
- nop; // scope 0 at $DIR/control_flow_simplification.rs:+3:6: +3:6
StorageDead(_1); // scope 0 at $DIR/control_flow_simplification.rs:+3:5: +3:6
return; // scope 0 at $DIR/control_flow_simplification.rs:+4:2: +4:2
}
let mut _2: main::InvalidChar; // in scope 0 at $DIR/invalid_constant.rs:+6:34: +6:63
let mut _4: E; // in scope 0 at $DIR/invalid_constant.rs:+13:25: +13:59
let mut _5: main::InvalidTag; // in scope 0 at $DIR/invalid_constant.rs:+13:34: +13:55
- let mut _7: Empty; // in scope 0 at $DIR/invalid_constant.rs:+20:35: +20:73
- let mut _8: main::NoVariants; // in scope 0 at $DIR/invalid_constant.rs:+20:44: +20:65
scope 1 {
debug _invalid_char => _1; // in scope 1 at $DIR/invalid_constant.rs:+6:9: +6:22
let _3: [E; 1]; // in scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
let _6: [Empty; 1]; // in scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
scope 5 {
debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
- let _9: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
+ let _7: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
scope 7 {
- debug _non_utf8_str => _9; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
+ debug _non_utf8_str => _7; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
}
}
scope 6 {
StorageDead(_4); // scope 1 at $DIR/invalid_constant.rs:+13:59: +13:60
StorageDead(_5); // scope 1 at $DIR/invalid_constant.rs:+13:60: +13:61
StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
- StorageLive(_7); // scope 3 at $DIR/invalid_constant.rs:+20:35: +20:73
- StorageLive(_8); // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
- Deinit(_8); // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
- (_8.0: u32) = const 0_u32; // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
- nop; // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:71
- nop; // scope 3 at $DIR/invalid_constant.rs:+20:34: +20:74
- StorageDead(_7); // scope 3 at $DIR/invalid_constant.rs:+20:73: +20:74
- StorageDead(_8); // scope 3 at $DIR/invalid_constant.rs:+20:74: +20:75
- StorageLive(_9); // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
- nop; // scope 0 at $DIR/invalid_constant.rs:+0:11: +27:2
- StorageDead(_9); // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
+ StorageLive(_7); // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
+ StorageDead(_7); // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
StorageDead(_6); // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2
StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:+27:1: +27:2
StorageDead(_1); // scope 0 at $DIR/invalid_constant.rs:+27:1: +27:2
let mut _0: (); // return place in scope 0 at $DIR/issue_66971.rs:+0:11: +0:11
let _1: (); // in scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
let mut _2: ((), u8, u8); // in scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
- let mut _3: (); // in scope 0 at $DIR/issue_66971.rs:+1:13: +1:15
bb0: {
StorageLive(_1); // scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
StorageLive(_2); // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
- StorageLive(_3); // scope 0 at $DIR/issue_66971.rs:+1:13: +1:15
- nop; // scope 0 at $DIR/issue_66971.rs:+1:13: +1:15
Deinit(_2); // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
- nop; // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
(_2.1: u8) = const 0_u8; // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
(_2.2: u8) = const 0_u8; // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
- StorageDead(_3); // scope 0 at $DIR/issue_66971.rs:+1:21: +1:22
_1 = encode(move _2) -> bb1; // scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
// mir::Constant
// + span: $DIR/issue_66971.rs:17:5: 17:11
bb1: {
StorageDead(_2); // scope 0 at $DIR/issue_66971.rs:+1:22: +1:23
StorageDead(_1); // scope 0 at $DIR/issue_66971.rs:+1:23: +1:24
- nop; // scope 0 at $DIR/issue_66971.rs:+0:11: +2:2
return; // scope 0 at $DIR/issue_66971.rs:+2:2: +2:2
}
}
bb1: {
StorageDead(_2); // scope 0 at $DIR/issue_67019.rs:+1:19: +1:20
StorageDead(_1); // scope 0 at $DIR/issue_67019.rs:+1:20: +1:21
- nop; // scope 0 at $DIR/issue_67019.rs:+0:11: +2:2
return; // scope 0 at $DIR/issue_67019.rs:+2:2: +2:2
}
}
_1 = _2[_3]; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
StorageDead(_3); // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
StorageDead(_2); // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
- nop; // scope 0 at $DIR/large_array_index.rs:+0:11: +3:2
StorageDead(_1); // scope 0 at $DIR/large_array_index.rs:+3:1: +3:2
return; // scope 0 at $DIR/large_array_index.rs:+3:2: +3:2
}
_1 = _2[_3]; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
StorageDead(_3); // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
StorageDead(_2); // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
- nop; // scope 0 at $DIR/large_array_index.rs:+0:11: +3:2
StorageDead(_1); // scope 0 at $DIR/large_array_index.rs:+3:1: +3:2
return; // scope 0 at $DIR/large_array_index.rs:+3:2: +3:2
}
StorageLive(_2); // scope 1 at $DIR/mutable_variable.rs:+3:9: +3:10
- _2 = _1; // scope 1 at $DIR/mutable_variable.rs:+3:13: +3:14
+ _2 = const 99_i32; // scope 1 at $DIR/mutable_variable.rs:+3:13: +3:14
- nop; // scope 0 at $DIR/mutable_variable.rs:+0:11: +4:2
StorageDead(_2); // scope 1 at $DIR/mutable_variable.rs:+4:1: +4:2
StorageDead(_1); // scope 0 at $DIR/mutable_variable.rs:+4:1: +4:2
return; // scope 0 at $DIR/mutable_variable.rs:+4:2: +4:2
StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10
- _2 = _1; // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14
+ _2 = const (42_i32, 99_i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14
- nop; // scope 0 at $DIR/mutable_variable_aggregate.rs:+0:11: +4:2
StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:+4:1: +4:2
StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate.rs:+4:1: +4:2
return; // scope 0 at $DIR/mutable_variable_aggregate.rs:+4:2: +4:2
((*_2).1: i32) = const 99_i32; // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+3:5: +3:13
StorageLive(_3); // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10
_3 = _1; // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:13: +4:14
- nop; // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+0:11: +5:2
StorageDead(_3); // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:1: +5:2
StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:1: +5:2
StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:1: +5:2
StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+4:9: +4:10
- _2 = (_1.1: i32); // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+4:13: +4:16
+ _2 = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+4:13: +4:16
- nop; // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+0:11: +5:2
StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+5:1: +5:2
StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+5:1: +5:2
return; // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+5:2: +5:2
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_no_prop.rs:+0:11: +0:11
let mut _1: u32; // in scope 0 at $DIR/mutable_variable_no_prop.rs:+1:9: +1:14
- let _2: (); // in scope 0 at $DIR/mutable_variable_no_prop.rs:+2:5: +4:6
- let mut _3: u32; // in scope 0 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
- let mut _4: *mut u32; // in scope 0 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
+ let mut _2: u32; // in scope 0 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
+ let mut _3: *mut u32; // in scope 0 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
scope 1 {
debug x => _1; // in scope 1 at $DIR/mutable_variable_no_prop.rs:+1:9: +1:14
- let _5: u32; // in scope 1 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10
+ let _4: u32; // in scope 1 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10
scope 2 {
}
scope 3 {
- debug y => _5; // in scope 3 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10
+ debug y => _4; // in scope 3 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10
}
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/mutable_variable_no_prop.rs:+1:9: +1:14
_1 = const 42_u32; // scope 0 at $DIR/mutable_variable_no_prop.rs:+1:17: +1:19
- StorageLive(_2); // scope 1 at $DIR/mutable_variable_no_prop.rs:+2:5: +4:6
+ StorageLive(_2); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
StorageLive(_3); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
- StorageLive(_4); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
- _4 = const {alloc1: *mut u32}; // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
+ _3 = const {alloc1: *mut u32}; // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
// mir::Constant
// + span: $DIR/mutable_variable_no_prop.rs:10:13: 10:19
// + literal: Const { ty: *mut u32, val: Value(Scalar(alloc1)) }
- _3 = (*_4); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
- _1 = move _3; // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:9: +3:19
- StorageDead(_3); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:18: +3:19
- StorageDead(_4); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:19: +3:20
- nop; // scope 2 at $DIR/mutable_variable_no_prop.rs:+2:5: +4:6
- StorageDead(_2); // scope 1 at $DIR/mutable_variable_no_prop.rs:+4:5: +4:6
- StorageLive(_5); // scope 1 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10
- _5 = _1; // scope 1 at $DIR/mutable_variable_no_prop.rs:+5:13: +5:14
- nop; // scope 0 at $DIR/mutable_variable_no_prop.rs:+0:11: +6:2
- StorageDead(_5); // scope 1 at $DIR/mutable_variable_no_prop.rs:+6:1: +6:2
+ _2 = (*_3); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
+ _1 = move _2; // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:9: +3:19
+ StorageDead(_2); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:18: +3:19
+ StorageDead(_3); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:19: +3:20
+ StorageLive(_4); // scope 1 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10
+ _4 = _1; // scope 1 at $DIR/mutable_variable_no_prop.rs:+5:13: +5:14
+ StorageDead(_4); // scope 1 at $DIR/mutable_variable_no_prop.rs:+6:1: +6:2
StorageDead(_1); // scope 0 at $DIR/mutable_variable_no_prop.rs:+6:1: +6:2
return; // scope 0 at $DIR/mutable_variable_no_prop.rs:+6:2: +6:2
}
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+0:11: +0:11
let _1: i32; // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10
- let mut _3: i32; // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
+ let mut _2: i32; // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
scope 1 {
debug a => _1; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10
- let mut _2: (i32, i32); // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
+ let mut _5: i32; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
let mut _6: i32; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
- let mut _7: i32; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
scope 2 {
- debug x => (i32, i32){ .0 => _6, .1 => _7, }; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
- let _4: i32; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
+ debug x => (i32, i32){ .0 => _5, .1 => _6, }; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
+ let _3: i32; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
scope 3 {
- debug y => _4; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
- let _5: i32; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
+ debug y => _3; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
+ let _4: i32; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
scope 4 {
- debug z => _5; // in scope 4 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
+ debug z => _4; // in scope 4 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
}
}
}
}
bb1: {
+ StorageLive(_5); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
StorageLive(_6); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
- StorageLive(_7); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
+ Deinit(_5); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
Deinit(_6); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
- Deinit(_7); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
- _6 = const 1_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
- _7 = const 2_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
- StorageLive(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
- _3 = _1; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
- _7 = move _3; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:5: +3:12
- StorageDead(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
- StorageLive(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
- _4 = _7; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16
- StorageLive(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
-- _5 = _6; // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
-+ _5 = const 1_i32; // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
- nop; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+0:11: +6:2
- StorageDead(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
- StorageDead(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
+ _5 = const 1_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
+ _6 = const 2_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
+ StorageLive(_2); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
+ _2 = _1; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
+ _6 = move _2; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:5: +3:12
+ StorageDead(_2); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
+ StorageLive(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
+ _3 = _6; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16
+ StorageLive(_4); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
+- _4 = _5; // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
++ _4 = const 1_i32; // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
+ StorageDead(_4); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
+ StorageDead(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
+ StorageDead(_5); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
StorageDead(_6); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
- StorageDead(_7); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
StorageDead(_1); // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
return; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:2: +6:2
}
let _5: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:32: +2:33
let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
- let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- let mut _10: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- let mut _11: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ let mut _9: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
scope 1 {
debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
- StorageLive(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- StorageLive(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- Deinit(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- Deinit(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- _10 = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- _11 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
-- _8 = _11; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
+ StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ Deinit(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ _9 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+- _8 = _9; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
+ _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
- StorageDead(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
- StorageDead(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
- nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2
+ StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
let _5: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:32: +2:33
let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
- let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- let mut _10: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- let mut _11: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ let mut _9: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
scope 1 {
debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
- StorageLive(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- StorageLive(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- Deinit(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- Deinit(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- _10 = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
- _11 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
-- _8 = _11; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
+ StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ Deinit(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+ _9 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+- _8 = _9; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
+ _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
- StorageDead(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
- StorageDead(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
- nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2
+ StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
--- /dev/null
+// MIR for `main` after SimplifyLocals-final
+
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11
+ let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
+ scope 1 {
+ debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
+ let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
+ scope 2 {
+ debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
+ let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
+ scope 3 {
+ debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
+ StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
+ StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
+ StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
+ StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
+ StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
+ return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2
+ }
+}
--- /dev/null
+// MIR for `main` after SimplifyLocals-final
+
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11
+ let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
+ scope 1 {
+ debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
+ let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
+ scope 2 {
+ debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
+ let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
+ scope 3 {
+ debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
+ StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
+ StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
+ StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
+ StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
+ StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
+ return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2
+ }
+}
+++ /dev/null
-// MIR for `main` after SimplifyLocals
-
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11
- let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
- scope 1 {
- debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
- let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
- scope 2 {
- debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
- let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
- scope 3 {
- debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
- }
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
- StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
- StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
- StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
- StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
- StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
- return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2
- }
-}
+++ /dev/null
-// MIR for `main` after SimplifyLocals
-
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11
- let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
- scope 1 {
- debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
- let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
- scope 2 {
- debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
- let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
- scope 3 {
- debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
- }
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
- StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
- StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
- StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
- StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
- StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
- return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2
- }
-}
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR optimizes_into_variable.main.ScalarReplacementOfAggregates.diff
// EMIT_MIR optimizes_into_variable.main.ConstProp.diff
-// EMIT_MIR optimizes_into_variable.main.SimplifyLocals.after.mir
+// EMIT_MIR optimizes_into_variable.main.SimplifyLocals-final.after.mir
// EMIT_MIR optimizes_into_variable.main.PreCodegen.after.mir
fn main() {
let x = 2 + 2;
StorageDead(_2); // scope 0 at $DIR/read_immutable_static.rs:+1:21: +1:22
StorageDead(_5); // scope 0 at $DIR/read_immutable_static.rs:+1:22: +1:23
StorageDead(_3); // scope 0 at $DIR/read_immutable_static.rs:+1:22: +1:23
- nop; // scope 0 at $DIR/read_immutable_static.rs:+0:11: +2:2
StorageDead(_1); // scope 0 at $DIR/read_immutable_static.rs:+2:1: +2:2
return; // scope 0 at $DIR/read_immutable_static.rs:+2:2: +2:2
}
StorageLive(_2); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
_4 = const _; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
// mir::Constant
- // + span: $DIR/ref_deref.rs:5:6: 5:10
+ // + span: $DIR/ref_deref.rs:6:6: 6:10
// + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
_2 = _4; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
- _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
- _2 = &_3; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
+ _4 = const _; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
+ // mir::Constant
-+ // + span: $DIR/ref_deref.rs:5:6: 5:10
++ // + span: $DIR/ref_deref.rs:6:6: 6:10
+ // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
+ _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
_1 = (*_2); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
+// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
// EMIT_MIR ref_deref.main.PromoteTemps.diff
// EMIT_MIR ref_deref.main.ConstProp.diff
-// unit-test
+// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
// EMIT_MIR ref_deref_project.main.PromoteTemps.diff
// EMIT_MIR ref_deref_project.main.ConstProp.diff
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/reify_fn_ptr.rs:+0:11: +0:11
- let mut _1: *const fn(); // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41
- let mut _2: usize; // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
- let mut _3: fn(); // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
+ let mut _1: usize; // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
+ let mut _2: fn(); // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
scope 1 {
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41
- StorageLive(_2); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
- StorageLive(_3); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
- _3 = main as fn() (Pointer(ReifyFnPointer)); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
+ StorageLive(_1); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
+ StorageLive(_2); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
+ _2 = main as fn() (Pointer(ReifyFnPointer)); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
// mir::Constant
// + span: $DIR/reify_fn_ptr.rs:4:13: 4:17
// + literal: Const { ty: fn() {main}, val: Value(<ZST>) }
- _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
- StorageDead(_3); // scope 0 at $DIR/reify_fn_ptr.rs:+1:25: +1:26
- _1 = move _2 as *const fn() (PointerFromExposedAddress); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41
- StorageDead(_2); // scope 0 at $DIR/reify_fn_ptr.rs:+1:40: +1:41
- StorageDead(_1); // scope 0 at $DIR/reify_fn_ptr.rs:+1:41: +1:42
- nop; // scope 0 at $DIR/reify_fn_ptr.rs:+0:11: +2:2
+ _1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
+ StorageDead(_2); // scope 0 at $DIR/reify_fn_ptr.rs:+1:25: +1:26
+ StorageDead(_1); // scope 0 at $DIR/reify_fn_ptr.rs:+1:40: +1:41
return; // scope 0 at $DIR/reify_fn_ptr.rs:+2:2: +2:2
}
}
StorageDead(_2); // scope 0 at $DIR/repeat.rs:+1:31: +1:32
StorageDead(_4); // scope 0 at $DIR/repeat.rs:+1:32: +1:33
StorageDead(_3); // scope 0 at $DIR/repeat.rs:+1:32: +1:33
- nop; // scope 0 at $DIR/repeat.rs:+0:11: +2:2
StorageDead(_1); // scope 0 at $DIR/repeat.rs:+2:1: +2:2
return; // scope 0 at $DIR/repeat.rs:+2:2: +2:2
}
StorageDead(_2); // scope 0 at $DIR/repeat.rs:+1:31: +1:32
StorageDead(_4); // scope 0 at $DIR/repeat.rs:+1:32: +1:33
StorageDead(_3); // scope 0 at $DIR/repeat.rs:+1:32: +1:33
- nop; // scope 0 at $DIR/repeat.rs:+0:11: +2:2
StorageDead(_1); // scope 0 at $DIR/repeat.rs:+2:1: +2:2
return; // scope 0 at $DIR/repeat.rs:+2:2: +2:2
}
bb1: {
StorageDead(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:14: +2:15
StorageDead(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:15: +2:16
- nop; // scope 0 at $DIR/scalar_literal_propagation.rs:+0:11: +3:2
StorageDead(_1); // scope 0 at $DIR/scalar_literal_propagation.rs:+3:1: +3:2
return; // scope 0 at $DIR/scalar_literal_propagation.rs:+3:2: +3:2
}
StorageLive(_4); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
_9 = const _; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
// mir::Constant
- // + span: $DIR/slice_len.rs:5:6: 5:19
+ // + span: $DIR/slice_len.rs:6:6: 6:19
// + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
_4 = _9; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
_3 = _4; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
StorageLive(_4); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
_9 = const _; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
// mir::Constant
- // + span: $DIR/slice_len.rs:5:6: 5:19
+ // + span: $DIR/slice_len.rs:6:6: 6:19
// + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
_4 = _9; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
_3 = _4; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
+// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR slice_len.main.ConstProp.diff
bb1: {
StorageDead(_3); // scope 1 at $DIR/tuple_literal_propagation.rs:+3:14: +3:15
StorageDead(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:+3:15: +3:16
- nop; // scope 0 at $DIR/tuple_literal_propagation.rs:+0:11: +4:2
StorageDead(_1); // scope 0 at $DIR/tuple_literal_propagation.rs:+4:1: +4:2
return; // scope 0 at $DIR/tuple_literal_propagation.rs:+4:2: +4:2
}
fn bar() -> () {
let mut _0: (); // return place in scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +0:10
let mut _1: (i32,); // in scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
- let _2: (); // in scope 0 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
- let mut _3: *mut i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
- let mut _5: i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
+ let mut _2: *mut i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+ let mut _4: i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
scope 1 {
debug v => _1; // in scope 1 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
- let _4: bool; // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+ let _3: bool; // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
scope 2 {
}
scope 3 {
- debug y => _4; // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+ debug y => _3; // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
}
}
StorageLive(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
Deinit(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
(_1.0: i32) = const 1_i32; // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
- StorageLive(_2); // scope 1 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
- StorageLive(_3); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
- _3 = &raw mut (_1.0: i32); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
- (*_3) = const 5_i32; // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26
- StorageDead(_3); // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27
- nop; // scope 2 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
- StorageDead(_2); // scope 1 at $DIR/const_prop_miscompile.rs:+4:5: +4:6
- StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
- StorageLive(_5); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
- _5 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18
- _4 = Eq(move _5, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25
- StorageDead(_5); // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25
- nop; // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +6:2
- StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
+ StorageLive(_2); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+ _2 = &raw mut (_1.0: i32); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+ (*_2) = const 5_i32; // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26
+ StorageDead(_2); // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27
+ StorageLive(_3); // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+ StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
+ _4 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18
+ _3 = Eq(move _4, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25
+ StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25
+ StorageDead(_3); // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
return; // scope 0 at $DIR/const_prop_miscompile.rs:+6:2: +6:2
}
_4 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+3:15: +3:18
_3 = Eq(move _4, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:+3:13: +3:25
StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+3:24: +3:25
- nop; // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +4:2
StorageDead(_3); // scope 1 at $DIR/const_prop_miscompile.rs:+4:1: +4:2
StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+4:1: +4:2
return; // scope 0 at $DIR/const_prop_miscompile.rs:+4:2: +4:2
let mut _0: (); // return place in scope 0 at $DIR/inherit_overflow.rs:+0:11: +0:11
let mut _1: u8; // in scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
let mut _2: u8; // in scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
- let mut _3: u8; // in scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
scope 1 {
}
scope 2 (inlined <u8 as Add>::add) { // at $DIR/inherit_overflow.rs:7:13: 7:47
- debug self => _2; // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- debug other => _3; // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+ debug self => _1; // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+ debug other => _2; // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+ let mut _3: u8; // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
let mut _4: u8; // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- let mut _5: u8; // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- let mut _6: (u8, bool); // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+ let mut _5: (u8, bool); // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
+ _1 = const u8::MAX; // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
StorageLive(_2); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
- _2 = const u8::MAX; // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
- StorageLive(_3); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
- _3 = const 1_u8; // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
+ _2 = const 1_u8; // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
+ StorageLive(_3); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+ _3 = const u8::MAX; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
StorageLive(_4); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- _4 = const u8::MAX; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- StorageLive(_5); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- _5 = const 1_u8; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- _6 = CheckedAdd(const u8::MAX, const 1_u8); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> bb1; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+ _4 = const 1_u8; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+ _5 = CheckedAdd(const u8::MAX, const 1_u8); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+ assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> bb1; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
}
bb1: {
-- _1 = move (_6.0: u8); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-+ _1 = const 0_u8; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- StorageDead(_5); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
StorageDead(_4); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- StorageDead(_3); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
+ StorageDead(_3); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
StorageDead(_2); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
- StorageDead(_1); // scope 0 at $DIR/inherit_overflow.rs:+3:47: +3:48
- nop; // scope 0 at $DIR/inherit_overflow.rs:+0:11: +4:2
+ StorageDead(_1); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
return; // scope 0 at $DIR/inherit_overflow.rs:+4:2: +4:2
}
}
- _4 = const (); // scope 0 at $DIR/cycle.rs:+3:18: +8:6
- StorageDead(_6); // scope 0 at $DIR/cycle.rs:+8:5: +8:6
+ StorageLive(_5); // scope 0 at $DIR/cycle.rs:+4:13: +4:17
-+ nop; // scope 0 at $DIR/cycle.rs:+4:20: +4:21
-+ nop; // scope 1 at $DIR/cycle.rs:+5:13: +5:14
-+ nop; // scope 1 at $DIR/cycle.rs:+5:9: +5:14
-+ nop; // scope 1 at $DIR/cycle.rs:+6:13: +6:14
-+ nop; // scope 1 at $DIR/cycle.rs:+6:9: +6:14
-+ nop; // scope 1 at $DIR/cycle.rs:+7:13: +7:17
-+ nop; // scope 1 at $DIR/cycle.rs:+7:9: +7:17
-+ nop; // scope 0 at $DIR/cycle.rs:+3:18: +8:6
StorageDead(_5); // scope 0 at $DIR/cycle.rs:+8:5: +8:6
+ StorageDead(_4); // scope 0 at $DIR/cycle.rs:+8:5: +8:6
goto -> bb1; // scope 0 at $DIR/cycle.rs:+3:5: +8:6
bb0: {
nop; // scope 0 at $DIR/dead_stores_better.rs:+1:9: +1:10
nop; // scope 0 at $DIR/dead_stores_better.rs:+1:13: +1:14
- nop; // scope 1 at $DIR/dead_stores_better.rs:+2:5: +2:10
nop; // scope 1 at $DIR/dead_stores_better.rs:+3:9: +3:10
nop; // scope 1 at $DIR/dead_stores_better.rs:+3:9: +3:10
nop; // scope 1 at $DIR/dead_stores_better.rs:+3:5: +3:10
}
bb1: {
- nop; // scope 0 at $DIR/union.rs:+5:14: +5:30
- nop; // scope 0 at $DIR/union.rs:+5:14: +5:30
StorageDead(_2); // scope 0 at $DIR/union.rs:+5:29: +5:30
StorageLive(_3); // scope 1 at $DIR/union.rs:+7:10: +7:26
- nop; // scope 2 at $DIR/union.rs:+7:19: +7:24
StorageDead(_3); // scope 1 at $DIR/union.rs:+7:26: +7:27
StorageDead(_1); // scope 0 at $DIR/union.rs:+8:1: +8:2
return; // scope 0 at $DIR/union.rs:+8:2: +8:2
--- /dev/null
+// MIR for `const_dividend` after PreCodegen
+
+fn const_dividend(_1: i32) -> i32 {
+ debug a => _1; // in scope 0 at $DIR/div_overflow.rs:+0:23: +0:24
+ let mut _0: i32; // return place in scope 0 at $DIR/div_overflow.rs:+0:34: +0:37
+ let mut _2: bool; // in scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+
+ bb0: {
+ _2 = Eq(_1, const 0_i32); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+ assert(!move _2, "attempt to divide `{}` by zero", const 256_i32) -> bb1; // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+ }
+
+ bb1: {
+ _0 = Div(const 256_i32, move _1); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+ return; // scope 0 at $DIR/div_overflow.rs:+2:2: +2:2
+ }
+}
--- /dev/null
+// MIR for `const_divisor` after PreCodegen
+
+fn const_divisor(_1: i32) -> i32 {
+ debug a => _1; // in scope 0 at $DIR/div_overflow.rs:+0:22: +0:23
+ let mut _0: i32; // return place in scope 0 at $DIR/div_overflow.rs:+0:33: +0:36
+
+ bb0: {
+ _0 = Div(move _1, const 256_i32); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+ return; // scope 0 at $DIR/div_overflow.rs:+2:2: +2:2
+ }
+}
--- /dev/null
+// compile-flags: -Copt-level=0 -Coverflow-checks=yes
+
+// Tests that division with a const does not emit a panicking branch for overflow
+
+// EMIT_MIR div_overflow.const_divisor.PreCodegen.after.mir
+pub fn const_divisor(a: i32) -> i32 {
+ a / 256
+}
+
+// EMIT_MIR div_overflow.const_dividend.PreCodegen.after.mir
+pub fn const_dividend(a: i32) -> i32 {
+ 256 / a
+}
+
+fn main() {
+ const_divisor(123);
+ const_dividend(123);
+}
+ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
+ let mut _4: &fn() {main}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6
+ let mut _5: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
++ scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
++ }
+ }
bb0: {
+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+ _3 = <fn() {main} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+ // mir::Constant
-+ // + span: $DIR/cycle.rs:6:5: 6:6
-+ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {main}, ()) -> <fn() {main} as FnOnce<()>>::Output {<fn() {main} as Fn<()>>::call}, val: Value(<ZST>) }
++ _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
}
bb1: {
return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2
+ }
+
-+ bb2: {
-+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9
-+ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2
++ bb2 (cleanup): {
++ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:7:1: 7:2
+ }
+
+ bb3 (cleanup): {
-+ drop(_2) -> bb4; // scope 1 at $DIR/cycle.rs:7:1: 7:2
++ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
+ }
+
-+ bb4 (cleanup): {
-+ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
++ bb4: {
++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
++ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8
++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9
++ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2
}
}
+ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
+ let mut _4: &fn() {g}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6
+ let mut _5: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
++ scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8
++ }
+ }
bb0: {
+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+ _3 = <fn() {g} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+ // mir::Constant
-+ // + span: $DIR/cycle.rs:6:5: 6:6
-+ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {g}, ()) -> <fn() {g} as FnOnce<()>>::Output {<fn() {g} as Fn<()>>::call}, val: Value(<ZST>) }
++ _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
}
bb1: {
return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2
+ }
+
-+ bb2: {
-+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9
-+ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2
++ bb2 (cleanup): {
++ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:7:1: 7:2
+ }
+
+ bb3 (cleanup): {
-+ drop(_2) -> bb4; // scope 1 at $DIR/cycle.rs:7:1: 7:2
++ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
+ }
+
-+ bb4 (cleanup): {
-+ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
++ bb4: {
++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
++ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8
++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9
++ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2
}
}
+ let _2: (); // in scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
+ let _3: (); // in scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
+ let _4: (); // in scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++ scope 2 (inlined <() as F>::call) { // at $DIR/exponential_runtime.rs:73:9: 73:25
++ let _5: (); // in scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
++ let _6: (); // in scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++ let _7: (); // in scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++ }
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
- _1 = <() as G>::call() -> bb1; // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
+ StorageLive(_2); // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
-+ _2 = <() as F>::call() -> bb1; // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++ StorageLive(_5); // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
++ _5 = <() as E>::call() -> bb3; // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
// mir::Constant
- // + span: $DIR/exponential_runtime.rs:86:5: 86:20
- // + literal: Const { ty: fn() {<() as G>::call}, val: Value(<ZST>) }
-+ // + span: $DIR/exponential_runtime.rs:73:9: 73:23
-+ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
++ // + span: $DIR/exponential_runtime.rs:61:9: 61:23
++ // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
}
bb1: {
-+ StorageDead(_2); // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
-+ StorageLive(_3); // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
-+ _3 = <() as F>::call() -> bb2; // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
-+ // mir::Constant
-+ // + span: $DIR/exponential_runtime.rs:74:9: 74:23
-+ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
-+ }
-+
-+ bb2: {
+ StorageDead(_3); // scope 1 at $DIR/exponential_runtime.rs:74:25: 74:26
+ StorageLive(_4); // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
-+ _4 = <() as F>::call() -> bb3; // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++ _4 = <() as F>::call() -> bb2; // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
+ // mir::Constant
+ // + span: $DIR/exponential_runtime.rs:75:9: 75:23
+ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
+ }
+
-+ bb3: {
++ bb2: {
+ StorageDead(_4); // scope 1 at $DIR/exponential_runtime.rs:75:25: 75:26
StorageDead(_1); // scope 0 at $DIR/exponential_runtime.rs:+1:22: +1:23
_0 = const (); // scope 0 at $DIR/exponential_runtime.rs:+0:11: +2:2
return; // scope 0 at $DIR/exponential_runtime.rs:+2:2: +2:2
++ }
++
++ bb3: {
++ StorageDead(_5); // scope 2 at $DIR/exponential_runtime.rs:61:25: 61:26
++ StorageLive(_6); // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++ _6 = <() as E>::call() -> bb4; // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++ // mir::Constant
++ // + span: $DIR/exponential_runtime.rs:62:9: 62:23
++ // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
++ }
++
++ bb4: {
++ StorageDead(_6); // scope 2 at $DIR/exponential_runtime.rs:62:25: 62:26
++ StorageLive(_7); // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++ _7 = <() as E>::call() -> bb5; // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++ // mir::Constant
++ // + span: $DIR/exponential_runtime.rs:63:9: 63:23
++ // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
++ }
++
++ bb5: {
++ StorageDead(_7); // scope 2 at $DIR/exponential_runtime.rs:63:25: 63:26
++ StorageDead(_2); // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
++ StorageLive(_3); // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++ _3 = <() as F>::call() -> bb1; // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++ // mir::Constant
++ // + span: $DIR/exponential_runtime.rs:74:9: 74:23
++ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
}
}
let mut _0: (); // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10
let _1: (); // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
+ scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle.rs:14:5: 14:24
++ scope 2 (inlined <A<C> as Call>::call) { // at $DIR/inline_cycle.rs:43:9: 43:23
++ scope 3 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle.rs:28:9: 28:31
++ }
++ }
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
-+ _1 = <A<C> as Call>::call() -> bb1; // scope 1 at $DIR/inline_cycle.rs:43:9: 43:23
++ _1 = <C as Call>::call() -> bb1; // scope 3 at $DIR/inline_cycle.rs:36:9: 36:28
// mir::Constant
- // + span: $DIR/inline_cycle.rs:14:5: 14:22
-- // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
-+ // + span: $DIR/inline_cycle.rs:43:9: 43:21
-+ // + literal: Const { ty: fn() {<A<C> as Call>::call}, val: Value(<ZST>) }
++ // + span: $DIR/inline_cycle.rs:36:9: 36:26
+ // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
}
bb1: {
+ debug f => _2; // in scope 1 at $DIR/inline_cycle.rs:53:22: 53:23
+ let _3: (); // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
+ let mut _4: (); // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
++ scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline_cycle.rs:54:5: 54:8
++ }
+ }
bb0: {
// + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
+ StorageLive(_3); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
+ StorageLive(_4); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+ _3 = <fn() {f} as FnOnce<()>>::call_once(move _2, move _4) -> bb1; // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+ // mir::Constant
-+ // + span: $DIR/inline_cycle.rs:54:5: 54:6
-+ // + literal: Const { ty: extern "rust-call" fn(fn() {f}, ()) -> <fn() {f} as FnOnce<()>>::Output {<fn() {f} as FnOnce<()>>::call_once}, val: Value(<ZST>) }
++ _3 = move _2() -> bb1; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
}
bb1: {
let _1: (); // in scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
+ scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle_generic.rs:9:5: 9:24
+ scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline_cycle_generic.rs:38:9: 38:31
++ scope 3 (inlined <A as Call>::call) { // at $DIR/inline_cycle_generic.rs:31:9: 31:28
++ scope 4 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle_generic.rs:23:9: 23:31
++ }
++ }
+ }
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
-+ _1 = <A as Call>::call() -> bb1; // scope 2 at $DIR/inline_cycle_generic.rs:31:9: 31:28
++ _1 = <C as Call>::call() -> bb1; // scope 4 at $DIR/inline_cycle_generic.rs:31:9: 31:28
// mir::Constant
- // + span: $DIR/inline_cycle_generic.rs:9:5: 9:22
-- // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
+ // + span: $DIR/inline_cycle_generic.rs:31:9: 31:26
-+ // + literal: Const { ty: fn() {<A as Call>::call}, val: Value(<ZST>) }
+ // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
}
bb1: {
+ debug b => _9; // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10
+ }
+ }
++ scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16
++ }
+ }
bb0: {
+ StorageLive(_4); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
+ _4 = &_2; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
+ StorageLive(_5); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+ _3 = <fn() -> ! {sleep} as Fn<()>>::call(move _4, move _5) -> [return: bb1, unwind: bb5]; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+ // mir::Constant
-+ // + span: $DIR/inline_diverging.rs:27:13: 27:14
-+ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
++ _3 = move (*_4)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL
+ }
+
+ bb1: {
-+ StorageDead(_5); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
-+ StorageDead(_4); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
-+ StorageLive(_6); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
-+ _6 = &_2; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
-+ StorageLive(_7); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
-+ _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb2, unwind: bb4]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
-+ // mir::Constant
-+ // + span: $DIR/inline_diverging.rs:28:13: 28:14
-+ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
-+ }
-+
-+ bb2: {
+ StorageDead(_7); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
+ StorageDead(_6); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
+ StorageLive(_8); // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
+ (_1.1: !) = move _9; // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
+ StorageDead(_8); // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11
+ StorageDead(_3); // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
-+ drop(_2) -> bb3; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++ drop(_2) -> bb2; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
+ }
+
-+ bb3: {
++ bb2: {
+ unreachable; // scope 0 at $DIR/inline_diverging.rs:30:2: 30:2
+ }
+
++ bb3 (cleanup): {
++ drop(_3) -> bb4; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++ }
++
+ bb4 (cleanup): {
-+ drop(_3) -> bb5; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++ drop(_2) -> bb5; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
+ }
+
+ bb5 (cleanup): {
-+ drop(_2) -> bb6; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++ resume; // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2
+ }
+
-+ bb6 (cleanup): {
-+ resume; // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2
++ bb6: {
++ StorageDead(_5); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++ StorageDead(_4); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++ StorageLive(_6); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++ _6 = &_2; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++ StorageLive(_7); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++ _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++ // mir::Constant
++ // + span: $DIR/inline_diverging.rs:28:13: 28:14
++ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
}
}
let mut _2: std::pin::Pin<&mut [generator@$DIR/inline_generator.rs:15:5: 15:8]>; // in scope 0 at $DIR/inline_generator.rs:+1:14: +1:32
let mut _3: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline_generator.rs:+1:23: +1:31
let mut _4: [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline_generator.rs:+1:28: +1:31
-+ let mut _7: bool; // in scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
++ let mut _7: bool; // in scope 0 at $DIR/inline_generator.rs:+1:33: +1:46
scope 1 {
debug _r => _1; // in scope 1 at $DIR/inline_generator.rs:+1:9: +1:11
}
+ }
+ }
+ }
-+ scope 6 (inlined g::{closure#0}) { // at $DIR/inline_generator.rs:9:14: 9:46
++ scope 6 (inlined g::{closure#0}) { // at $DIR/inline_generator.rs:9:33: 9:46
+ debug a => _7; // in scope 6 at $DIR/inline_generator.rs:15:6: 15:7
+ let mut _8: i32; // in scope 6 at $DIR/inline_generator.rs:15:17: 15:39
+ let mut _9: u32; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41
- // mir::Constant
- // + span: $DIR/inline_generator.rs:9:33: 9:39
- // + literal: Const { ty: for<'a> fn(Pin<&'a mut [generator@$DIR/inline_generator.rs:15:5: 15:8]>, bool) -> GeneratorState<<[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::Yield, <[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::Return> {<[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::resume}, val: Value(<ZST>) }
-+ StorageLive(_7); // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
-+ _7 = const false; // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
++ StorageLive(_7); // scope 0 at $DIR/inline_generator.rs:+1:33: +1:46
++ _7 = const false; // scope 0 at $DIR/inline_generator.rs:+1:33: +1:46
+ _10 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
+ _9 = discriminant((*_10)); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
+ switchInt(move _9) -> [0: bb3, 1: bb8, 3: bb7, otherwise: bb9]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
- bb3: {
+ bb1: {
-+ StorageDead(_7); // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
++ StorageDead(_7); // scope 0 at $DIR/inline_generator.rs:+1:33: +1:46
StorageDead(_2); // scope 0 at $DIR/inline_generator.rs:+1:45: +1:46
StorageDead(_4); // scope 0 at $DIR/inline_generator.rs:+1:46: +1:47
_0 = const (); // scope 0 at $DIR/inline_generator.rs:+0:11: +2:2
debug f => _1; // in scope 0 at $DIR/inline_shims.rs:+0:20: +0:21
let mut _0: fn(A, B); // return place in scope 0 at $DIR/inline_shims.rs:+0:36: +0:44
let mut _2: &fn(A, B); // in scope 0 at $DIR/inline_shims.rs:+1:5: +1:14
-+ scope 1 (inlined <fn(A, B) as Clone>::clone - shim(fn(A, B))) { // at $DIR/inline_shims.rs:6:5: 6:14
++ scope 1 (inlined <fn(A, B) as Clone>::clone - shim(fn(A, B))) { // at $DIR/inline_shims.rs:6:7: 6:14
+ }
bb0: {
let mut _2: &mut [T]; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
let mut _3: &mut [T]; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
let mut _4: &mut [T]; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
- scope 1 (inlined <[T] as AsMut<[T]>>::as_mut) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:3:5: 3:15
+ scope 1 (inlined <[T] as AsMut<[T]>>::as_mut) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:3:7: 3:15
debug self => _4; // in scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
let mut _5: &mut [T]; // in scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
}
let mut _2: &mut T; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
let mut _3: &mut T; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
let mut _4: &mut std::boxed::Box<T>; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
- scope 1 (inlined <Box<T> as AsMut<T>>::as_mut) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:8:5: 8:15
+ scope 1 (inlined <Box<T> as AsMut<T>>::as_mut) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:8:7: 8:15
debug self => _4; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
let mut _5: &mut T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
let mut _6: &mut T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
let mut _0: &[T]; // return place in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+0:25: +0:29
let _2: &[T]; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
let mut _3: &[T]; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
- scope 1 (inlined <[T] as AsRef<[T]>>::as_ref) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:13:5: 13:15
+ scope 1 (inlined <[T] as AsRef<[T]>>::as_ref) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:13:7: 13:15
debug self => _3; // in scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
}
let mut _0: &T; // return place in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+0:28: +0:30
let _2: &T; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
let mut _3: &std::boxed::Box<T>; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
- scope 1 (inlined <Box<T> as AsRef<T>>::as_ref) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:18:5: 18:15
+ scope 1 (inlined <Box<T> as AsRef<T>>::as_ref) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:18:7: 18:15
debug self => _3; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
let mut _4: std::boxed::Box<T>; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
let mut _5: *const T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
debug out => _4; // in scope 2 at $DIR/issue_101973.rs:6:9: 6:16
}
}
- scope 3 (inlined core::num::<impl u32>::rotate_right) { // at $DIR/issue_101973.rs:14:5: 14:58
+ scope 3 (inlined core::num::<impl u32>::rotate_right) { // at $DIR/issue_101973.rs:14:18: 14:58
debug self => _4; // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
debug n => _6; // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
let mut _15: u32; // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
let mut _3: isize; // in scope 0 at $DIR/issue_73223.rs:+2:9: +2:16
let _4: i32; // in scope 0 at $DIR/issue_73223.rs:+2:14: +2:15
- let mut _5: !; // in scope 0 at $DIR/issue_73223.rs:+3:17: +3:23
- let mut _7: i32; // in scope 0 at $DIR/issue_73223.rs:+6:22: +6:27
- let _8: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _9: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _10: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _11: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _12: i32; // in scope 0 at $DIR/issue_73223.rs:+7:23: +7:24
- let mut _15: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _16: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _17: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _18: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _19: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _21: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _22: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _23: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _24: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _6: i32; // in scope 0 at $DIR/issue_73223.rs:+6:22: +6:27
+ let mut _7: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _8: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _11: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _12: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _13: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _14: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _16: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _17: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _18: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _19: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _20: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _21: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _22: std::option::Option<std::fmt::Arguments<'_>>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _24: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _25: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _26: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _27: std::option::Option<std::fmt::Arguments<'_>>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _29: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _30: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 1 {
debug split => _1; // in scope 1 at $DIR/issue_73223.rs:+1:9: +1:14
- let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue_73223.rs:+6:9: +6:14
+ let _5: std::option::Option<i32>; // in scope 1 at $DIR/issue_73223.rs:+6:9: +6:14
scope 3 {
- debug _prev => _6; // in scope 3 at $DIR/issue_73223.rs:+6:9: +6:14
- let _13: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _14: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _28: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug _prev => _5; // in scope 3 at $DIR/issue_73223.rs:+6:9: +6:14
+ let _9: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _10: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _23: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 4 {
- debug left_val => _13; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- debug right_val => _14; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _20: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug left_val => _9; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug right_val => _10; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _15: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 5 {
- debug kind => _20; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug kind => _15; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
}
}
}
}
bb1: {
- nop; // scope 0 at $DIR/issue_73223.rs:+3:17: +3:23
StorageDead(_2); // scope 0 at $DIR/issue_73223.rs:+4:6: +4:7
StorageDead(_1); // scope 0 at $DIR/issue_73223.rs:+8:1: +8:2
return; // scope 0 at $DIR/issue_73223.rs:+8:2: +8:2
_1 = _4; // scope 2 at $DIR/issue_73223.rs:+2:20: +2:21
StorageDead(_4); // scope 0 at $DIR/issue_73223.rs:+2:20: +2:21
StorageDead(_2); // scope 0 at $DIR/issue_73223.rs:+4:6: +4:7
- StorageLive(_6); // scope 1 at $DIR/issue_73223.rs:+6:9: +6:14
- StorageLive(_7); // scope 1 at $DIR/issue_73223.rs:+6:22: +6:27
- _7 = _1; // scope 1 at $DIR/issue_73223.rs:+6:22: +6:27
- Deinit(_6); // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
- ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
- discriminant(_6) = 1; // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
- StorageDead(_7); // scope 1 at $DIR/issue_73223.rs:+6:27: +6:28
+ StorageLive(_5); // scope 1 at $DIR/issue_73223.rs:+6:9: +6:14
+ StorageLive(_6); // scope 1 at $DIR/issue_73223.rs:+6:22: +6:27
+ _6 = _1; // scope 1 at $DIR/issue_73223.rs:+6:22: +6:27
+ Deinit(_5); // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
+ ((_5 as Some).0: i32) = move _6; // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
+ discriminant(_5) = 1; // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
+ StorageDead(_6); // scope 1 at $DIR/issue_73223.rs:+6:27: +6:28
+ StorageLive(_24); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_25); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _7 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_29); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_30); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _10 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _28 = const _; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _23 = const _; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
- _11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- Deinit(_29); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- Deinit(_30); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _29 = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _30 = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _13 = _29; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _14 = _30; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _17 = (*_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _18 = const 1_i32; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _16 = Eq(move _17, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _15 = Not(move _16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- switchInt(move _15) -> [0: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _8 = _23; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ Deinit(_24); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ Deinit(_25); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _24 = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _25 = move _8; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _9 = _24; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _10 = _25; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _13 = (*_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_14); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _14 = const 1_i32; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _12 = Eq(move _13, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_14); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _11 = Not(move _12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ switchInt(move _11) -> [0: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
}
bb4: {
- StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- Deinit(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- discriminant(_20) = 0; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_21); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_22); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _22 = const core::panicking::AssertKind::Eq; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ Deinit(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ discriminant(_15) = 0; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_16); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_17); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _17 = const core::panicking::AssertKind::Eq; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
- StorageLive(_23); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_24); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _24 = _13; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _23 = _24; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_25); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_26); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _26 = _14; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _25 = _26; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- Deinit(_27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- discriminant(_27) = 0; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _21 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _19 = _9; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _18 = _19; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_20); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_21); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _21 = _10; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _20 = _21; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_22); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ Deinit(_22); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ discriminant(_22) = 0; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _16 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _18, move _20, move _22); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: for<'a, 'b, 'c> fn(core::panicking::AssertKind, &'a i32, &'b i32, Option<Arguments<'c>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
}
bb5: {
- nop; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_29); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_30); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- nop; // scope 0 at $DIR/issue_73223.rs:+0:11: +8:2
- StorageDead(_6); // scope 1 at $DIR/issue_73223.rs:+8:1: +8:2
+ StorageDead(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_24); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_25); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_5); // scope 1 at $DIR/issue_73223.rs:+8:1: +8:2
StorageDead(_1); // scope 0 at $DIR/issue_73223.rs:+8:1: +8:2
return; // scope 0 at $DIR/issue_73223.rs:+8:2: +8:2
}
let mut _6: T; // in scope 0 at $DIR/issue_76432.rs:+1:21: +1:22
let mut _7: T; // in scope 0 at $DIR/issue_76432.rs:+1:24: +1:25
let mut _8: T; // in scope 0 at $DIR/issue_76432.rs:+1:27: +1:28
- let _9: [*const T; 3]; // in scope 0 at $DIR/issue_76432.rs:+2:5: +5:6
+ let mut _9: usize; // in scope 0 at $DIR/issue_76432.rs:+3:9: +3:33
let mut _10: usize; // in scope 0 at $DIR/issue_76432.rs:+3:9: +3:33
- let mut _11: usize; // in scope 0 at $DIR/issue_76432.rs:+3:9: +3:33
- let mut _12: bool; // in scope 0 at $DIR/issue_76432.rs:+3:9: +3:33
- let mut _16: *const T; // in scope 0 at $DIR/issue_76432.rs:+3:38: +3:52
- let mut _17: *const T; // in scope 0 at $DIR/issue_76432.rs:+3:38: +3:52
- let mut _18: *const T; // in scope 0 at $DIR/issue_76432.rs:+3:54: +3:68
- let mut _19: *const T; // in scope 0 at $DIR/issue_76432.rs:+3:54: +3:68
- let mut _20: *const T; // in scope 0 at $DIR/issue_76432.rs:+3:70: +3:84
- let mut _21: *const T; // in scope 0 at $DIR/issue_76432.rs:+3:70: +3:84
- let mut _22: !; // in scope 0 at $SRC_DIR/core/src/panic.rs:LL:COL
+ let mut _11: bool; // in scope 0 at $DIR/issue_76432.rs:+3:9: +3:33
+ let mut _15: !; // in scope 0 at $SRC_DIR/core/src/panic.rs:LL:COL
scope 1 {
debug v => _2; // in scope 1 at $DIR/issue_76432.rs:+1:9: +1:10
- let _13: &T; // in scope 1 at $DIR/issue_76432.rs:+3:10: +3:16
- let _14: &T; // in scope 1 at $DIR/issue_76432.rs:+3:18: +3:24
- let _15: &T; // in scope 1 at $DIR/issue_76432.rs:+3:26: +3:32
+ let _12: &T; // in scope 1 at $DIR/issue_76432.rs:+3:10: +3:16
+ let _13: &T; // in scope 1 at $DIR/issue_76432.rs:+3:18: +3:24
+ let _14: &T; // in scope 1 at $DIR/issue_76432.rs:+3:26: +3:32
scope 2 {
- debug v1 => _13; // in scope 2 at $DIR/issue_76432.rs:+3:10: +3:16
- debug v2 => _14; // in scope 2 at $DIR/issue_76432.rs:+3:18: +3:24
- debug v3 => _15; // in scope 2 at $DIR/issue_76432.rs:+3:26: +3:32
+ debug v1 => _12; // in scope 2 at $DIR/issue_76432.rs:+3:10: +3:16
+ debug v2 => _13; // in scope 2 at $DIR/issue_76432.rs:+3:18: +3:24
+ debug v3 => _14; // in scope 2 at $DIR/issue_76432.rs:+3:26: +3:32
}
}
_2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
StorageDead(_3); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
StorageDead(_4); // scope 0 at $DIR/issue_76432.rs:+1:29: +1:30
- StorageLive(_9); // scope 1 at $DIR/issue_76432.rs:+2:5: +5:6
- _10 = Len((*_2)); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
- _11 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
-- _12 = Eq(move _10, const 3_usize); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
-- switchInt(move _12) -> [0: bb1, otherwise: bb2]; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
+ _9 = Len((*_2)); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
+ _10 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
+- _11 = Eq(move _9, const 3_usize); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
+- switchInt(move _11) -> [0: bb1, otherwise: bb2]; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
+ nop; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
-+ switchInt(move _10) -> [3: bb2, otherwise: bb1]; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
++ switchInt(move _9) -> [3: bb2, otherwise: bb1]; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
}
bb1: {
- StorageLive(_22); // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL
- _22 = core::panicking::panic(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL
+ StorageLive(_15); // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL
+ _15 = core::panicking::panic(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/panic.rs:LL:COL
// + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(<ZST>) }
}
bb2: {
- StorageLive(_13); // scope 1 at $DIR/issue_76432.rs:+3:10: +3:16
- _13 = &(*_2)[0 of 3]; // scope 1 at $DIR/issue_76432.rs:+3:10: +3:16
- StorageLive(_14); // scope 1 at $DIR/issue_76432.rs:+3:18: +3:24
- _14 = &(*_2)[1 of 3]; // scope 1 at $DIR/issue_76432.rs:+3:18: +3:24
- StorageLive(_15); // scope 1 at $DIR/issue_76432.rs:+3:26: +3:32
- _15 = &(*_2)[2 of 3]; // scope 1 at $DIR/issue_76432.rs:+3:26: +3:32
- StorageLive(_16); // scope 2 at $DIR/issue_76432.rs:+3:38: +3:52
- StorageLive(_17); // scope 2 at $DIR/issue_76432.rs:+3:38: +3:52
- _17 = &raw const (*_13); // scope 2 at $DIR/issue_76432.rs:+3:38: +3:40
- _16 = _17; // scope 2 at $DIR/issue_76432.rs:+3:38: +3:52
- StorageLive(_18); // scope 2 at $DIR/issue_76432.rs:+3:54: +3:68
- StorageLive(_19); // scope 2 at $DIR/issue_76432.rs:+3:54: +3:68
- _19 = &raw const (*_14); // scope 2 at $DIR/issue_76432.rs:+3:54: +3:56
- _18 = _19; // scope 2 at $DIR/issue_76432.rs:+3:54: +3:68
- StorageLive(_20); // scope 2 at $DIR/issue_76432.rs:+3:70: +3:84
- StorageLive(_21); // scope 2 at $DIR/issue_76432.rs:+3:70: +3:84
- _21 = &raw const (*_15); // scope 2 at $DIR/issue_76432.rs:+3:70: +3:72
- _20 = _21; // scope 2 at $DIR/issue_76432.rs:+3:70: +3:84
- _9 = [move _16, move _18, move _20]; // scope 2 at $DIR/issue_76432.rs:+3:37: +3:85
- StorageDead(_21); // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85
- StorageDead(_20); // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85
- StorageDead(_19); // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85
- StorageDead(_18); // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85
- StorageDead(_17); // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85
- StorageDead(_16); // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85
- StorageDead(_15); // scope 1 at $DIR/issue_76432.rs:+3:84: +3:85
+ StorageLive(_12); // scope 1 at $DIR/issue_76432.rs:+3:10: +3:16
+ _12 = &(*_2)[0 of 3]; // scope 1 at $DIR/issue_76432.rs:+3:10: +3:16
+ StorageLive(_13); // scope 1 at $DIR/issue_76432.rs:+3:18: +3:24
+ _13 = &(*_2)[1 of 3]; // scope 1 at $DIR/issue_76432.rs:+3:18: +3:24
+ StorageLive(_14); // scope 1 at $DIR/issue_76432.rs:+3:26: +3:32
+ _14 = &(*_2)[2 of 3]; // scope 1 at $DIR/issue_76432.rs:+3:26: +3:32
StorageDead(_14); // scope 1 at $DIR/issue_76432.rs:+3:84: +3:85
StorageDead(_13); // scope 1 at $DIR/issue_76432.rs:+3:84: +3:85
- StorageDead(_9); // scope 1 at $DIR/issue_76432.rs:+5:6: +5:7
- nop; // scope 0 at $DIR/issue_76432.rs:+0:44: +6:2
+ StorageDead(_12); // scope 1 at $DIR/issue_76432.rs:+3:84: +3:85
StorageDead(_5); // scope 0 at $DIR/issue_76432.rs:+6:1: +6:2
StorageDead(_2); // scope 0 at $DIR/issue_76432.rs:+6:1: +6:2
return; // scope 0 at $DIR/issue_76432.rs:+6:2: +6:2
debug num => _1; // in scope 0 at $DIR/issue_59352.rs:+0:21: +0:24
let mut _0: u32; // return place in scope 0 at $DIR/issue_59352.rs:+0:35: +0:38
let mut _2: std::option::Option<u32>; // in scope 0 at $DIR/issue_59352.rs:+2:26: +2:41
- let mut _3: u32; // in scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
+ let mut _3: u32; // in scope 0 at $DIR/issue_59352.rs:+2:12: +2:23
let mut _9: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 1 (inlined char::methods::<impl char>::is_digit) { // at $DIR/issue_59352.rs:14:8: 14:23
+ scope 1 (inlined char::methods::<impl char>::is_digit) { // at $DIR/issue_59352.rs:14:12: 14:23
debug self => _1; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
debug radix => _3; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
let mut _4: &std::option::Option<u32>; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
debug self => _4; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL
}
}
- scope 3 (inlined #[track_caller] Option::<u32>::unwrap) { // at $DIR/issue_59352.rs:14:26: 14:50
+ scope 3 (inlined #[track_caller] Option::<u32>::unwrap) { // at $DIR/issue_59352.rs:14:42: 14:50
debug self => _2; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
let mut _7: isize; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
let mut _8: !; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
}
bb0: {
- StorageLive(_3); // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
+ StorageLive(_3); // scope 0 at $DIR/issue_59352.rs:+2:12: +2:23
StorageLive(_4); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
StorageLive(_5); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
StorageLive(_6); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
_9 = discriminant((*_4)); // scope 2 at $SRC_DIR/core/src/option.rs:LL:COL
StorageDead(_4); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
StorageDead(_5); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
- StorageDead(_3); // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
+ StorageDead(_3); // scope 0 at $DIR/issue_59352.rs:+2:12: +2:23
switchInt(move _9) -> [1: bb1, otherwise: bb3]; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
}
let mut _18: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
scope 9 {
debug e => _16; // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
+ debug t => _18; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+ }
}
}
}
StorageLive(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
StorageLive(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
_18 = move _16; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-- _17 = <i32 as From<i32>>::from(move _18) -> bb8; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-+ _17 = <i32 as From<i32>>::from(move _18) -> bb7; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/result.rs:LL:COL
- // + literal: Const { ty: fn(i32) -> i32 {<i32 as From<i32>>::from}, val: Value(<ZST>) }
+ _17 = move _18; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+ StorageDead(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ StorageDead(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ StorageDead(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+ StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
+ StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
+ StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
+ StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
}
- bb5: {
+ _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
+ switchInt(move _5) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
}
-
-- bb8: {
-+ bb7: {
- StorageDead(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
- StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
- return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
- }
}
--- /dev/null
+// MIR for `ezmap` after PreCodegen
+
+fn ezmap(_1: Option<i32>) -> Option<i32> {
+ debug x => _1; // in scope 0 at $DIR/simple_option_map_e2e.rs:+0:14: +0:15
+ let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/simple_option_map_e2e.rs:+0:33: +0:44
+ let mut _2: [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]; // in scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21
+ scope 1 (inlined map::<i32, i32, [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]>) { // at $DIR/simple_option_map_e2e.rs:14:5: 14:22
+ debug slf => _1; // in scope 1 at $DIR/simple_option_map_e2e.rs:2:17: 2:20
+ debug f => _2; // in scope 1 at $DIR/simple_option_map_e2e.rs:2:33: 2:34
+ let mut _3: isize; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:9: 7:16
+ let mut _4: i32; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+ let mut _5: i32; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+ scope 2 {
+ debug x => _5; // in scope 2 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+ scope 3 (inlined ezmap::{closure#0}) { // at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+ debug n => _5; // in scope 3 at $DIR/simple_option_map_e2e.rs:+1:13: +1:14
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21
+ _3 = discriminant(_1); // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14
+ switchInt(move _3) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 1 at $DIR/simple_option_map_e2e.rs:6:5: 6:14
+ }
+
+ bb1: {
+ Deinit(_0); // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+ discriminant(_0) = 0; // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+ goto -> bb4; // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+ }
+
+ bb2: {
+ unreachable; // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14
+ }
+
+ bb3: {
+ _5 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+ StorageLive(_4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+ _4 = Add(move _5, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
+ Deinit(_0); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
+ ((_0 as Some).0: i32) = move _4; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
+ discriminant(_0) = 1; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
+ StorageDead(_4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:29: 7:30
+ goto -> bb4; // scope 1 at $DIR/simple_option_map_e2e.rs:10:1: 10:2
+ }
+
+ bb4: {
+ StorageDead(_2); // scope 0 at $DIR/simple_option_map_e2e.rs:+1:21: +1:22
+ return; // scope 0 at $DIR/simple_option_map_e2e.rs:+2:2: +2:2
+ }
+}
--- /dev/null
+#[inline(always)]
+fn map<T, U, F>(slf: Option<T>, f: F) -> Option<U>
+where
+ F: FnOnce(T) -> U,
+{
+ match slf {
+ Some(x) => Some(f(x)),
+ None => None,
+ }
+}
+
+// EMIT_MIR simple_option_map_e2e.ezmap.PreCodegen.after.mir
+pub fn ezmap(x: Option<i32>) -> Option<i32> {
+ map(x, |n| n + 1)
+}
+
+fn main() {
+ assert_eq!(None, ezmap(None));
+}
bb2: {
StorageDead(_2); // scope 0 at $DIR/simplify_if.rs:+2:15: +2:16
- nop; // scope 0 at $DIR/simplify_if.rs:+1:14: +3:6
goto -> bb4; // scope 0 at $DIR/simplify_if.rs:+1:5: +3:6
}
bb3: {
- nop; // scope 0 at $DIR/simplify_if.rs:+3:6: +3:6
goto -> bb4; // scope 0 at $DIR/simplify_if.rs:+1:5: +3:6
}
--- /dev/null
+- // MIR for `c` before SimplifyLocals-before-const-prop
++ // MIR for `c` after SimplifyLocals-before-const-prop
+
+ fn c() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:8: +0:8
+ let _1: [u8; 10]; // in scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
+- let mut _2: &[u8]; // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
+- let mut _3: &[u8; 10]; // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
+- let _4: &[u8; 10]; // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
+ scope 1 {
+ debug bytes => _1; // in scope 1 at $DIR/simplify_locals.rs:+1:9: +1:14
+ scope 2 {
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
+ _1 = [const 0_u8; 10]; // scope 0 at $DIR/simplify_locals.rs:+1:17: +1:26
+- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+- StorageLive(_3); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+- StorageLive(_4); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+- _4 = &_1; // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+- _3 = &(*_4); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+- _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+- StorageDead(_3); // scope 1 at $DIR/simplify_locals.rs:+3:25: +3:26
+- StorageDead(_4); // scope 1 at $DIR/simplify_locals.rs:+3:26: +3:27
+- StorageDead(_2); // scope 1 at $DIR/simplify_locals.rs:+3:26: +3:27
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:8: +4:2
+ StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+4:1: +4:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+4:2: +4:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `c` before SimplifyLocals
-+ // MIR for `c` after SimplifyLocals
-
- fn c() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:8: +0:8
- let _1: [u8; 10]; // in scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
-- let mut _2: &[u8]; // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
-- let mut _3: &[u8; 10]; // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
-- let _4: &[u8; 10]; // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
- scope 1 {
- debug bytes => _1; // in scope 1 at $DIR/simplify_locals.rs:+1:9: +1:14
- scope 2 {
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
- _1 = [const 0_u8; 10]; // scope 0 at $DIR/simplify_locals.rs:+1:17: +1:26
-- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
-- StorageLive(_3); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
-- StorageLive(_4); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
-- _4 = &_1; // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
-- _3 = &(*_4); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
-- _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
-- StorageDead(_3); // scope 1 at $DIR/simplify_locals.rs:+3:25: +3:26
-- StorageDead(_4); // scope 1 at $DIR/simplify_locals.rs:+3:26: +3:27
-- StorageDead(_2); // scope 1 at $DIR/simplify_locals.rs:+3:26: +3:27
- _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:8: +4:2
- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+4:1: +4:2
- return; // scope 0 at $DIR/simplify_locals.rs:+4:2: +4:2
- }
- }
-
--- /dev/null
+- // MIR for `d1` before SimplifyLocals-before-const-prop
++ // MIR for `d1` after SimplifyLocals-before-const-prop
+
+ fn d1() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+- let mut _1: E; // in scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
+ scope 1 {
+ }
+
+ bb0: {
+- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
+- Deinit(_1); // scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
+- discriminant(_1) = 0; // scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
+- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:17: +2:18
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `d1` before SimplifyLocals
-+ // MIR for `d1` after SimplifyLocals
-
- fn d1() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
-- let mut _1: E; // in scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
- scope 1 {
- }
-
- bb0: {
-- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
-- Deinit(_1); // scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
-- discriminant(_1) = 0; // scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
-- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:17: +2:18
- _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
- return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
- }
- }
-
--- /dev/null
+- // MIR for `d2` before SimplifyLocals-before-const-prop
++ // MIR for `d2` after SimplifyLocals-before-const-prop
+
+ fn d2() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+- let mut _1: E; // in scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
+- let mut _2: (i32, E); // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:17
+- let mut _3: E; // in scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
+
+ bb0: {
+- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
+- Deinit(_1); // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
+- discriminant(_1) = 1; // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
+- StorageLive(_2); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:17
+- StorageLive(_3); // scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
+- Deinit(_3); // scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
+- discriminant(_3) = 0; // scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
+- Deinit(_2); // scope 0 at $DIR/simplify_locals.rs:+2:6: +2:16
+- (_2.0: i32) = const 10_i32; // scope 0 at $DIR/simplify_locals.rs:+2:6: +2:16
+- (_2.1: E) = move _3; // scope 0 at $DIR/simplify_locals.rs:+2:6: +2:16
+- StorageDead(_3); // scope 0 at $DIR/simplify_locals.rs:+2:15: +2:16
+- (_2.1: E) = move _1; // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:26
+- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:25: +2:26
+- StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:26: +2:27
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `d2` before SimplifyLocals
-+ // MIR for `d2` after SimplifyLocals
-
- fn d2() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
-- let mut _1: E; // in scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
-- let mut _2: (i32, E); // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:17
-- let mut _3: E; // in scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
-
- bb0: {
-- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
-- Deinit(_1); // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
-- discriminant(_1) = 1; // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
-- StorageLive(_2); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:17
-- StorageLive(_3); // scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
-- Deinit(_3); // scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
-- discriminant(_3) = 0; // scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
-- Deinit(_2); // scope 0 at $DIR/simplify_locals.rs:+2:6: +2:16
-- (_2.0: i32) = const 10_i32; // scope 0 at $DIR/simplify_locals.rs:+2:6: +2:16
-- (_2.1: E) = move _3; // scope 0 at $DIR/simplify_locals.rs:+2:6: +2:16
-- StorageDead(_3); // scope 0 at $DIR/simplify_locals.rs:+2:15: +2:16
-- (_2.1: E) = move _1; // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:26
-- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:25: +2:26
-- StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:26: +2:27
- _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
- return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
- }
- }
-
--- /dev/null
+- // MIR for `expose_addr` before SimplifyLocals-before-const-prop
++ // MIR for `expose_addr` after SimplifyLocals-before-const-prop
+
+ fn expose_addr(_1: *const usize) -> () {
+ debug p => _1; // in scope 0 at $DIR/simplify_locals.rs:+0:16: +0:17
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:33: +0:33
+ let _2: usize; // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
+ let mut _3: *const usize; // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
+ StorageLive(_3); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
+ _3 = _1; // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
+ _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
+ StorageDead(_3); // scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
+ StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:15: +2:16
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:33: +3:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `expose_addr` before SimplifyLocals
-+ // MIR for `expose_addr` after SimplifyLocals
-
- fn expose_addr(_1: *const usize) -> () {
- debug p => _1; // in scope 0 at $DIR/simplify_locals.rs:+0:16: +0:17
- let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:33: +0:33
- let _2: usize; // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
- let mut _3: *const usize; // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
- StorageLive(_3); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
- _3 = _1; // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
- _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
- StorageDead(_3); // scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
- StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:15: +2:16
- _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:33: +3:2
- return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
- }
- }
-
--- /dev/null
+- // MIR for `r` before SimplifyLocals-before-const-prop
++ // MIR for `r` after SimplifyLocals-before-const-prop
+
+ fn r() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:8: +0:8
+ let mut _1: i32; // in scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
+- let mut _2: &i32; // in scope 0 at $DIR/simplify_locals.rs:+3:13: +3:15
+- let mut _3: &mut i32; // in scope 0 at $DIR/simplify_locals.rs:+4:13: +4:19
+ scope 1 {
+ debug a => _1; // in scope 1 at $DIR/simplify_locals.rs:+1:9: +1:14
+ scope 2 {
+ scope 3 {
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
+ _1 = const 1_i32; // scope 0 at $DIR/simplify_locals.rs:+1:17: +1:18
+- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+3:13: +3:15
+- _2 = &_1; // scope 1 at $DIR/simplify_locals.rs:+3:13: +3:15
+- StorageDead(_2); // scope 1 at $DIR/simplify_locals.rs:+3:15: +3:16
+- StorageLive(_3); // scope 2 at $DIR/simplify_locals.rs:+4:13: +4:19
+- _3 = &mut _1; // scope 2 at $DIR/simplify_locals.rs:+4:13: +4:19
+- StorageDead(_3); // scope 2 at $DIR/simplify_locals.rs:+4:19: +4:20
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:8: +5:2
+ StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+5:1: +5:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+5:2: +5:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `r` before SimplifyLocals
-+ // MIR for `r` after SimplifyLocals
-
- fn r() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:8: +0:8
- let mut _1: i32; // in scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
-- let mut _2: &i32; // in scope 0 at $DIR/simplify_locals.rs:+3:13: +3:15
-- let mut _3: &mut i32; // in scope 0 at $DIR/simplify_locals.rs:+4:13: +4:19
- scope 1 {
- debug a => _1; // in scope 1 at $DIR/simplify_locals.rs:+1:9: +1:14
- scope 2 {
- scope 3 {
- }
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
- _1 = const 1_i32; // scope 0 at $DIR/simplify_locals.rs:+1:17: +1:18
-- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+3:13: +3:15
-- _2 = &_1; // scope 1 at $DIR/simplify_locals.rs:+3:13: +3:15
-- StorageDead(_2); // scope 1 at $DIR/simplify_locals.rs:+3:15: +3:16
-- StorageLive(_3); // scope 2 at $DIR/simplify_locals.rs:+4:13: +4:19
-- _3 = &mut _1; // scope 2 at $DIR/simplify_locals.rs:+4:13: +4:19
-- StorageDead(_3); // scope 2 at $DIR/simplify_locals.rs:+4:19: +4:20
- _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:8: +5:2
- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+5:1: +5:2
- return; // scope 0 at $DIR/simplify_locals.rs:+5:2: +5:2
- }
- }
-
-// unit-test: SimplifyLocals
+// unit-test: SimplifyLocals-before-const-prop
#![feature(thread_local)]
B,
}
-// EMIT_MIR simplify_locals.c.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.c.SimplifyLocals-before-const-prop.diff
fn c() {
let bytes = [0u8; 10];
// Unused cast
let _: &[u8] = &bytes;
}
-// EMIT_MIR simplify_locals.d1.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.d1.SimplifyLocals-before-const-prop.diff
fn d1() {
// Unused set discriminant
let _ = E::A;
}
-// EMIT_MIR simplify_locals.d2.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.d2.SimplifyLocals-before-const-prop.diff
fn d2() {
// Unused set discriminant
{(10, E::A)}.1 = E::B;
}
-// EMIT_MIR simplify_locals.r.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.r.SimplifyLocals-before-const-prop.diff
fn r() {
let mut a = 1;
// Unused references
#[thread_local] static mut X: u32 = 0;
-// EMIT_MIR simplify_locals.t1.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.t1.SimplifyLocals-before-const-prop.diff
fn t1() {
// Unused thread local
unsafe { X };
}
-// EMIT_MIR simplify_locals.t2.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.t2.SimplifyLocals-before-const-prop.diff
fn t2() {
// Unused thread local
unsafe { &mut X };
}
-// EMIT_MIR simplify_locals.t3.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.t3.SimplifyLocals-before-const-prop.diff
fn t3() {
// Unused thread local
unsafe { *&mut X };
}
-// EMIT_MIR simplify_locals.t4.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.t4.SimplifyLocals-before-const-prop.diff
fn t4() -> u32 {
// Used thread local
unsafe { X + 1 }
}
-// EMIT_MIR simplify_locals.expose_addr.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff
fn expose_addr(p: *const usize) {
// Used pointer to address cast. Has a side effect of exposing the provenance.
p as usize;
--- /dev/null
+- // MIR for `t1` before SimplifyLocals-before-const-prop
++ // MIR for `t1` after SimplifyLocals-before-const-prop
+
+ fn t1() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+- let _1: u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
+- let mut _2: *mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
+ scope 1 {
+ }
+
+ bb0: {
+- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:17
+- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+- _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+- _1 = (*_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+- StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:17: +2:18
+- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:17: +2:18
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `t1` before SimplifyLocals
-+ // MIR for `t1` after SimplifyLocals
-
- fn t1() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
-- let _1: u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
-- let mut _2: *mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
- scope 1 {
- }
-
- bb0: {
-- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:17
-- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
-- _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
-- _1 = (*_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
-- StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:17: +2:18
-- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:17: +2:18
- _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
- return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
- }
- }
-
--- /dev/null
+- // MIR for `t2` before SimplifyLocals-before-const-prop
++ // MIR for `t2` after SimplifyLocals-before-const-prop
+
+ fn t2() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+- let _1: &mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:20
+- let mut _2: *mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:19: +2:20
+ scope 1 {
+ }
+
+ bb0: {
+- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:22
+- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+2:19: +2:20
+- _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify_locals.rs:+2:19: +2:20
+- _1 = &mut (*_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:20
+- StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:23
+- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:23
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `t2` before SimplifyLocals
-+ // MIR for `t2` after SimplifyLocals
-
- fn t2() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
-- let _1: &mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:20
-- let mut _2: *mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:19: +2:20
- scope 1 {
- }
-
- bb0: {
-- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:22
-- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+2:19: +2:20
-- _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify_locals.rs:+2:19: +2:20
-- _1 = &mut (*_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:20
-- StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:23
-- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:23
- _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
- return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
- }
- }
-
--- /dev/null
+- // MIR for `t3` before SimplifyLocals-before-const-prop
++ // MIR for `t3` after SimplifyLocals-before-const-prop
+
+ fn t3() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+- let _1: u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:21
+- let mut _2: &mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:15: +2:21
+- let mut _3: *mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:20: +2:21
+ scope 1 {
+ }
+
+ bb0: {
+- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:23
+- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+2:15: +2:21
+- StorageLive(_3); // scope 1 at $DIR/simplify_locals.rs:+2:20: +2:21
+- _3 = &/*tls*/ mut X; // scope 1 at $DIR/simplify_locals.rs:+2:20: +2:21
+- _2 = &mut (*_3); // scope 1 at $DIR/simplify_locals.rs:+2:15: +2:21
+- _1 = (*_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:21
+- StorageDead(_3); // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
+- StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
+- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `t3` before SimplifyLocals
-+ // MIR for `t3` after SimplifyLocals
-
- fn t3() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
-- let _1: u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:21
-- let mut _2: &mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:15: +2:21
-- let mut _3: *mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:20: +2:21
- scope 1 {
- }
-
- bb0: {
-- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:23
-- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+2:15: +2:21
-- StorageLive(_3); // scope 1 at $DIR/simplify_locals.rs:+2:20: +2:21
-- _3 = &/*tls*/ mut X; // scope 1 at $DIR/simplify_locals.rs:+2:20: +2:21
-- _2 = &mut (*_3); // scope 1 at $DIR/simplify_locals.rs:+2:15: +2:21
-- _1 = (*_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:21
-- StorageDead(_3); // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
-- StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
-- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
- _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
- return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
- }
- }
-
--- /dev/null
+- // MIR for `t4` before SimplifyLocals-before-const-prop
++ // MIR for `t4` after SimplifyLocals-before-const-prop
+
+ fn t4() -> u32 {
+ let mut _0: u32; // return place in scope 0 at $DIR/simplify_locals.rs:+0:12: +0:15
+ let mut _1: u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
+ let mut _2: *mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
+ scope 1 {
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+ StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+ _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+ _1 = (*_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+ _0 = Add(move _1, const 1_u32); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:19
+ StorageDead(_1); // scope 1 at $DIR/simplify_locals.rs:+2:18: +2:19
+ StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+3:1: +3:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `t4` before SimplifyLocals
-+ // MIR for `t4` after SimplifyLocals
-
- fn t4() -> u32 {
- let mut _0: u32; // return place in scope 0 at $DIR/simplify_locals.rs:+0:12: +0:15
- let mut _1: u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
- let mut _2: *mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
- scope 1 {
- }
-
- bb0: {
- StorageLive(_1); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
- _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
- _1 = (*_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
- _0 = Add(move _1, const 1_u32); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:19
- StorageDead(_1); // scope 1 at $DIR/simplify_locals.rs:+2:18: +2:19
- StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+3:1: +3:2
- return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
- }
- }
-
--- /dev/null
+- // MIR for `foo` before SimplifyLocals-final
++ // MIR for `foo` after SimplifyLocals-final
+
+ fn foo() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+0:13: +0:13
+ let mut _1: (std::option::Option<u8>, std::option::Option<T>); // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
+ let mut _2: std::option::Option<u8>; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
+ let mut _3: std::option::Option<T>; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
+ let mut _4: isize; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:22: +1:26
+ let mut _5: isize; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:13: +1:20
+- let mut _7: bool; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
+- let mut _8: u8; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
+ scope 1 {
+ debug a => _6; // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
+ let _6: u8; // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
+ StorageLive(_2); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
+ Deinit(_2); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
+ discriminant(_2) = 0; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
+ StorageLive(_3); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
+ Deinit(_3); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
+ discriminant(_3) = 0; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
+ Deinit(_1); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
+ (_1.0: std::option::Option<u8>) = move _2; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
+ (_1.1: std::option::Option<T>) = move _3; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
+ StorageDead(_3); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:68: +1:69
+ StorageDead(_2); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:68: +1:69
+ _5 = discriminant((_1.0: std::option::Option<u8>)); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
+ switchInt(move _5) -> [1: bb1, otherwise: bb3]; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
+ }
+
+ bb1: {
+ _4 = discriminant((_1.1: std::option::Option<T>)); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
+ switchInt(move _4) -> [0: bb2, otherwise: bb3]; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
+ }
+
+ bb2: {
+ StorageLive(_6); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
+ _6 = (((_1.0: std::option::Option<u8>) as Some).0: u8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
+- StorageLive(_7); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
+- StorageLive(_8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
+- _8 = _6; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
+- _7 = Gt(move _8, const 42_u8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
+- StorageDead(_8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:19: +2:20
+- StorageDead(_7); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+4:9: +4:10
+ StorageDead(_6); // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+5:5: +5:6
+ goto -> bb3; // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:5: +5:6
+ }
+
+ bb3: {
+ drop(_1) -> bb4; // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:1: +6:2
+ }
+
+ bb4: {
+ StorageDead(_1); // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:1: +6:2
+ return; // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:2: +6:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `foo` before SimplifyLocals
-+ // MIR for `foo` after SimplifyLocals
-
- fn foo() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+0:13: +0:13
- let mut _1: (std::option::Option<u8>, std::option::Option<T>); // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
- let mut _2: std::option::Option<u8>; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
- let mut _3: std::option::Option<T>; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
- let mut _4: isize; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:22: +1:26
- let mut _5: isize; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:13: +1:20
-- let mut _7: bool; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
-- let mut _8: u8; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
- scope 1 {
- debug a => _6; // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
- let _6: u8; // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
- }
-
- bb0: {
- StorageLive(_1); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
- StorageLive(_2); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
- Deinit(_2); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
- discriminant(_2) = 0; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
- StorageLive(_3); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
- Deinit(_3); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
- discriminant(_3) = 0; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
- Deinit(_1); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
- (_1.0: std::option::Option<u8>) = move _2; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
- (_1.1: std::option::Option<T>) = move _3; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
- StorageDead(_3); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:68: +1:69
- StorageDead(_2); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:68: +1:69
- _5 = discriminant((_1.0: std::option::Option<u8>)); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
- switchInt(move _5) -> [1: bb1, otherwise: bb3]; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
- }
-
- bb1: {
- _4 = discriminant((_1.1: std::option::Option<T>)); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
- switchInt(move _4) -> [0: bb2, otherwise: bb3]; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
- }
-
- bb2: {
- StorageLive(_6); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
- _6 = (((_1.0: std::option::Option<u8>) as Some).0: u8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
-- StorageLive(_7); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
-- StorageLive(_8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
-- _8 = _6; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
-- _7 = Gt(move _8, const 42_u8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
-- StorageDead(_8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:19: +2:20
-- StorageDead(_7); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+4:9: +4:10
- StorageDead(_6); // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+5:5: +5:6
- goto -> bb3; // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:5: +5:6
- }
-
- bb3: {
- drop(_1) -> bb4; // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:1: +6:2
- }
-
- bb4: {
- StorageDead(_1); // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:1: +6:2
- return; // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:2: +6:2
- }
- }
-
foo::<()>();
}
-// EMIT_MIR simplify_locals_fixedpoint.foo.SimplifyLocals.diff
+// EMIT_MIR simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff
--- /dev/null
+- // MIR for `main` before SimplifyLocals-before-const-prop
++ // MIR for `main` after SimplifyLocals-before-const-prop
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+0:11: +0:11
+- let mut _1: ((), ()); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
+- let mut _2: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:21: +1:23
+- let mut _3: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:25: +1:27
+- let _4: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
+- let mut _5: ((), ()); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
+- let mut _6: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
+- let mut _7: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
+- let _8: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
+- let mut _9: u8; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
+- let mut _10: u8; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
+- let mut _11: Temp; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
++ let _1: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
++ let mut _2: ((), ()); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
++ let mut _3: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
++ let mut _4: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
++ let _5: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
++ let mut _6: u8; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
++ let mut _7: u8; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
++ let mut _8: Temp; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
+ scope 1 {
+ }
+
+ bb0: {
+- StorageLive(_1); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
+- StorageLive(_2); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:21: +1:23
+- Deinit(_2); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:21: +1:23
+- StorageLive(_3); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:25: +1:27
+- Deinit(_3); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:25: +1:27
+- Deinit(_1); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
+- (_1.0: ()) = move _2; // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
+- (_1.1: ()) = move _3; // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
+- StorageDead(_3); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:27: +1:28
+- StorageDead(_2); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:27: +1:28
+- StorageDead(_1); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:28: +1:29
+- StorageLive(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
+- StorageLive(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
+- StorageLive(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
+- Deinit(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
+- StorageLive(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
+- Deinit(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
+- Deinit(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
+- (_5.0: ()) = move _6; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
+- (_5.1: ()) = move _7; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
+- StorageDead(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
+- StorageDead(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
+- _4 = use_zst(move _5) -> bb1; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
++ StorageLive(_1); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
++ StorageLive(_2); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
++ StorageLive(_3); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
++ Deinit(_3); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
++ StorageLive(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
++ Deinit(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
++ Deinit(_2); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
++ (_2.0: ()) = move _3; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
++ (_2.1: ()) = move _4; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
++ StorageDead(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
++ StorageDead(_3); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
++ _1 = use_zst(move _2) -> bb1; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
+ // mir::Constant
+ // + span: $DIR/simplify_locals_removes_unused_consts.rs:15:5: 15:12
+ // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+- StorageDead(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:21: +2:22
+- StorageDead(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:22: +2:23
+- StorageLive(_8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
+- StorageLive(_9); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
+- StorageLive(_10); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
+- StorageLive(_11); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
+- Deinit(_11); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
+- (_11.0: u8) = const 40_u8; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
+- _10 = (_11.0: u8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
+- _9 = Add(move _10, const 2_u8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
+- StorageDead(_10); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:33: +4:34
+- _8 = use_u8(move _9) -> bb2; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
++ StorageDead(_2); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:21: +2:22
++ StorageDead(_1); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:22: +2:23
++ StorageLive(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
++ StorageLive(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
++ StorageLive(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
++ StorageLive(_8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
++ Deinit(_8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
++ (_8.0: u8) = const 40_u8; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
++ _7 = (_8.0: u8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
++ _6 = Add(move _7, const 2_u8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
++ StorageDead(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:33: +4:34
++ _5 = use_u8(move _6) -> bb2; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
+ // mir::Constant
+ // + span: $DIR/simplify_locals_removes_unused_consts.rs:17:5: 17:11
+ // + literal: Const { ty: fn(u8) {use_u8}, val: Value(<ZST>) }
+ }
+
+ bb2: {
+- StorageDead(_9); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:34: +4:35
+- StorageDead(_11); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
++ StorageDead(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:34: +4:35
+ StorageDead(_8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
++ StorageDead(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
+ _0 = const (); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+0:11: +5:2
+ return; // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+5:2: +5:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `main` before SimplifyLocals
-+ // MIR for `main` after SimplifyLocals
-
- fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+0:11: +0:11
-- let mut _1: ((), ()); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
-- let mut _2: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:21: +1:23
-- let mut _3: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:25: +1:27
-- let _4: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
-- let mut _5: ((), ()); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
-- let mut _6: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
-- let mut _7: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
-- let _8: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
-- let mut _9: u8; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
-- let mut _10: u8; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
-- let mut _11: Temp; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
-+ let _1: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
-+ let mut _2: ((), ()); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
-+ let mut _3: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
-+ let mut _4: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
-+ let _5: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
-+ let mut _6: u8; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
-+ let mut _7: u8; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
-+ let mut _8: Temp; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
- scope 1 {
- }
-
- bb0: {
-- StorageLive(_1); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
-- StorageLive(_2); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:21: +1:23
-- Deinit(_2); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:21: +1:23
-- StorageLive(_3); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:25: +1:27
-- Deinit(_3); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:25: +1:27
-- Deinit(_1); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
-- (_1.0: ()) = move _2; // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
-- (_1.1: ()) = move _3; // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
-- StorageDead(_3); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:27: +1:28
-- StorageDead(_2); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:27: +1:28
-- StorageDead(_1); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:28: +1:29
-- StorageLive(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
-- StorageLive(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
-- StorageLive(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
-- Deinit(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
-- StorageLive(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
-- Deinit(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
-- Deinit(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
-- (_5.0: ()) = move _6; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
-- (_5.1: ()) = move _7; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
-- StorageDead(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
-- StorageDead(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
-- _4 = use_zst(move _5) -> bb1; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
-+ StorageLive(_1); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
-+ StorageLive(_2); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
-+ StorageLive(_3); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
-+ Deinit(_3); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
-+ StorageLive(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
-+ Deinit(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
-+ Deinit(_2); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
-+ (_2.0: ()) = move _3; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
-+ (_2.1: ()) = move _4; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
-+ StorageDead(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
-+ StorageDead(_3); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
-+ _1 = use_zst(move _2) -> bb1; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
- // mir::Constant
- // + span: $DIR/simplify_locals_removes_unused_consts.rs:15:5: 15:12
- // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(<ZST>) }
- }
-
- bb1: {
-- StorageDead(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:21: +2:22
-- StorageDead(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:22: +2:23
-- StorageLive(_8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
-- StorageLive(_9); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
-- StorageLive(_10); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
-- StorageLive(_11); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
-- Deinit(_11); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
-- (_11.0: u8) = const 40_u8; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
-- _10 = (_11.0: u8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
-- _9 = Add(move _10, const 2_u8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
-- StorageDead(_10); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:33: +4:34
-- _8 = use_u8(move _9) -> bb2; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
-+ StorageDead(_2); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:21: +2:22
-+ StorageDead(_1); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:22: +2:23
-+ StorageLive(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
-+ StorageLive(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
-+ StorageLive(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
-+ StorageLive(_8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
-+ Deinit(_8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
-+ (_8.0: u8) = const 40_u8; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
-+ _7 = (_8.0: u8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
-+ _6 = Add(move _7, const 2_u8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
-+ StorageDead(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:33: +4:34
-+ _5 = use_u8(move _6) -> bb2; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
- // mir::Constant
- // + span: $DIR/simplify_locals_removes_unused_consts.rs:17:5: 17:11
- // + literal: Const { ty: fn(u8) {use_u8}, val: Value(<ZST>) }
- }
-
- bb2: {
-- StorageDead(_9); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:34: +4:35
-- StorageDead(_11); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
-+ StorageDead(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:34: +4:35
- StorageDead(_8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
-+ StorageDead(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
- _0 = const (); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+0:11: +5:2
- return; // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+5:2: +5:2
- }
- }
-
-// unit-test: SimplifyLocals
+// unit-test: SimplifyLocals-before-const-prop
// compile-flags: -C overflow-checks=no
fn use_zst(_: ((), ())) {}
fn use_u8(_: u8) {}
-// EMIT_MIR simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
+// EMIT_MIR simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.diff
fn main() {
let ((), ()) = ((), ());
use_zst(((), ()));
--- /dev/null
+- // MIR for `map` before SimplifyLocals-before-const-prop
++ // MIR for `map` after SimplifyLocals-before-const-prop
+
+ fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
+ debug x => _1; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+0:8: +0:9
+ let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+0:31: +0:46
+ let mut _2: isize; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:9: +2:13
+ let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
+ let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:25: +3:26
+- let mut _5: bool; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
+- let mut _6: isize; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
+- let mut _7: isize; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
+ scope 1 {
+ debug x => _3; // in scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
+ }
+
+ bb0: {
+- _5 = const false; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
+- _5 = const true; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
+ _2 = discriminant(_1); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
+ switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:5: +1:12
+ }
+
+ bb1: {
+ StorageLive(_3); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
+ _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
+ StorageLive(_4); // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:25: +3:26
+ _4 = move _3; // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:25: +3:26
+ Deinit(_0); // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:20: +3:27
+ ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:20: +3:27
+ discriminant(_0) = 1; // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:20: +3:27
+ StorageDead(_4); // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:26: +3:27
+ StorageDead(_3); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:26: +3:27
+ goto -> bb4; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:26: +3:27
+ }
+
+ bb2: {
+ unreachable; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
+ }
+
+ bb3: {
+ Deinit(_0); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
+ discriminant(_0) = 0; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
+ goto -> bb4; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
+ }
+
+ bb4: {
+- _6 = discriminant(_1); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
+ return; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:2: +5:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `map` before SimplifyLocals
-+ // MIR for `map` after SimplifyLocals
-
- fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
- debug x => _1; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+0:8: +0:9
- let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+0:31: +0:46
- let mut _2: isize; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:9: +2:13
- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:25: +3:26
-- let mut _5: bool; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
-- let mut _6: isize; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
-- let mut _7: isize; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
- scope 1 {
- debug x => _3; // in scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
- }
-
- bb0: {
-- _5 = const false; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
-- _5 = const true; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
- _2 = discriminant(_1); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
- switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:5: +1:12
- }
-
- bb1: {
- StorageLive(_3); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
- _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
- StorageLive(_4); // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:25: +3:26
- _4 = move _3; // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:25: +3:26
- Deinit(_0); // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:20: +3:27
- ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:20: +3:27
- discriminant(_0) = 1; // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:20: +3:27
- StorageDead(_4); // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:26: +3:27
- StorageDead(_3); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:26: +3:27
- goto -> bb4; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:26: +3:27
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
- }
-
- bb3: {
- Deinit(_0); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
- discriminant(_0) = 0; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
- goto -> bb4; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
- }
-
- bb4: {
-- _6 = discriminant(_1); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
- return; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:2: +5:2
- }
- }
-
-// unit-test: SimplifyLocals
+// unit-test: SimplifyLocals-before-const-prop
fn map(x: Option<Box<()>>) -> Option<Box<()>> {
match x {
map(None);
}
-// EMIT_MIR simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff
+// EMIT_MIR simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals-before-const-prop.diff
}
bb1: {
- nop; // scope 0 at $DIR/simplify_match.rs:+3:18: +3:20
goto -> bb3; // scope 0 at $DIR/simplify_match.rs:+3:18: +3:20
}
--- /dev/null
+// MIR for `process_never` after SimplifyLocals-final
+
+fn process_never(_1: *const !) -> () {
+ debug input => _1; // in scope 0 at $DIR/uninhabited_enum.rs:+0:22: +0:27
+ let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum.rs:+0:39: +0:39
+ let _2: &!; // in scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
+ scope 1 {
+ debug _input => _2; // in scope 1 at $DIR/uninhabited_enum.rs:+1:8: +1:14
+ }
+ scope 2 {
+ }
+
+ bb0: {
+ unreachable; // scope 0 at $DIR/uninhabited_enum.rs:+0:39: +2:2
+ }
+}
+++ /dev/null
-// MIR for `process_never` after SimplifyLocals
-
-fn process_never(_1: *const !) -> () {
- debug input => _1; // in scope 0 at $DIR/uninhabited_enum.rs:+0:22: +0:27
- let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum.rs:+0:39: +0:39
- let _2: &!; // in scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
- scope 1 {
- debug _input => _2; // in scope 1 at $DIR/uninhabited_enum.rs:+1:8: +1:14
- }
- scope 2 {
- }
-
- bb0: {
- unreachable; // scope 0 at $DIR/uninhabited_enum.rs:+0:39: +2:2
- }
-}
--- /dev/null
+// MIR for `process_void` after SimplifyLocals-final
+
+fn process_void(_1: *const Void) -> () {
+ debug input => _1; // in scope 0 at $DIR/uninhabited_enum.rs:+0:21: +0:26
+ let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum.rs:+0:41: +0:41
+ let _2: &Void; // in scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
+ scope 1 {
+ debug _input => _2; // in scope 1 at $DIR/uninhabited_enum.rs:+1:8: +1:14
+ }
+ scope 2 {
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
+ StorageDead(_2); // scope 0 at $DIR/uninhabited_enum.rs:+4:1: +4:2
+ return; // scope 0 at $DIR/uninhabited_enum.rs:+4:2: +4:2
+ }
+}
+++ /dev/null
-// MIR for `process_void` after SimplifyLocals
-
-fn process_void(_1: *const Void) -> () {
- debug input => _1; // in scope 0 at $DIR/uninhabited_enum.rs:+0:21: +0:26
- let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum.rs:+0:41: +0:41
- let _2: &Void; // in scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
- scope 1 {
- debug _input => _2; // in scope 1 at $DIR/uninhabited_enum.rs:+1:8: +1:14
- }
- scope 2 {
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
- StorageDead(_2); // scope 0 at $DIR/uninhabited_enum.rs:+4:1: +4:2
- return; // scope 0 at $DIR/uninhabited_enum.rs:+4:2: +4:2
- }
-}
pub enum Void {}
-// EMIT_MIR uninhabited_enum.process_never.SimplifyLocals.after.mir
+// EMIT_MIR uninhabited_enum.process_never.SimplifyLocals-final.after.mir
#[no_mangle]
pub fn process_never(input: *const !) {
let _input = unsafe { &*input };
}
-// EMIT_MIR uninhabited_enum.process_void.SimplifyLocals.after.mir
+// EMIT_MIR uninhabited_enum.process_void.SimplifyLocals-final.after.mir
#[no_mangle]
pub fn process_void(input: *const Void) {
let _input = unsafe { &*input };
fn change_loop_body() -> () {
let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
- let mut _2: (); // in scope 0 at $DIR/while_let_loops.rs:+0:1: +6:2
- let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
- let mut _4: isize; // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
- let mut _5: !; // in scope 0 at $DIR/while_let_loops.rs:+2:33: +5:6
- let mut _6: !; // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
- let _7: (); // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
- let mut _8: !; // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
+ let mut _2: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
+ let mut _3: isize; // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
scope 1 {
debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
scope 2 {
bb0: {
StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
_1 = const 0_i32; // scope 0 at $DIR/while_let_loops.rs:+1:18: +1:19
- StorageLive(_3); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
- Deinit(_3); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
- discriminant(_3) = 0; // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-- _4 = discriminant(_3); // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-- switchInt(move _4) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+ _4 = const 0_isize; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+ StorageLive(_2); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
+ Deinit(_2); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
+ discriminant(_2) = 0; // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
+- _3 = discriminant(_2); // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+- switchInt(move _3) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
++ _3 = const 0_isize; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+ switchInt(const 0_isize) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
}
bb1: {
- switchInt(((_3 as Some).0: u32)) -> [0: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+ switchInt(((_2 as Some).0: u32)) -> [0: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
}
bb2: {
_1 = const 1_i32; // scope 2 at $DIR/while_let_loops.rs:+3:9: +3:15
- nop; // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
goto -> bb4; // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
}
bb3: {
- StorageLive(_7); // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
- nop; // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
- StorageDead(_7); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
goto -> bb4; // scope 1 at no-location
}
bb4: {
- StorageDead(_3); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
+ StorageDead(_2); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
return; // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
}
bb5: {
StorageDead(_4); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
- goto -> bb8; // scope 0 at no-location
+ goto -> bb7; // scope 0 at no-location
}
bb6: {
}
bb7: {
- goto -> bb8; // scope 0 at no-location
- }
-
- bb8: {
StorageDead(_2); // scope 0 at $DIR/while_storage.rs:+5:5: +5:6
return; // scope 0 at $DIR/while_storage.rs:+6:2: +6:2
}
extern crate rustc_graphviz;
// A simple rust project
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
extern crate krate2;
extern crate krate2 as krate3;
--- /dev/null
+include ../../run-make-fulldeps/tools.mk
+
+all:
+ $(RUSTC) --crate-type lib foo.rs -Z dump-mono-stats=$(TMPDIR) -Zdump-mono-stats-format=json
+ cat $(TMPDIR)/foo.mono_items.json | $(CGREP) '"name":"bar"'
--- /dev/null
+pub fn bar() {}
define-function: (
"check-colors",
(theme, main_color, title_color, fqn_color, fqn_type_color, src_link_color, sidebar_link_color),
- [
- ("goto", "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"),
+ block {
+ goto: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
// This is needed to ensure that the text color is computed.
- ("show-text", true),
+ show-text: true
// Setting the theme.
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
// We reload the page so the local storage settings are being used.
- ("reload"),
+ reload:
- ("assert-css", ("#toggle-all-docs", {"color": |main_color|})),
- ("assert-css", (".fqn a:nth-of-type(1)", {"color": |fqn_color|})),
- ("assert-css", (".fqn a:nth-of-type(2)", {"color": |fqn_type_color|})),
- ("assert-css", (
+ assert-css: ("#toggle-all-docs", {"color": |main_color|})
+ assert-css: (".fqn a:nth-of-type(1)", {"color": |fqn_color|})
+ assert-css: (".fqn a:nth-of-type(2)", {"color": |fqn_type_color|})
+ assert-css: (
".rightside .srclink",
{"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|},
ALL,
- )),
- (
- "compare-elements-css",
- (".rightside .srclink", ".rightside.srclink", ["color", "text-decoration"]),
- ),
- (
- "compare-elements-css",
- (".main-heading .srclink", ".rightside.srclink", ["color", "text-decoration"]),
- ),
+ )
+ compare-elements-css: (
+ ".rightside .srclink",
+ ".rightside.srclink",
+ ["color", "text-decoration"],
+ )
+ compare-elements-css: (
+ ".main-heading .srclink",
+ ".rightside.srclink",
+ ["color", "text-decoration"],
+ )
- ("move-cursor-to", ".main-heading .srclink"),
- ("assert-css", (
+ move-cursor-to: ".main-heading .srclink"
+ assert-css: (
".main-heading .srclink",
{"color": |src_link_color|, "text-decoration": "underline solid " + |src_link_color|},
- )),
- ("move-cursor-to", ".impl-items .rightside .srclink"),
- ("assert-css", (
+ )
+ move-cursor-to: ".impl-items .rightside .srclink"
+ assert-css: (
".impl-items .rightside .srclink",
{"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|},
- )),
- ("move-cursor-to", ".impl-items .rightside.srclink"),
- ("assert-css", (
+ )
+ move-cursor-to: ".impl-items .rightside.srclink"
+ assert-css: (
".impl-items .rightside.srclink",
{"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|},
- )),
+ )
- ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"),
+ goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
// Since we changed page, we need to set the theme again.
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
// We reload the page so the local storage settings are being used.
- ("reload"),
+ reload:
- ("assert-css", ("#top-doc-prose-title", {"color": |title_color|})),
+ assert-css: ("#top-doc-prose-title", {"color": |title_color|})
- ("assert-css", (".sidebar a", {"color": |sidebar_link_color|})),
- ("assert-css", ("h1.fqn a", {"color": |title_color|})),
+ assert-css: (".sidebar a", {"color": |sidebar_link_color|})
+ assert-css: ("h1.fqn a", {"color": |title_color|})
// We move the cursor over the "Implementations" title so the anchor is displayed.
- ("move-cursor-to", "h2#implementations"),
- ("assert-css", ("h2#implementations a.anchor", {"color": |main_color|})),
+ move-cursor-to: "h2#implementations"
+ assert-css: ("h2#implementations a.anchor", {"color": |main_color|})
// Same thing with the impl block title.
- ("move-cursor-to", "#impl-HeavilyDocumentedStruct"),
- ("assert-css", ("#impl-HeavilyDocumentedStruct a.anchor", {"color": |main_color|})),
+ move-cursor-to: "#impl-HeavilyDocumentedStruct"
+ assert-css: ("#impl-HeavilyDocumentedStruct a.anchor", {"color": |main_color|})
- ("assert-css", ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})),
- ],
+ assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})
+ },
)
call-function: (
define-function: (
"check-colors",
(theme, doc_code_color, doc_inline_code_color),
- [
+ block {
// Set the theme.
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
// We reload the page so the local storage settings are being used.
- ("reload"),
- ("assert-css", (".docblock pre > code", {"color": |doc_code_color|}, ALL)),
- ("assert-css", (".docblock > p > code", {"color": |doc_inline_code_color|}, ALL)),
- ],
+ reload:
+ assert-css: (".docblock pre > code", {"color": |doc_code_color|}, ALL)
+ assert-css: (".docblock > p > code", {"color": |doc_inline_code_color|}, ALL)
+ },
)
call-function: ("check-colors", ("ayu", "rgb(230, 225, 207)", "rgb(255, 180, 84)"))
define-function: (
"check-colors",
(theme, background, color, border),
- [
+ block {
// Setting the theme.
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
// compile_fail block
- ("assert-css", (
+ assert-css: (
".docblock .example-wrap.compile_fail .tooltip",
{"color": "rgba(255, 0, 0, 0.5)"},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".docblock .example-wrap.compile_fail",
{"border-left": "2px solid rgba(255, 0, 0, 0.5)"},
- )),
+ )
- ("move-cursor-to", ".docblock .example-wrap.compile_fail .tooltip"),
+ move-cursor-to: ".docblock .example-wrap.compile_fail .tooltip"
- ("assert-css", (
+ assert-css: (
".docblock .example-wrap.compile_fail .tooltip",
{"color": "rgb(255, 0, 0)"},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".docblock .example-wrap.compile_fail",
{"border-left": "2px solid rgb(255, 0, 0)"},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".docblock .example-wrap.compile_fail .tooltip::after",
{
"content": '"This example deliberately fails to compile"',
- "text-align": "center",
"padding": "5px 3px 3px",
"background-color": |background|,
"color": |color|,
"border": "1px solid " + |border|,
},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".docblock .example-wrap.compile_fail .tooltip::before",
{
"border-width": "5px",
"border-style": "solid",
"border-color": "rgba(0, 0, 0, 0) " + |background| + " rgba(0, 0, 0, 0) rgba(0, 0, 0, 0)",
},
- )),
+ )
// should_panic block
- ("assert-css", (
+ assert-css: (
".docblock .example-wrap.should_panic .tooltip",
{"color": "rgba(255, 0, 0, 0.5)"},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".docblock .example-wrap.should_panic",
{"border-left": "2px solid rgba(255, 0, 0, 0.5)"},
- )),
+ )
- ("move-cursor-to", ".docblock .example-wrap.should_panic .tooltip"),
+ move-cursor-to: ".docblock .example-wrap.should_panic .tooltip"
- ("assert-css", (
+ assert-css: (
".docblock .example-wrap.should_panic .tooltip",
{"color": "rgb(255, 0, 0)"},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".docblock .example-wrap.should_panic",
{"border-left": "2px solid rgb(255, 0, 0)"},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".docblock .example-wrap.should_panic .tooltip::after",
{
"content": '"This example panics"',
- "text-align": "center",
"padding": "5px 3px 3px",
"background-color": |background|,
"color": |color|,
"border": "1px solid " + |border|,
},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".docblock .example-wrap.should_panic .tooltip::before",
{
"border-width": "5px",
"border-style": "solid",
"border-color": "rgba(0, 0, 0, 0) " + |background| + " rgba(0, 0, 0, 0) rgba(0, 0, 0, 0)",
},
- )),
+ )
// ignore block
- ("assert-css", (
+ assert-css: (
".docblock .example-wrap.ignore .tooltip",
{"color": "rgba(255, 142, 0, 0.6)"},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".docblock .example-wrap.ignore",
{"border-left": "2px solid rgba(255, 142, 0, 0.6)"},
- )),
+ )
- ("move-cursor-to", ".docblock .example-wrap.ignore .tooltip"),
+ move-cursor-to: ".docblock .example-wrap.ignore .tooltip"
- ("assert-css", (
+ assert-css: (
".docblock .example-wrap.ignore .tooltip",
{"color": "rgb(255, 142, 0)"},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".docblock .example-wrap.ignore",
{"border-left": "2px solid rgb(255, 142, 0)"},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".docblock .example-wrap.ignore .tooltip::after",
{
"content": '"This example is not tested"',
- "text-align": "center",
"padding": "5px 3px 3px",
"background-color": |background|,
"color": |color|,
"border": "1px solid " + |border|,
},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".docblock .example-wrap.ignore .tooltip::before",
{
"border-width": "5px",
"border-style": "solid",
"border-color": "rgba(0, 0, 0, 0) " + |background| + " rgba(0, 0, 0, 0) rgba(0, 0, 0, 0)",
},
- )),
- ],
+ )
+ },
)
call-function: ("check-colors", {
define-function: (
"check-colors",
(theme, color),
- [
+ block {
// We now set the setting to show the line numbers on code examples.
- ("local-storage", {
+ local-storage: {
"rustdoc-theme": |theme|,
"rustdoc-use-system-theme": "false",
"rustdoc-line-numbers": "true"
- }),
+ }
// We reload to make the line numbers appear and change theme.
- ("reload"),
+ reload:
// We wait for them to be added into the DOM by the JS...
- ("wait-for", "pre.example-line-numbers"),
+ wait-for: "pre.example-line-numbers"
// If the test didn't fail, it means that it was found!
- ("assert-css", (
+ assert-css: (
"pre.example-line-numbers",
{
"color": |color|,
"text-align": "right",
},
ALL,
- )),
- ],
+ )
+ },
)
call-function: ("check-colors", {
"theme": "ayu",
+// This test checks the appearance of the tables in the doc comments.
goto: "file://" + |DOC_PATH| + "/test_docs/doc_block_table/struct.DocBlockTable.html#method.func"
compare-elements-css: (".impl-items .docblock table th", ".top-doc .docblock table th", ["border"])
define-function: (
"check-colors",
(theme, border_color, zebra_stripe_color),
- [
- ("local-storage", {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}),
- ("reload"),
- ("assert-css", (".top-doc .docblock table tbody tr:nth-child(1)", {
+ block {
+ local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
+ reload:
+ assert-css: (".top-doc .docblock table tbody tr:nth-child(1)", {
"background-color": "rgba(0, 0, 0, 0)",
- })),
- ("assert-css", (".top-doc .docblock table tbody tr:nth-child(2)", {
+ })
+ assert-css: (".top-doc .docblock table tbody tr:nth-child(2)", {
"background-color": |zebra_stripe_color|,
- })),
- ("assert-css", (".top-doc .docblock table tbody tr:nth-child(3)", {
+ })
+ assert-css: (".top-doc .docblock table tbody tr:nth-child(3)", {
"background-color": "rgba(0, 0, 0, 0)",
- })),
- ("assert-css", (".top-doc .docblock table tbody tr:nth-child(4)", {
+ })
+ assert-css: (".top-doc .docblock table tbody tr:nth-child(4)", {
"background-color": |zebra_stripe_color|,
- })),
- ("assert-css", (".top-doc .docblock table td", {
+ })
+ assert-css: (".top-doc .docblock table td", {
"border-style": "solid",
"border-width": "1px",
"border-color": |border_color|,
- })),
- ("assert-css", (".top-doc .docblock table th", {
+ })
+ assert-css: (".top-doc .docblock table th", {
"border-style": "solid",
"border-width": "1px",
"border-color": |border_color|,
- })),
- ]
+ })
+ }
)
call-function: ("check-colors", {
write: (".search-input", "test")
// To be SURE that the search will be run.
press-key: 'Enter'
-wait-for: "#search h1" // The search element is empty before the first search
+wait-for: "#search h1" // The search element is empty before the first search
// Check that the currently displayed element is search.
wait-for: "#alternative-display #search"
assert-attribute: ("#main-content", {"class": "content hidden"})
define-function: (
"check-colors",
(theme, color, code_header_color, focus_background_color, headings_color),
- [
- ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"),
+ block {
+ goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
// This is needed so that the text color is computed.
- ("show-text", true),
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
- ("assert-css", (
+ show-text: true
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
+ assert-css: (
".impl",
{"color": |color|, "background-color": "rgba(0, 0, 0, 0)"},
ALL,
- )),
- ("assert-css", (
+ )
+ assert-css: (
".impl .code-header",
{"color": |code_header_color|, "background-color": "rgba(0, 0, 0, 0)"},
ALL,
- )),
- ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#impl-Foo"),
- ("assert-css", (
+ )
+ goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#impl-Foo"
+ assert-css: (
"#impl-Foo",
{"color": |color|, "background-color": |focus_background_color|},
- )),
- ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#method.must_use"),
- ("assert-css", (
+ )
+ goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#method.must_use"
+ assert-css: (
"#method\.must_use",
{"color": |color|, "background-color": |focus_background_color|},
ALL,
- )),
- ("goto", "file://" + |DOC_PATH| + "/test_docs/index.html"),
- ("assert-css", (".small-section-header a", {"color": |color|}, ALL)),
- ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"),
+ )
+ goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
+ assert-css: (".small-section-header a", {"color": |color|}, ALL)
+ goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
// We select headings (h2, h3, h...).
- ("assert-css", (".docblock > :not(p) > a", {"color": |headings_color|}, ALL)),
- ],
+ assert-css: (".docblock > :not(p) > a", {"color": |headings_color|}, ALL)
+ },
)
call-function: (
define-function: (
"check-colors",
(theme, heading_color, small_heading_color, heading_border_color),
- [
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
- ("assert-css", (
+ block {
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
+ assert-css: (
".top-doc .docblock h2",
{"color": |heading_color|, "border-bottom": "1px solid " + |heading_border_color|},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".top-doc .docblock h3",
{"color": |heading_color|, "border-bottom": "1px solid " + |heading_border_color|},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".top-doc .docblock h4",
{"color": |heading_color|, "border-bottom": "1px solid " + |heading_border_color|},
- )),
- ("assert-css", (
+ )
+ assert-css: (
".top-doc .docblock h5",
{"color": |small_heading_color|, "border-bottom-width": "0px"},
- )),
- ("assert-css", (
+ )
+ assert-css: (
"#implementations-list .docblock h4",
{"color": |heading_color|, "border-bottom-width": "0px"},
- )),
- ("assert-css", (
+ )
+ assert-css: (
"#implementations-list .docblock h5",
{"color": |small_heading_color|, "border-bottom-width": "0px"},
- )),
- ("assert-css", (
+ )
+ assert-css: (
"#implementations-list .docblock h6",
{"color": |small_heading_color|, "border-bottom-width": "0px"},
- )),
- ],
+ )
+ },
)
call-function: (
"check-colors",
define-function: (
"check-since-color",
(theme),
- [
- ("local-storage", {"rustdoc-theme": |theme|}),
- ("reload"),
- ("assert-css", (".since", {"color": "rgb(128, 128, 128)"}, ALL)),
- ],
+ block {
+ local-storage: {"rustdoc-theme": |theme|}
+ reload:
+ assert-css: (".since", {"color": "rgb(128, 128, 128)"}, ALL)
+ },
)
goto: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
define-function: (
"check-colors",
(theme, color, background, box_shadow),
- [
+ block {
// Setting the theme.
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
// We reload the page so the local storage settings are being used.
- ("reload"),
- ("assert-css", ("#help kbd", {
+ reload:
+ assert-css: ("#help kbd", {
"color": |color|,
"background-color": |background|,
"box-shadow": |box_shadow| + " 0px -1px 0px 0px inset",
- }, ALL)),
- ],
+ }, ALL)
+ },
)
call-function: ("check-colors", {
})
call-function: ("check-colors", {
"theme": "dark",
- "color": "rgb(221, 221, 221)",
+ "color": "rgb(0, 0, 0)",
"background": "rgb(250, 251, 252)",
"box_shadow": "rgb(198, 203, 209)",
})
assert-css: ("#help", {"display": "none"})
compare-elements-property-false: (".sub", "#help", ["offsetWidth"])
compare-elements-position-false: (".sub", "#help", ("x"))
+
+// This test ensures that the "the rustdoc book" anchor link within the help popover works.
+goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
+size: (1000, 1000) // Popover only appears when the screen width is >700px.
+assert-false: "#help"
+click: "#help-button > a"
+click: ".popover a[href='https://doc.rust-lang.org/rustdoc/']"
+wait-for: 2000
+assert-document-property: {"URL": "https://doc.rust-lang.org/rustdoc/"}
comment,
doc_comment,
),
- [
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
- ("assert-css", ("pre.rust .kw", {"color": |kw|}, ALL)),
- ("assert-css", ("pre.rust .kw-2", {"color": |kw2|}, ALL)),
- ("assert-css", ("pre.rust .prelude-ty", {"color": |prelude_ty|}, ALL)),
- ("assert-css", ("pre.rust .prelude-val", {"color": |prelude_val|}, ALL)),
- ("assert-css", ("pre.rust .lifetime", {"color": |lifetime|}, ALL)),
- ("assert-css", ("pre.rust .number", {"color": |number|}, ALL)),
- ("assert-css", ("pre.rust .string", {"color": |string|}, ALL)),
- ("assert-css", ("pre.rust .bool-val", {"color": |bool_val|}, ALL)),
- ("assert-css", ("pre.rust .self", {"color": |self|}, ALL)),
- ("assert-css", ("pre.rust .attr", {"color": |attr|}, ALL)),
- ("assert-css", ("pre.rust .macro", {"color": |macro|}, ALL)),
- ("assert-css", ("pre.rust .question-mark", {"color": |question_mark|}, ALL)),
- ("assert-css", ("pre.rust .comment", {"color": |comment|}, ALL)),
- ("assert-css", ("pre.rust .doccomment", {"color": |doc_comment|}, ALL)),
- ],
+ block {
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
+ assert-css: ("pre.rust .kw", {"color": |kw|}, ALL)
+ assert-css: ("pre.rust .kw-2", {"color": |kw2|}, ALL)
+ assert-css: ("pre.rust .prelude-ty", {"color": |prelude_ty|}, ALL)
+ assert-css: ("pre.rust .prelude-val", {"color": |prelude_val|}, ALL)
+ assert-css: ("pre.rust .lifetime", {"color": |lifetime|}, ALL)
+ assert-css: ("pre.rust .number", {"color": |number|}, ALL)
+ assert-css: ("pre.rust .string", {"color": |string|}, ALL)
+ assert-css: ("pre.rust .bool-val", {"color": |bool_val|}, ALL)
+ assert-css: ("pre.rust .self", {"color": |self|}, ALL)
+ assert-css: ("pre.rust .attr", {"color": |attr|}, ALL)
+ assert-css: ("pre.rust .macro", {"color": |macro|}, ALL)
+ assert-css: ("pre.rust .question-mark", {"color": |question_mark|}, ALL)
+ assert-css: ("pre.rust .comment", {"color": |comment|}, ALL)
+ assert-css: ("pre.rust .doccomment", {"color": |doc_comment|}, ALL)
+ },
)
call-function: ("check-colors", {
// The text is about 24px tall, so if there's a margin, then their position will be >24px apart
compare-elements-position-near-false: (
- "#implementations-list > .implementors-toggle > .docblock > p",
- "#implementations-list > .implementors-toggle > .impl-items",
- {"y": 24}
+ "#implementations-list > .implementors-toggle > .docblock > p",
+ "#implementations-list > .implementors-toggle > .impl-items",
+ {"y": 24}
)
assert-count: ("#implementors-list .impl", 1)
goto: "file://" + |DOC_PATH| + "/implementors/trait.TraitToReexport.html"
assert-count: ("#implementors-list .impl", 1)
+
+// Now check that the link is properly rewritten for a crate called `http`.
+// An older version of rustdoc had a buggy check for absolute links.
+goto: "file://" + |DOC_PATH| + "/http/trait.HttpTrait.html"
+assert-count: ("#implementors-list .impl", 1)
+assert-attribute: ("#implementors-list .impl a.trait", {"href": "../http/trait.HttpTrait.html"})
fn_color,
assoc_type_color,
),
- [
- ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.WithGenerics.html"),
- ("show-text", true),
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
- ("assert-css", (".item-decl .code-attribute", {"color": |attr_color|}, ALL)),
- ("assert-css", (".item-decl .trait", {"color": |trait_color|}, ALL)),
+ block {
+ goto: "file://" + |DOC_PATH| + "/test_docs/struct.WithGenerics.html"
+ show-text: true
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
+ assert-css: (".item-decl .code-attribute", {"color": |attr_color|}, ALL)
+ assert-css: (".item-decl .trait", {"color": |trait_color|}, ALL)
// We need to add `code` here because otherwise it would select the parent too.
- ("assert-css", (".item-decl code .struct", {"color": |struct_color|}, ALL)),
- ("assert-css", (".item-decl .enum", {"color": |enum_color|}, ALL)),
- ("assert-css", (".item-decl .primitive", {"color": |primitive_color|}, ALL)),
- ("goto", "file://" + |DOC_PATH| + "/test_docs/trait.TraitWithoutGenerics.html"),
- ("assert-css", (".item-decl .constant", {"color": |constant_color|}, ALL)),
- ("assert-css", (".item-decl .fn", {"color": |fn_color|}, ALL)),
- ("assert-css", (".item-decl .associatedtype", {"color": |assoc_type_color|}, ALL)),
- ],
+ assert-css: (".item-decl code .struct", {"color": |struct_color|}, ALL)
+ assert-css: (".item-decl .enum", {"color": |enum_color|}, ALL)
+ assert-css: (".item-decl .primitive", {"color": |primitive_color|}, ALL)
+
+ goto: "file://" + |DOC_PATH| + "/test_docs/trait.TraitWithoutGenerics.html"
+ assert-css: (".item-decl .constant", {"color": |constant_color|}, ALL)
+ assert-css: (".item-decl .fn", {"color": |fn_color|}, ALL)
+ assert-css: (".item-decl .associatedtype", {"color": |assoc_type_color|}, ALL)
+ },
)
call-function: (
define-function: (
"check-background-color",
(theme, background_color),
- [
+ block {
// Set the theme.
- ("local-storage", { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }),
+ local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }
// We reload the page so the local storage settings are being used.
- ("reload"),
- ("assert-css", (
+ reload:
+ assert-css: (
"body.source .example-wrap pre.rust a",
{"background-color": |background_color|},
ALL,
- )),
- ],
+ )
+ },
)
call-function: ("check-background-color", ("ayu", "rgb(51, 51, 51)"))
"check-colors",
(theme, mod, macro, struct, enum, trait, fn, type, union, keyword,
sidebar, sidebar_current, sidebar_current_background),
- [
- ("local-storage", {
+ block {
+ local-storage: {
"rustdoc-theme": |theme|,
"rustdoc-use-system-theme": "false",
- }),
- ("reload"),
+ }
+ reload:
// Checking results colors.
- ("assert-css", (".item-table .mod", {"color": |mod|}, ALL)),
- ("assert-css", (".item-table .macro", {"color": |macro|}, ALL)),
- ("assert-css", (".item-table .struct", {"color": |struct|}, ALL)),
- ("assert-css", (".item-table .enum", {"color": |enum|}, ALL)),
- ("assert-css", (".item-table .trait", {"color": |trait|}, ALL)),
- ("assert-css", (".item-table .fn", {"color": |fn|}, ALL)),
- ("assert-css", (".item-table .type", {"color": |type|}, ALL)),
- ("assert-css", (".item-table .union", {"color": |union|}, ALL)),
- ("assert-css", (".item-table .keyword", {"color": |keyword|}, ALL)),
+ assert-css: (".item-table .mod", {"color": |mod|}, ALL)
+ assert-css: (".item-table .macro", {"color": |macro|}, ALL)
+ assert-css: (".item-table .struct", {"color": |struct|}, ALL)
+ assert-css: (".item-table .enum", {"color": |enum|}, ALL)
+ assert-css: (".item-table .trait", {"color": |trait|}, ALL)
+ assert-css: (".item-table .fn", {"color": |fn|}, ALL)
+ assert-css: (".item-table .type", {"color": |type|}, ALL)
+ assert-css: (".item-table .union", {"color": |union|}, ALL)
+ assert-css: (".item-table .keyword", {"color": |keyword|}, ALL)
// Checking sidebar elements.
- ("assert-css", (
+ assert-css: (
".sidebar-elems a:not(.current)",
{"color": |sidebar|, "background-color": "rgba(0, 0, 0, 0)", "font-weight": "400"},
ALL,
- )),
- ("assert-css", (
+ )
+ assert-css: (
".sidebar-elems a.current",
{
"color": |sidebar_current|,
"font-weight": "500",
},
ALL,
- )),
- ],
+ )
+ },
)
call-function: (
goto: "file://" + |DOC_PATH| + "/settings.html"
size: (400, 600)
// Ignored for now https://github.com/rust-lang/rust/issues/93784.
-// compare-elements-position-near-false: ("#preferred-light-theme .setting-name", "#preferred-light-theme .choice", {"y": 16})
+// compare-elements-position-near-false: (
+// "#preferred-light-theme .setting-name",
+// "#preferred-light-theme .choice",
+// {"y": 16},
+// )
define-function: (
"check-colors",
(theme, header_color, content_color, type_color, trait_color),
- [
- ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html"),
+ block {
+ goto: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html"
// This is needed to ensure that the text color is computed.
- ("show-text", true),
+ show-text: true
// Setting the theme.
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
// We reload the page so the local storage settings are being used.
- ("reload"),
+ reload:
- ("move-cursor-to", "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"),
- ("assert-count", (".notable.popover", 1)),
+ move-cursor-to: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
+ assert-count: (".notable.popover", 1)
- ("assert-css", (
+ assert-css: (
".notable.popover h3",
{"color": |header_color|},
ALL,
- )),
- ("assert-css", (
+ )
+ assert-css: (
".notable.popover pre",
{"color": |content_color|},
ALL,
- )),
- ("assert-css", (
+ )
+ assert-css: (
".notable.popover pre a.struct",
{"color": |type_color|},
ALL,
- )),
- ("assert-css", (
+ )
+ assert-css: (
".notable.popover pre a.trait",
{"color": |trait_color|},
ALL,
- )),
- ]
+ )
+ },
)
call-function: (
define-function: (
"check-run-button",
(theme, color, background, hover_color, hover_background),
- [
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
- ("assert-css", (".test-arrow", {"visibility": "hidden"})),
- ("move-cursor-to", ".example-wrap"),
- ("assert-css", (".test-arrow", {
+ block {
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
+ assert-css: (".test-arrow", {"visibility": "hidden"})
+ move-cursor-to: ".example-wrap"
+ assert-css: (".test-arrow", {
"visibility": "visible",
"color": |color|,
"background-color": |background|,
"font-size": "22px",
"border-radius": "5px",
- })),
- ("move-cursor-to", ".test-arrow"),
- ("assert-css", (".test-arrow:hover", {
+ })
+ move-cursor-to: ".test-arrow"
+ assert-css: (".test-arrow:hover", {
"visibility": "visible",
"color": |hover_color|,
"background-color": |hover_background|,
"font-size": "22px",
"border-radius": "5px",
- })),
- ],
+ })
+ },
)
call-function: ("check-run-button", {
define-function: (
"check-logo",
(theme, filter),
- [
+ block {
// Going to the doc page.
- ("goto", "file://" + |DOC_PATH| + "/test_docs/index.html"),
+ goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
// Changing theme.
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
- ("assert-css", (".rust-logo", {"filter": |filter|})),
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
+ assert-css: (".rust-logo", {"filter": |filter|})
// Going to the source code page.
- ("goto", "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"),
+ goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
// Changing theme (since it's local files, the local storage works by folder).
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
- ("assert-css", (".rust-logo", {"filter": |filter|})),
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
+ assert-css: (".rust-logo", {"filter": |filter|})
// Now we check that the non-rust logos don't have a CSS filter set.
- ("goto", "file://" + |DOC_PATH| + "/huge_logo/index.html"),
+ goto: "file://" + |DOC_PATH| + "/huge_logo/index.html"
// Changing theme on the new page (again...).
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
// Check there is no rust logo
- ("assert-false", ".rust-logo"),
+ assert-false: ".rust-logo"
// Check there is no filter.
- ("assert-css", (".sidebar .logo-container img", {"filter": "none"})),
- ],
+ assert-css: (".sidebar .logo-container img", {"filter": "none"})
+ },
)
call-function: (
"check-logo",
- ("ayu", "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"),
+ {
+ "theme": "ayu",
+ "filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) " +
+ "drop-shadow(rgb(255, 255, 255) 0px 1px 0px) " +
+ "drop-shadow(rgb(255, 255, 255) -1px 0px 0px) " +
+ "drop-shadow(rgb(255, 255, 255) 0px -1px 0px)",
+ },
)
call-function: (
"check-logo",
- ("dark", "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"),
+ {
+ "theme": "dark",
+ "filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) " +
+ "drop-shadow(rgb(255, 255, 255) 0px 1px 0px) " +
+ "drop-shadow(rgb(255, 255, 255) -1px 0px 0px) " +
+ "drop-shadow(rgb(255, 255, 255) 0px -1px 0px)",
+ },
)
call-function: (
"check-logo",
- ("light", "none"),
+ {
+ "theme": "light",
+ "filter": "none",
+ },
)
focus: ".scraped-example-list > .scraped-example .next"
press-key: "Enter"
assert-property-false: (".scraped-example-list > .scraped-example pre", {
- "scrollTop": |initialScrollTop|
+ "scrollTop": |initialScrollTop|
})
focus: ".scraped-example-list > .scraped-example .prev"
press-key: "Enter"
assert-property: (".scraped-example-list > .scraped-example pre", {
- "scrollTop": |initialScrollTop|
+ "scrollTop": |initialScrollTop|
})
// The expand button increases the scrollHeight of the minimized code viewport
store-property: (smallOffsetHeight, ".scraped-example-list > .scraped-example pre", "offsetHeight")
assert-property-false: (".scraped-example-list > .scraped-example pre", {
- "scrollHeight": |smallOffsetHeight|
+ "scrollHeight": |smallOffsetHeight|
})
focus: ".scraped-example-list > .scraped-example .expand"
press-key: "Enter"
assert-property-false: (".scraped-example-list > .scraped-example pre", {
- "offsetHeight": |smallOffsetHeight|
+ "offsetHeight": |smallOffsetHeight|
})
store-property: (fullOffsetHeight, ".scraped-example-list > .scraped-example pre", "offsetHeight")
assert-property: (".scraped-example-list > .scraped-example pre", {
- "scrollHeight": |fullOffsetHeight|
+ "scrollHeight": |fullOffsetHeight|
})
--- /dev/null
+// Check that scrape example code blocks have the expected colors.
+goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html"
+show-text: true
+
+define-function: (
+ "check-colors",
+ (theme, highlight, highlight_focus, help_border, help_color, help_hover_border,
+ help_hover_color),
+ block {
+ local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", }
+ reload:
+ wait-for: ".more-examples-toggle"
+ assert-css: (".scraped-example .example-wrap .rust span.highlight:not(.focus)", {
+ "background-color": |highlight|,
+ }, ALL)
+ assert-css: (".scraped-example .example-wrap .rust span.highlight.focus", {
+ "background-color": |highlight_focus|,
+ }, ALL)
+
+ assert-css: (".scraped-example-list .scrape-help", {
+ "border-color": |help_border|,
+ "color": |help_color|,
+ })
+ move-cursor-to: ".scraped-example-list .scrape-help"
+ assert-css: (".scraped-example-list .scrape-help:hover", {
+ "border-color": |help_hover_border|,
+ "color": |help_hover_color|,
+ })
+ // Moving the cursor to another item to not break next runs.
+ move-cursor-to: ".search-input"
+ }
+)
+
+call-function: ("check-colors", {
+ "theme": "ayu",
+ "highlight": "rgb(91, 59, 1)",
+ "highlight_focus": "rgb(124, 75, 15)",
+ "help_border": "rgb(170, 170, 170)",
+ "help_color": "rgb(238, 238, 238)",
+ "help_hover_border": "rgb(255, 255, 255)",
+ "help_hover_color": "rgb(255, 255, 255)",
+})
+call-function: ("check-colors", {
+ "theme": "dark",
+ "highlight": "rgb(91, 59, 1)",
+ "highlight_focus": "rgb(124, 75, 15)",
+ "help_border": "rgb(170, 170, 170)",
+ "help_color": "rgb(238, 238, 238)",
+ "help_hover_border": "rgb(255, 255, 255)",
+ "help_hover_color": "rgb(255, 255, 255)",
+})
+call-function: ("check-colors", {
+ "theme": "light",
+ "highlight": "rgb(252, 255, 214)",
+ "highlight_focus": "rgb(246, 253, 176)",
+ "help_border": "rgb(85, 85, 85)",
+ "help_color": "rgb(51, 51, 51)",
+ "help_hover_border": "rgb(0, 0, 0)",
+ "help_hover_color": "rgb(0, 0, 0)",
+})
+// This test ensures that the correct font is used in scraped examples.
goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html"
store-value: (font, '"Fira Sans", Arial, NanumBarunGothic, sans-serif')
".more-scraped-examples .scraped-example:nth-child(6) .code-wrapper .src-line-numbers",
{"clientWidth": |clientWidth|}
)
+
+// Check that for both mobile and desktop sizes, the buttons in scraped examples are displayed
+// correctly.
+
+store-value: (offset_y, 4)
+
+// First with desktop
+assert-position: (".scraped-example .code-wrapper", {"y": 255})
+assert-position: (".scraped-example .code-wrapper .prev", {"y": 255 + |offset_y|})
+
+// Then with mobile
+size: (600, 600)
+assert-position: (".scraped-example .code-wrapper", {"y": 314})
+assert-position: (".scraped-example .code-wrapper .prev", {"y": 314 + |offset_y|})
define-function: (
"check-color",
(theme, toggle_line_color, toggle_line_hover_color),
- [
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
+ block {
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
// Clicking "More examples..." will open additional examples
- ("assert-attribute-false", (".more-examples-toggle", {"open": ""})),
- ("click", ".more-examples-toggle"),
- ("assert-attribute", (".more-examples-toggle", {"open": ""})),
+ assert-attribute-false: (".more-examples-toggle", {"open": ""})
+ click: ".more-examples-toggle"
+ assert-attribute: (".more-examples-toggle", {"open": ""})
- ("assert-css", (".toggle-line-inner", {"background-color": |toggle_line_color|}, ALL)),
- ("move-cursor-to", ".toggle-line"),
- ("assert-css", (
+ assert-css: (".toggle-line-inner", {"background-color": |toggle_line_color|}, ALL)
+ move-cursor-to: ".toggle-line"
+ assert-css: (
".toggle-line:hover .toggle-line-inner",
{"background-color": |toggle_line_hover_color|},
- )),
+ )
// Moving cursor away from the toggle line to prevent disrupting next test.
- ("move-cursor-to", ".search-input"),
- ],
+ move-cursor-to: ".search-input"
+ },
)
call-function: ("check-color", {
press-key: "ArrowDown"
press-key: "ArrowDown"
press-key: "ArrowDown"
+press-key: "ArrowDown"
press-key: "Enter"
// Waiting for the search results to appear...
wait-for: "#search-tabs"
press-key: "ArrowUp"
press-key: "ArrowUp"
press-key: "ArrowUp"
+press-key: "ArrowUp"
press-key: "Enter"
// Waiting for the search results to appear...
wait-for: "#search-tabs"
define-function: (
"check-no-result",
(theme, link, link_hover),
- [
+ block {
// Changing theme.
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
- ("wait-for", "#results"),
- ("assert", ".search-failed.active"),
- ("assert-css", ("#results a", {"color": |link|}, ALL)),
- ("move-cursor-to", "#results a"),
- ("assert-css", ("#results a:hover", {"color": |link_hover|})),
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
+ wait-for: "#results"
+ assert: ".search-failed.active"
+ assert-css: ("#results a", {"color": |link|}, ALL)
+ move-cursor-to: "#results a"
+ assert-css: ("#results a:hover", {"color": |link_hover|})
// Moving the cursor to some other place to not create issues with next function run.
- ("move-cursor-to", ".search-input"),
- ]
+ move-cursor-to: ".search-input"
+ },
)
call-function: ("check-no-result", {
define-function: (
"check-result-color",
(result_kind, color, hover_color),
- [
- (
- "assert-css",
- (".result-" + |result_kind| + " ." + |result_kind|, {"color": |color|}, ALL),
- ),
- (
- "assert-css",
- (
- ".result-" + |result_kind|,
- {"color": |entry_color|, "background-color": |background_color|},
- ),
- ),
- (
- "move-cursor-to",
+ block {
+ assert-css: (".result-" + |result_kind| + " ." + |result_kind|, {"color": |color|}, ALL)
+ assert-css: (
".result-" + |result_kind|,
- ),
- (
- "assert-css",
- (
- ".result-" + |result_kind| + ":hover",
- {"color": |hover_entry_color|, "background-color": |hover_background_color|},
- ),
- ),
- (
- "assert-css",
- (".result-" + |result_kind| + ":hover ." + |result_kind|, {"color": |hover_color|}),
- ),
- (
- "move-cursor-to",
- ".search-input",
- ),
- (
- "focus",
- ".result-" + |result_kind|,
- ),
- (
- "assert-css",
- (
- ".result-" + |result_kind| + ":focus",
- {"color": |hover_entry_color|, "background-color": |hover_background_color|},
- ),
- ),
- (
- "assert-css",
- (".result-" + |result_kind| + ":focus ." + |result_kind|, {"color": |hover_color|}),
- ),
- ],
+ {"color": |entry_color|, "background-color": |background_color|},
+ )
+ move-cursor-to: ".result-" + |result_kind|
+ assert-css: (
+ ".result-" + |result_kind| + ":hover",
+ {"color": |hover_entry_color|, "background-color": |hover_background_color|},
+ )
+ assert-css: (
+ ".result-" + |result_kind| + ":hover ." + |result_kind|,
+ {"color": |hover_color|},
+ )
+ move-cursor-to: ".search-input"
+ focus: ".result-" + |result_kind|
+ assert-css: (
+ ".result-" + |result_kind| + ":focus",
+ {"color": |hover_entry_color|, "background-color": |hover_background_color|},
+ )
+ assert-css: (
+ ".result-" + |result_kind| + ":focus ." + |result_kind|,
+ {"color": |hover_color|},
+ )
+ },
)
goto: "file://" + |DOC_PATH| + "/test_docs/index.html?search=coo"
define-function: (
"check-alias",
(theme, alias, grey),
- [
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
- ("write", (".search-input", "thisisanalias")),
+ block {
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
+ write: (".search-input", "thisisanalias")
// To be SURE that the search will be run.
- ("press-key", 'Enter'),
+ press-key: 'Enter'
// Waiting for the search results to appear...
- ("wait-for", "#search-tabs"),
+ wait-for: "#search-tabs"
// Checking that the colors for the alias element are the ones expected.
- ("assert-css", (".result-name > .alias", {"color": |alias|})),
- ("assert-css", (".result-name > .alias > .grey", {"color": |grey|})),
+ assert-css: (".result-name > .alias", {"color": |alias|})
+ assert-css: (".result-name > .alias > .grey", {"color": |grey|})
// Leave the search results to prevent reloading with an already filled search input.
- ("press-key", "Escape"),
- ],
+ press-key: "Escape"
+ },
)
call-function: ("check-alias", {
define-function: (
"check-filter",
(theme, border, filter, hover_border, hover_filter),
- [
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
- ("wait-for", "#crate-search"),
- ("assert-css", ("#crate-search", {"border": "1px solid " + |border|})),
- ("assert-css", ("#crate-search-div::after", {"filter": |filter|})),
- ("move-cursor-to", "#crate-search"),
- ("assert-css", ("#crate-search", {"border": "1px solid " + |hover_border|})),
- ("assert-css", ("#crate-search-div::after", {"filter": |hover_filter|})),
- ("move-cursor-to", ".search-input"),
- ],
+ block {
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
+ wait-for: "#crate-search"
+ assert-css: ("#crate-search", {"border": "1px solid " + |border|})
+ assert-css: ("#crate-search-div::after", {"filter": |filter|})
+ move-cursor-to: "#crate-search"
+ assert-css: ("#crate-search", {"border": "1px solid " + |hover_border|})
+ assert-css: ("#crate-search-div::after", {"filter": |hover_filter|})
+ move-cursor-to: ".search-input"
+ },
)
call-function: ("check-filter", {
--- /dev/null
+// Checking the colors of the search tab headers.
+goto: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html?search=something"
+show-text: true
+
+define-function: (
+ "check-colors",
+ (theme, background, background_selected, background_hover, border_bottom,
+ border_bottom_selected, border_bottom_hover, border_top, border_top_selected,
+ border_top_hover),
+ block {
+ // Setting the theme.
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
+
+ // These two commands are used to be sure the search will be run.
+ focus: ".search-input"
+ press-key: "Enter"
+
+ wait-for: "#search-tabs"
+ assert-css: ("#search-tabs > button:not(.selected)", {
+ "background-color": |background|,
+ "border-bottom": |border_bottom|,
+ "border-top": |border_top|,
+ })
+ assert-css: ("#search-tabs > button.selected", {
+ "background-color": |background_selected|,
+ "border-bottom": |border_bottom_selected|,
+ "border-top": |border_top_selected|,
+ })
+ move-cursor-to: "#search-tabs > button:not(.selected)"
+ assert-css: ("#search-tabs > button:not(.selected):hover", {
+ "background-color": |background_hover|,
+ "border-bottom": |border_bottom_hover|,
+ "border-top": |border_top_hover|,
+ })
+ // To prevent disrupting next run of this function.
+ move-cursor-to: ".search-input"
+ },
+)
+
+call-function: ("check-colors", {
+ "theme": "ayu",
+ "background": "rgba(0, 0, 0, 0)",
+ "background_selected": "rgb(20, 25, 32)",
+ "background_hover": "rgba(0, 0, 0, 0)",
+ "border_bottom": "0px none rgb(197, 197, 197)",
+ "border_bottom_selected": "1px solid rgb(255, 180, 76)",
+ "border_bottom_hover": "1px solid rgba(242, 151, 24, 0.3)",
+ "border_top": "0px none rgb(197, 197, 197)",
+ "border_top_selected": "0px none rgb(197, 197, 197)",
+ "border_top_hover": "0px none rgb(197, 197, 197)",
+})
+call-function: ("check-colors", {
+ "theme": "dark",
+ "background": "rgb(37, 37, 37)",
+ "background_selected": "rgb(53, 53, 53)",
+ "background_hover": "rgb(53, 53, 53)",
+ "border_bottom": "0px none rgb(221, 221, 221)",
+ "border_bottom_selected": "0px none rgb(221, 221, 221)",
+ "border_bottom_hover": "0px none rgb(221, 221, 221)",
+ "border_top": "2px solid rgb(37, 37, 37)",
+ "border_top_selected": "2px solid rgb(0, 137, 255)",
+ "border_top_hover": "2px solid rgb(0, 137, 255)",
+})
+call-function: ("check-colors", {
+ "theme": "light",
+ "background": "rgb(230, 230, 230)",
+ "background_selected": "rgb(255, 255, 255)",
+ "background_hover": "rgb(255, 255, 255)",
+ "border_bottom": "0px none rgb(0, 0, 0)",
+ "border_bottom_selected": "0px none rgb(0, 0, 0)",
+ "border_bottom_hover": "0px none rgb(0, 0, 0)",
+ "border_top": "2px solid rgb(230, 230, 230)",
+ "border_top_selected": "2px solid rgb(0, 137, 255)",
+ "border_top_hover": "2px solid rgb(0, 137, 255)",
+})
trait_hover_background, fn, fn_hover, fn_hover_background, type, type_hover,
type_hover_background, keyword, keyword_hover, keyword_hover_background,
),
- [
- ("local-storage", { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }),
- ("reload"),
+ block {
+ local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }
+ reload:
// Struct
- ("assert-css", (
+ assert-css: (
".sidebar .block.struct a:not(.current)",
{"color": |struct|, "background-color": "rgba(0, 0, 0, 0)"},
- )),
- ("move-cursor-to", ".sidebar .block.struct a:not(.current)"),
- ("assert-css", (
+ )
+ move-cursor-to: ".sidebar .block.struct a:not(.current)"
+ assert-css: (
".sidebar .block.struct a:hover",
{"color": |struct_hover|, "background-color": |struct_hover_background|},
- )),
+ )
// Enum
- ("assert-css", (
+ assert-css: (
".sidebar .block.enum a",
{"color": |enum|, "background-color": "rgba(0, 0, 0, 0)"},
- )),
- ("move-cursor-to", ".sidebar .block.enum a"),
- ("assert-css", (
+ )
+ move-cursor-to: ".sidebar .block.enum a"
+ assert-css: (
".sidebar .block.enum a:hover",
{"color": |enum_hover|, "background-color": |enum_hover_background|},
- )),
+ )
// Union
- ("assert-css", (
+ assert-css: (
".sidebar .block.union a",
{"color": |union|, "background-color": "rgba(0, 0, 0, 0)"},
- )),
- ("move-cursor-to", ".sidebar .block.union a"),
- ("assert-css", (
+ )
+ move-cursor-to: ".sidebar .block.union a"
+ assert-css: (
".sidebar .block.union a:hover",
{"color": |union_hover|, "background-color": |union_hover_background|},
- )),
+ )
// Trait
- ("assert-css", (
+ assert-css: (
".sidebar .block.trait a",
{"color": |trait|, "background-color": "rgba(0, 0, 0, 0)"},
- )),
- ("move-cursor-to", ".sidebar .block.trait a"),
- ("assert-css", (
+ )
+ move-cursor-to: ".sidebar .block.trait a"
+ assert-css: (
".sidebar .block.trait a:hover",
{"color": |trait_hover|, "background-color": |trait_hover_background|},
- )),
+ )
// Function
- ("assert-css", (
+ assert-css: (
".sidebar .block.fn a",
{"color": |fn|, "background-color": "rgba(0, 0, 0, 0)"},
- )),
- ("move-cursor-to", ".sidebar .block.fn a"),
- ("assert-css", (
+ )
+ move-cursor-to: ".sidebar .block.fn a"
+ assert-css: (
".sidebar .block.fn a:hover",
{"color": |fn_hover|, "background-color": |fn_hover_background|},
- )),
+ )
// Type definition
- ("assert-css", (
+ assert-css: (
".sidebar .block.type a",
{"color": |type|, "background-color": "rgba(0, 0, 0, 0)"},
- )),
- ("move-cursor-to", ".sidebar .block.type a"),
- ("assert-css", (
+ )
+ move-cursor-to: ".sidebar .block.type a"
+ assert-css: (
".sidebar .block.type a:hover",
{"color": |type_hover|, "background-color": |type_hover_background|},
- )),
+ )
// Keyword
- ("assert-css", (
+ assert-css: (
".sidebar .block.keyword a",
{"color": |keyword|, "background-color": "rgba(0, 0, 0, 0)"},
- )),
- ("move-cursor-to", ".sidebar .block.keyword a"),
- ("assert-css", (
+ )
+ move-cursor-to: ".sidebar .block.keyword a"
+ assert-css: (
".sidebar .block.keyword a:hover",
{"color": |keyword_hover|, "background-color": |keyword_hover_background|},
- )),
- ]
+ )
+ }
)
call-function: (
define-function: (
"check-colors",
(theme, color, background),
- [
- ("local-storage", {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}),
- ("reload"),
+ block {
+ local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
+ reload:
// Open the sidebar menu.
- ("click", ".sidebar-menu-toggle"),
- ("assert-css", (".sidebar", {
+ click: ".sidebar-menu-toggle"
+ assert-css: (".sidebar", {
"background-color": |background|,
"color": |color|,
- })),
- ],
+ })
+ },
)
call-function: ("check-colors", {
theme, color, color_hover, background, background_hover, background_toggle,
background_toggle_hover,
),
- [
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
- ("wait-for-css", ("#src-sidebar-toggle", {"visibility": "visible"})),
- ("assert-css", (
+ block {
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
+ wait-for-css: ("#src-sidebar-toggle", {"visibility": "visible"})
+ assert-css: (
"#source-sidebar details[open] > .files a.selected",
{"color": |color_hover|, "background-color": |background|},
- )),
+ )
// Without hover or focus.
- ("assert-css", ("#src-sidebar-toggle > button", {"background-color": |background_toggle|})),
+ assert-css: ("#src-sidebar-toggle > button", {"background-color": |background_toggle|})
// With focus.
- ("focus", "#src-sidebar-toggle > button"),
- ("assert-css", (
+ focus: "#src-sidebar-toggle > button"
+ assert-css: (
"#src-sidebar-toggle > button:focus",
{"background-color": |background_toggle_hover|},
- )),
- ("focus", ".search-input"),
+ )
+ focus: ".search-input"
// With hover.
- ("move-cursor-to", "#src-sidebar-toggle > button"),
- ("assert-css", (
+ move-cursor-to: "#src-sidebar-toggle > button"
+ assert-css: (
"#src-sidebar-toggle > button:hover",
{"background-color": |background_toggle_hover|},
- )),
+ )
// Without hover or focus.
- ("assert-css", (
+ assert-css: (
"#source-sidebar details[open] > .files a:not(.selected)",
{"color": |color|, "background-color": |background_toggle|},
- )),
+ )
// With focus.
- ("focus", "#source-sidebar details[open] > .files a:not(.selected)"),
- ("wait-for-css", (
+ focus: "#source-sidebar details[open] > .files a:not(.selected)"
+ wait-for-css: (
"#source-sidebar details[open] > .files a:not(.selected):focus",
{"color": |color_hover|, "background-color": |background_hover|},
- )),
- ("focus", ".search-input"),
+ )
+ focus: ".search-input"
// With hover.
- ("move-cursor-to", "#source-sidebar details[open] > .files a:not(.selected)"),
- ("assert-css", (
+ move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
+ assert-css: (
"#source-sidebar details[open] > .files a:not(.selected):hover",
{"color": |color_hover|, "background-color": |background_hover|},
- )),
+ )
// Without hover or focus.
- ("assert-css", (
+ assert-css: (
"#source-sidebar .dir-entry summary",
{"color": |color|, "background-color": |background_toggle|},
- )),
+ )
// With focus.
- ("focus", "#source-sidebar .dir-entry summary"),
- ("wait-for-css", (
+ focus: "#source-sidebar .dir-entry summary"
+ wait-for-css: (
"#source-sidebar .dir-entry summary:focus",
{"color": |color_hover|, "background-color": |background_hover|},
- )),
- ("focus", ".search-input"),
+ )
+ focus: ".search-input"
// With hover.
- ("move-cursor-to", "#source-sidebar .dir-entry summary"),
- ("assert-css", (
+ move-cursor-to: "#source-sidebar .dir-entry summary"
+ assert-css: (
"#source-sidebar .dir-entry summary:hover",
{"color": |color_hover|, "background-color": |background_hover|},
- )),
+ )
// Without hover or focus.
- ("assert-css", (
+ assert-css: (
"#source-sidebar details[open] > .folders > details > summary",
{"color": |color|, "background-color": |background_toggle|},
- )),
+ )
// With focus.
- ("focus", "#source-sidebar details[open] > .folders > details > summary"),
- ("wait-for-css", (
+ focus: "#source-sidebar details[open] > .folders > details > summary"
+ wait-for-css: (
"#source-sidebar details[open] > .folders > details > summary:focus",
{"color": |color_hover|, "background-color": |background_hover|},
- )),
- ("focus", ".search-input"),
+ )
+ focus: ".search-input"
// With hover.
- ("move-cursor-to", "#source-sidebar details[open] > .folders > details > summary"),
- ("assert-css", (
+ move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
+ assert-css: (
"#source-sidebar details[open] > .folders > details > summary:hover",
{"color": |color_hover|, "background-color": |background_hover|},
- )),
- ],
+ )
+ },
)
call-function: ("check-colors", {
// We now check that the scroll position is kept when opening the sidebar.
click: "#src-sidebar-toggle"
-wait-for-css: (".sidebar", {"width": "0px"})
+wait-for-css: (".sidebar", {"left": "-1000px"})
// We scroll to line 117 to change the scroll position.
scroll-to: '//*[@id="117"]'
assert-window-property: {"pageYOffset": "2542"}
// Expanding the sidebar...
click: "#src-sidebar-toggle"
-wait-for-css: (".sidebar", {"width": "500px"})
+wait-for-css: (".sidebar", {"left": "0px"})
click: "#src-sidebar-toggle"
-wait-for-css: (".sidebar", {"width": "0px"})
+wait-for-css: (".sidebar", {"left": "-1000px"})
// The "scrollTop" property should be the same.
assert-window-property: {"pageYOffset": "2542"}
// The goal of this test is to ensure that the sidebar is working as expected in the source
// code pages.
goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
-// First: desktop mode.
+show-text: true
+
+// First, check the sidebar colors.
+define-function: (
+ "check-colors",
+ (theme, color, background_color),
+ block {
+ local-storage: {
+ "rustdoc-theme": |theme|,
+ "rustdoc-use-system-theme": "false",
+ }
+ reload:
+ // Checking results colors.
+ assert-css: (".source .sidebar", {
+ "color": |color|,
+ "background-color": |background_color|
+ }, ALL)
+ },
+)
+
+call-function: (
+ "check-colors",
+ {
+ "theme": "ayu",
+ "color": "rgb(197, 197, 197)",
+ "background_color": "rgb(20, 25, 31)",
+ }
+)
+call-function: (
+ "check-colors",
+ {
+ "theme": "dark",
+ "color": "rgb(221, 221, 221)",
+ "background_color": "rgb(80, 80, 80)",
+ }
+)
+call-function: (
+ "check-colors",
+ {
+ "theme": "light",
+ "color": "rgb(0, 0, 0)",
+ "background_color": "rgb(245, 245, 245)",
+ }
+)
+
+// Next, desktop mode layout.
size: (1100, 800)
// We check that the sidebar isn't expanded and has the expected width.
assert-css: ("nav.sidebar", {"width": "50px"})
// Only "another_folder" should be "open" in "lib2".
assert: "//*[@class='dir-entry' and not(@open)]/*[text()='another_mod']"
// All other trees should be collapsed.
-assert-count: ("//*[@id='source-sidebar']/details[not(text()='lib2') and not(@open)]", 7)
+assert-count: ("//*[@id='source-sidebar']/details[not(text()='lib2') and not(@open)]", 8)
// We now switch to mobile mode.
size: (600, 600)
-wait-for-css: (".source-sidebar-expanded nav.sidebar", {"width": "600px"})
+wait-for-css: (".source-sidebar-expanded nav.sidebar", {"left": "0px"})
// We collapse the sidebar.
click: (10, 10)
-// We check that the sidebar has the expected width (0).
-assert-css: ("nav.sidebar", {"width": "0px"})
+// We check that the sidebar has been moved off-screen.
+assert-css: ("nav.sidebar", {"left": "-1000px"})
// We ensure that the class has been removed.
assert-false: ".source-sidebar-expanded"
assert: "nav.sidebar"
goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
assert-property: (".sidebar", {"clientWidth": "200"})
show-text: true
+
+// First, check the sidebar colors.
+define-function: (
+ "check-colors",
+ (theme, color, background_color),
+ block {
+ local-storage: {
+ "rustdoc-theme": |theme|,
+ "rustdoc-use-system-theme": "false",
+ }
+ reload:
+ // Checking results colors.
+ assert-css: (".sidebar", {
+ "color": |color|,
+ "background-color": |background_color|
+ }, ALL)
+ },
+)
+
+call-function: (
+ "check-colors",
+ {
+ "theme": "ayu",
+ "color": "rgb(197, 197, 197)",
+ "background_color": "rgb(20, 25, 31)",
+ }
+)
+call-function: (
+ "check-colors",
+ {
+ "theme": "dark",
+ "color": "rgb(221, 221, 221)",
+ "background_color": "rgb(80, 80, 80)",
+ }
+)
+call-function: (
+ "check-colors",
+ {
+ "theme": "light",
+ "color": "rgb(0, 0, 0)",
+ "background_color": "rgb(245, 245, 245)",
+ }
+)
+
local-storage: {"rustdoc-theme": "light"}
// We reload the page so the local storage settings are being used.
reload:
assert-property: (".sidebar", {"clientWidth": "200"})
click: "#toggle-all-docs"
assert-text: ("#toggle-all-docs", "[−]")
-assert-property: (".sidebar", {"clientWidth": "200"})
\ No newline at end of file
+assert-property: (".sidebar", {"clientWidth": "200"})
define-function: (
"check-colors",
(theme, color, background_color, highlight_color, highlight_background_color),
- [
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
- ("assert-css", (
+ block {
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
+ assert-css: (
".src-line-numbers > a:not(.line-highlighted)",
{"color": |color|, "background-color": |background_color|},
ALL,
- )),
- ("assert-css", (
+ )
+ assert-css: (
".src-line-numbers > a.line-highlighted",
{"color": |highlight_color|, "background-color": |highlight_background_color|},
ALL,
- )),
- ],
+ )
+ },
)
call-function: ("check-colors", {
// We check that the first entry of the sidebar is collapsed
assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
-assert-text: ("#source-sidebar details:first-of-type > summary", "huge_logo")
+assert-text: ("#source-sidebar details:first-of-type > summary", "http")
// We now click on it.
click: "#source-sidebar details:first-of-type > summary"
assert-property: ("#source-sidebar details:first-of-type", {"open": "true"})
click: "#source-sidebar details:first-of-type > summary"
assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
-// Check the spacing.
-assert-css: ("#source-sidebar > details.dir-entry", {"padding-left": "4px"})
+// And open it again, since it'll be the reference we use to check positions.
+click: "#source-sidebar details:first-of-type > summary"
+assert-property: ("#source-sidebar details:first-of-type", {"open": "true"})
+
+// Check the sidebar directory entries have a marker and spacing (desktop).
+store-property: (
+ link_height,
+ "#source-sidebar > details:first-of-type.dir-entry[open] > .files > a",
+ "offsetHeight"
+)
+define-function: (
+ "check-sidebar-dir-entry",
+ (x, y),
+ block {
+ assert: "details:first-of-type.dir-entry[open] > summary::marker"
+ assert-css: ("#source-sidebar > details:first-of-type.dir-entry", {"padding-left": "4px"})
+ // This check ensures that the summary is only one line.
+ assert-property: (
+ "#source-sidebar > details:first-of-type.dir-entry[open] > summary",
+ {"offsetHeight": |link_height|}
+ )
+ assert-position: (
+ "#source-sidebar > details:first-of-type.dir-entry[open] > summary",
+ {"x": |x|, "y": |y|}
+ )
+ assert-property: (
+ "#source-sidebar > details:first-of-type.dir-entry[open] > .files > a",
+ {"offsetHeight": |link_height|}
+ )
+ assert-position: (
+ "#source-sidebar > details:first-of-type.dir-entry[open] > .files > a",
+ // left margin
+ {"x": |x| + 27, "y": |y| + |link_height|}
+ )
+ }
+)
+store-property: (
+ source_sidebar_title_height,
+ "#source-sidebar > .title",
+ "offsetHeight"
+)
+store-property: (
+ source_sidebar_title_y,
+ "#source-sidebar > .title",
+ "offsetTop"
+)
+call-function: ("check-sidebar-dir-entry", {
+ "x": 0,
+ // border + margin = 6
+ "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
+})
// Check the search form
assert-css: ("nav.sub", {"flex-direction": "row"})
assert-property: ("#main-content", {"offsetTop": 90})
// 28 = 90 - 34 - 28
-// Now do the same check on moderately-sized mobile.
+// Now do the same check on moderately-sized, tablet mobile.
size: (700, 700)
assert-css: ("nav.sub", {"flex-direction": "row"})
assert-property: ("nav.sub form", {"offsetTop": 21, "offsetHeight": 34})
assert-property: ("#main-content", {"offsetTop": 76})
// 21 = 76 - 34 - 21
-// Tiny mobile gets a different display where the logo is stacked on top.
+// Check the sidebar directory entries have a marker and spacing (tablet).
+store-property: (
+ source_sidebar_title_height,
+ "#source-sidebar > .title",
+ "offsetHeight"
+)
+store-property: (
+ source_sidebar_title_y,
+ "#source-sidebar > .title",
+ "offsetTop"
+)
+call-function: ("check-sidebar-dir-entry", {
+ "x": 0,
+ "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
+})
+
+// Tiny, phone mobile gets a different display where the logo is stacked on top.
size: (450, 700)
assert-css: ("nav.sub", {"flex-direction": "column"})
+
+// Check the sidebar directory entries have a marker and spacing (phone).
+store-property: (
+ source_sidebar_title_height,
+ "#source-sidebar > .title",
+ "offsetHeight"
+)
+store-property: (
+ source_sidebar_title_y,
+ "#source-sidebar > .title",
+ "offsetTop"
+)
+call-function: ("check-sidebar-dir-entry", {
+ "x": 0,
+ "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
+})
# It is not intended for manual editing.
version = 3
+[[package]]
+name = "http"
+version = "0.1.0"
+
[[package]]
name = "implementors"
version = "0.1.0"
+dependencies = [
+ "http",
+]
[[package]]
name = "lib2"
version = "0.1.0"
dependencies = [
+ "http",
"implementors",
]
[dependencies]
implementors = { path = "./implementors" }
+http = { path = "./http" }
--- /dev/null
+[package]
+name = "http"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+path = "lib.rs"
--- /dev/null
+pub trait HttpTrait {}
[lib]
path = "lib.rs"
+
+[dependencies]
+http = { path = "../http/" }
type Foo = u8;
}
+impl http::HttpTrait for Struct {}
+
mod traits {
pub trait TraitToReexport {
fn method() {}
goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
show-text: true
define-function: (
- "check-badge",
- (theme, background, color),
- [
- ("local-storage", {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}),
- ("goto", "file://" + |DOC_PATH| + "/test_docs/index.html"),
- ("assert", (".docblock .stab")),
- ("assert", (".item-table .stab")),
- ("assert-css", (".stab", {
- "border-radius": "3px",
- "color": |color|,
- "background-color": |background|,
- })),
- ("goto", "file://" + |DOC_PATH| + "/test_docs/fn.replaced_function.html"),
- ("assert", (".item-info .stab")),
- ("assert-css", (".stab", {
- "border-radius": "3px",
- "color": |color|,
- "background-color": |background|,
- })),
- ]
+ "check-badge",
+ (theme, background, color),
+ block {
+ local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
+ goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
+ assert: ".docblock .stab"
+ assert: ".item-table .stab"
+ assert-css: (".stab", {
+ "border-radius": "3px",
+ "color": |color|,
+ "background-color": |background|,
+ })
+ goto: "file://" + |DOC_PATH| + "/test_docs/fn.replaced_function.html"
+ assert: (".item-info .stab")
+ assert-css: (".stab", {
+ "border-radius": "3px",
+ "color": |color|,
+ "background-color": |background|,
+ })
+ },
)
call-function: ("check-badge", {
- "theme": "ayu",
- "color": "rgb(197, 197, 197)",
- "background": "rgb(49, 69, 89)",
+ "theme": "ayu",
+ "color": "rgb(197, 197, 197)",
+ "background": "rgb(49, 69, 89)",
})
call-function: ("check-badge", {
- "theme": "dark",
- "color": "rgb(221, 221, 221)",
- "background": "rgb(49, 69, 89)",
+ "theme": "dark",
+ "color": "rgb(221, 221, 221)",
+ "background": "rgb(49, 69, 89)",
})
call-function: ("check-badge", {
- "theme": "light",
- "color": "rgb(0, 0, 0)",
- "background": "rgb(255, 245, 214)",
+ "theme": "light",
+ "color": "rgb(0, 0, 0)",
+ "background": "rgb(255, 245, 214)",
})
define-function: (
"check-style",
(theme, background, border),
- [
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
- ("reload"),
- ("assert-css", ("#method\.a_method:target", {
+ block {
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+ reload:
+ assert-css: ("#method\.a_method:target", {
"background-color": |background|,
"border-right": "3px solid " + |border|,
- })),
- ],
+ })
+ },
)
call-function: ("check-style", {
define-function: (
"check-color",
(theme, filter),
- [
+ block {
// Setting the theme.
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
// We reload the page so the local storage settings are being used.
- ("reload"),
+ reload:
- ("assert-css", ("details.rustdoc-toggle > summary::before", {
+ assert-css: ("details.rustdoc-toggle > summary::before", {
"opacity": "0.5",
"filter": |filter|,
- }, ALL)),
- ("move-cursor-to", "details.rustdoc-toggle summary"),
- ("assert-css", ("details.rustdoc-toggle > summary:hover::before", {
+ }, ALL)
+ move-cursor-to: "details.rustdoc-toggle summary"
+ assert-css: ("details.rustdoc-toggle > summary:hover::before", {
"opacity": "1",
"filter": |filter|,
- })),
+ })
// moving the cursor somewhere else to not mess with next function calls.
- ("move-cursor-to", ".search-input"),
- ]
+ move-cursor-to: ".search-input"
+ },
)
call-function: ("check-color", {"theme": "ayu", "filter": "invert(1)"})
+// ignore-tidy-linelength
// This test ensures that the items declaration content overflow is handled inside the <pre> directly.
// We need to disable this check because
// `theme` is the theme being tested.
// `color` is the expected color of the `<sup>` element.
(theme, color),
- [
+ block {
// Set the theme.
- ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+ local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
// We reload the page so the local storage settings are being used.
- ("reload"),
- ("assert-css", (".item-left sup", {"color": |color|})),
- ],
+ reload:
+ assert-css: (".item-left sup", {"color": |color|})
+ },
)
call-function: ("sup-check", ("dark", "rgb(221, 221, 221)"))
}
}
-// @count "$.index[*][?(@.name=='builders')]" 2
+// @count "$.index[*][?(@.name=='builders')]" 1
+// @has "$.index[*][?(@.name == 'ActionRowBuilder')"]
pub use auto::*;
pub mod builders {
#[repr(i8)]
pub enum Ordering {
- // @is "$.index[*][?(@.name=='Less')].inner.variant_inner.expr" '"-1"'
- // @is "$.index[*][?(@.name=='Less')].inner.variant_inner.value" '"-1"'
+ // @is "$.index[*][?(@.name=='Less')].inner.discriminant.expr" '"-1"'
+ // @is "$.index[*][?(@.name=='Less')].inner.discriminant.value" '"-1"'
Less = -1,
- // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.expr" '"0"'
- // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.value" '"0"'
+ // @is "$.index[*][?(@.name=='Equal')].inner.discriminant.expr" '"0"'
+ // @is "$.index[*][?(@.name=='Equal')].inner.discriminant.value" '"0"'
Equal = 0,
- // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.expr" '"1"'
- // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.value" '"1"'
+ // @is "$.index[*][?(@.name=='Greater')].inner.discriminant.expr" '"1"'
+ // @is "$.index[*][?(@.name=='Greater')].inner.discriminant.value" '"1"'
Greater = 1,
}
pub enum Foo {
- // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.value" '"0"'
- // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.expr" '"{ _ }"'
+ // @is "$.index[*][?(@.name=='Addition')].inner.discriminant.value" '"0"'
+ // @is "$.index[*][?(@.name=='Addition')].inner.discriminant.expr" '"{ _ }"'
Addition = 0 + 0,
- // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.value" '"1"'
- // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.expr" '"0b1"'
+ // @is "$.index[*][?(@.name=='Bin')].inner.discriminant.value" '"1"'
+ // @is "$.index[*][?(@.name=='Bin')].inner.discriminant.expr" '"0b1"'
Bin = 0b1,
- // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.value" '"2"'
- // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.expr" '"0o2"'
+ // @is "$.index[*][?(@.name=='Oct')].inner.discriminant.value" '"2"'
+ // @is "$.index[*][?(@.name=='Oct')].inner.discriminant.expr" '"0o2"'
Oct = 0o2,
- // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.value" '"3"'
- // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.expr" '"THREE"'
+ // @is "$.index[*][?(@.name=='PubConst')].inner.discriminant.value" '"3"'
+ // @is "$.index[*][?(@.name=='PubConst')].inner.discriminant.expr" '"THREE"'
PubConst = THREE,
- // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.value" '"4"'
- // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.expr" '"0x4"'
+ // @is "$.index[*][?(@.name=='Hex')].inner.discriminant.value" '"4"'
+ // @is "$.index[*][?(@.name=='Hex')].inner.discriminant.expr" '"0x4"'
Hex = 0x4,
- // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.value" '"5"'
- // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.expr" '"{ _ }"'
+ // @is "$.index[*][?(@.name=='Cast')].inner.discriminant.value" '"5"'
+ // @is "$.index[*][?(@.name=='Cast')].inner.discriminant.expr" '"{ _ }"'
Cast = 5 as isize,
- // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.value" '"6"'
- // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.expr" '"{ _ }"'
+ // @is "$.index[*][?(@.name=='PubCall')].inner.discriminant.value" '"6"'
+ // @is "$.index[*][?(@.name=='PubCall')].inner.discriminant.expr" '"{ _ }"'
PubCall = six(),
- // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.value" '"7"'
- // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.expr" '"{ _ }"'
+ // @is "$.index[*][?(@.name=='PrivCall')].inner.discriminant.value" '"7"'
+ // @is "$.index[*][?(@.name=='PrivCall')].inner.discriminant.expr" '"{ _ }"'
PrivCall = seven(),
- // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.value" '"8"'
- // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.expr" '"EIGHT"'
+ // @is "$.index[*][?(@.name=='PrivConst')].inner.discriminant.value" '"8"'
+ // @is "$.index[*][?(@.name=='PrivConst')].inner.discriminant.expr" '"EIGHT"'
PrivConst = EIGHT,
}
#[repr(u64)]
pub enum U64 {
- // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.value" '"0"'
- // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.expr" '"u64::MIN"'
+ // @is "$.index[*][?(@.name=='U64Min')].inner.discriminant.value" '"0"'
+ // @is "$.index[*][?(@.name=='U64Min')].inner.discriminant.expr" '"u64::MIN"'
U64Min = u64::MIN,
- // @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.value" '"18446744073709551615"'
- // @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.expr" '"u64::MAX"'
+ // @is "$.index[*][?(@.name=='U64Max')].inner.discriminant.value" '"18446744073709551615"'
+ // @is "$.index[*][?(@.name=='U64Max')].inner.discriminant.expr" '"u64::MAX"'
U64Max = u64::MAX,
}
#[repr(i64)]
pub enum I64 {
- // @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.value" '"-9223372036854775808"'
- // @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.expr" '"i64::MIN"'
+ // @is "$.index[*][?(@.name=='I64Min')].inner.discriminant.value" '"-9223372036854775808"'
+ // @is "$.index[*][?(@.name=='I64Min')].inner.discriminant.expr" '"i64::MIN"'
I64Min = i64::MIN,
- // @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.value" '"9223372036854775807"'
- // @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.expr" '"i64::MAX"'
+ // @is "$.index[*][?(@.name=='I64Max')].inner.discriminant.value" '"9223372036854775807"'
+ // @is "$.index[*][?(@.name=='I64Max')].inner.discriminant.expr" '"i64::MAX"'
I64Max = i64::MAX,
}
#[repr(u128)]
pub enum U128 {
- // @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.value" '"0"'
- // @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.expr" '"u128::MIN"'
+ // @is "$.index[*][?(@.name=='U128Min')].inner.discriminant.value" '"0"'
+ // @is "$.index[*][?(@.name=='U128Min')].inner.discriminant.expr" '"u128::MIN"'
U128Min = u128::MIN,
- // @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.value" '"340282366920938463463374607431768211455"'
- // @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.expr" '"u128::MAX"'
+ // @is "$.index[*][?(@.name=='U128Max')].inner.discriminant.value" '"340282366920938463463374607431768211455"'
+ // @is "$.index[*][?(@.name=='U128Max')].inner.discriminant.expr" '"u128::MAX"'
U128Max = u128::MAX,
}
#[repr(i128)]
pub enum I128 {
- // @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.value" '"-170141183460469231731687303715884105728"'
- // @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.expr" '"i128::MIN"'
+ // @is "$.index[*][?(@.name=='I128Min')].inner.discriminant.value" '"-170141183460469231731687303715884105728"'
+ // @is "$.index[*][?(@.name=='I128Min')].inner.discriminant.expr" '"i128::MIN"'
I128Min = i128::MIN,
- // @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.value" '"170141183460469231731687303715884105727"'
- // @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.expr" '"i128::MAX"'
+ // @is "$.index[*][?(@.name=='I128Max')].inner.discriminant.value" '"170141183460469231731687303715884105727"'
+ // @is "$.index[*][?(@.name=='I128Max')].inner.discriminant.expr" '"i128::MAX"'
I128Max = i128::MAX,
}
#[repr(u32)]
pub enum Foo {
- // @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.value" '"0"'
- // @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.expr" '"0"'
+ // @is "$.index[*][?(@.name=='Basic')].inner.discriminant.value" '"0"'
+ // @is "$.index[*][?(@.name=='Basic')].inner.discriminant.expr" '"0"'
Basic = 0,
- // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.value" '"10"'
- // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.expr" '"10u32"'
+ // @is "$.index[*][?(@.name=='Suffix')].inner.discriminant.value" '"10"'
+ // @is "$.index[*][?(@.name=='Suffix')].inner.discriminant.expr" '"10u32"'
Suffix = 10u32,
- // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.value" '"100"'
- // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.expr" '"1_0_0"'
+ // @is "$.index[*][?(@.name=='Underscore')].inner.discriminant.value" '"100"'
+ // @is "$.index[*][?(@.name=='Underscore')].inner.discriminant.expr" '"1_0_0"'
Underscore = 1_0_0,
- // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.value" '"1000"'
- // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.expr" '"1_0_0_0u32"'
+ // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.discriminant.value" '"1000"'
+ // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.discriminant.expr" '"1_0_0_0u32"'
SuffixUnderscore = 1_0_0_0u32,
}
pub enum Foo {
- // @is "$.index[*][?(@.name=='Has')].inner.variant_inner" '{"expr":"0", "value":"0"}'
+ // @is "$.index[*][?(@.name=='Has')].inner.discriminant" '{"expr":"0", "value":"0"}'
Has = 0,
- // @is "$.index[*][?(@.name=='Doesnt')].inner.variant_inner" null
+ // @is "$.index[*][?(@.name=='Doesnt')].inner.discriminant" null
Doesnt,
- // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant_inner" null
+ // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.discriminant" null
AlsoDoesnt,
- // @is "$.index[*][?(@.name=='AlsoHas')].inner.variant_inner" '{"expr":"44", "value":"44"}'
+ // @is "$.index[*][?(@.name=='AlsoHas')].inner.discriminant" '{"expr":"44", "value":"44"}'
AlsoHas = 44,
}
--- /dev/null
+// ignore-tidy-linelength
+
+#[repr(i32)]
+// @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(i32)]"]'
+pub enum Foo {
+ // @is "$.index[*][?(@.name=='Struct')].inner.discriminant" null
+ // @count "$.index[*][?(@.name=='Struct')].inner.kind.struct.fields[*]" 0
+ Struct {},
+ // @is "$.index[*][?(@.name=='StructWithDiscr')].inner.discriminant" '{"expr": "42", "value": "42"}'
+ // @count "$.index[*][?(@.name=='StructWithDiscr')].inner.kind.struct.fields[*]" 1
+ StructWithDiscr { x: i32 } = 42,
+ // @is "$.index[*][?(@.name=='StructWithHexDiscr')].inner.discriminant" '{"expr": "0x42", "value": "66"}'
+ // @count "$.index[*][?(@.name=='StructWithHexDiscr')].inner.kind.struct.fields[*]" 2
+ StructWithHexDiscr { x: i32, y: bool } = 0x42,
+}
--- /dev/null
+// ignore-tidy-linelength
+
+#[repr(u32)]
+// @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(u32)]"]'
+pub enum Foo {
+ // @is "$.index[*][?(@.name=='Tuple')].inner.discriminant" null
+ // @count "$.index[*][?(@.name=='Tuple')].inner.kind.tuple[*]" 0
+ Tuple(),
+ // @is "$.index[*][?(@.name=='TupleWithDiscr')].inner.discriminant" '{"expr": "1", "value": "1"}'
+ // @count "$.index[*][?(@.name=='TupleWithDiscr')].inner.kind.tuple[*]" 1
+ TupleWithDiscr(i32) = 1,
+ // @is "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.discriminant" '{"expr": "0b10", "value": "2"}'
+ // @count "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.kind.tuple[*]" 2
+ TupleWithBinDiscr(i32, i32) = 0b10,
+}
// @has "$.index[*][?(@.name=='ParseError')]"
// @has "$.index[*][?(@.name=='UnexpectedEndTag')]"
-// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_kind" '"tuple"'
-// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_inner" [null]
+// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.kind.tuple" [null]
+// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.discriminant" null
pub enum ParseError {
UnexpectedEndTag(#[doc(hidden)] u32),
pub enum Foo {
// @set Unit = "$.index[*][?(@.name=='Unit')].id"
- // @is "$.index[*][?(@.name=='Unit')].inner.variant_kind" '"plain"'
- // @is "$.index[*][?(@.name=='Unit')].inner.variant_inner" null
+ // @is "$.index[*][?(@.name=='Unit')].inner.kind" '"plain"'
Unit,
// @set Named = "$.index[*][?(@.name=='Named')].id"
- // @is "$.index[*][?(@.name=='Named')].inner.variant_kind" '"struct"'
- // @is "$.index[*][?(@.name=='Named')].inner.variant_inner" '{"fields": [], "fields_stripped": false}'
+ // @is "$.index[*][?(@.name=='Named')].inner.kind.struct" '{"fields": [], "fields_stripped": false}'
Named {},
// @set Tuple = "$.index[*][?(@.name=='Tuple')].id"
- // @is "$.index[*][?(@.name=='Tuple')].inner.variant_kind" '"tuple"'
- // @is "$.index[*][?(@.name=='Tuple')].inner.variant_inner" []
+ // @is "$.index[*][?(@.name=='Tuple')].inner.kind.tuple" []
Tuple(),
// @set NamedField = "$.index[*][?(@.name=='NamedField')].id"
// @set x = "$.index[*][?(@.name=='x' && @.kind=='struct_field')].id"
- // @is "$.index[*][?(@.name=='NamedField')].inner.variant_kind" '"struct"'
- // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields[*]" $x
- // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields_stripped" false
+ // @is "$.index[*][?(@.name=='NamedField')].inner.kind.struct.fields[*]" $x
+ // @is "$.index[*][?(@.name=='NamedField')].inner.kind.struct.fields_stripped" false
NamedField { x: i32 },
// @set TupleField = "$.index[*][?(@.name=='TupleField')].id"
- // @is "$.index[*][?(@.name=='TupleField')].inner.variant_kind" '"tuple"'
// @set tup_field = "$.index[*][?(@.name=='0' && @.kind=='struct_field')].id"
- // @is "$.index[*][?(@.name=='TupleField')].inner.variant_inner[*]" $tup_field
+ // @is "$.index[*][?(@.name=='TupleField')].inner.kind.tuple[*]" $tup_field
TupleField(i32),
}
// @set y = "$.index[*][?(@.name=='y')].id"
y: i32,
},
- // @is "$.index[*][?(@.name=='Variant')].inner.variant_kind" '"struct"'
- // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields_stripped" true
- // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[0]" $b
- // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[1]" $y
- // @count "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[*]" 2
+ // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields_stripped" true
+ // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[0]" $b
+ // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[1]" $y
+ // @count "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[*]" 2
}
// @set 3.3.1 = "$.index[*][?(@.docs=='3.3.1')].id"
pub enum EnumWithStrippedTupleVariants {
- // @is "$.index[*][?(@.name=='None')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='None')].inner.variant_inner[*]" 0
+ // @count "$.index[*][?(@.name=='None')].inner.kind.tuple[*]" 0
None(),
- // @is "$.index[*][?(@.name=='One')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='One')].inner.variant_inner[*]" 1
- // @is "$.index[*][?(@.name=='One')].inner.variant_inner[0]" $1.1.0
+ // @count "$.index[*][?(@.name=='One')].inner.kind.tuple[*]" 1
+ // @is "$.index[*][?(@.name=='One')].inner.kind.tuple[0]" $1.1.0
One(/** 1.1.0*/ bool),
- // @is "$.index[*][?(@.name=='OneHidden')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[*]" 1
- // @is "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[0]" null
+ // @count "$.index[*][?(@.name=='OneHidden')].inner.kind.tuple[*]" 1
+ // @is "$.index[*][?(@.name=='OneHidden')].inner.kind.tuple[0]" null
OneHidden(#[doc(hidden)] bool),
- // @is "$.index[*][?(@.name=='Two')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='Two')].inner.variant_inner[*]" 2
- // @is "$.index[*][?(@.name=='Two')].inner.variant_inner[0]" $2.1.0
- // @is "$.index[*][?(@.name=='Two')].inner.variant_inner[1]" $2.1.1
+ // @count "$.index[*][?(@.name=='Two')].inner.kind.tuple[*]" 2
+ // @is "$.index[*][?(@.name=='Two')].inner.kind.tuple[0]" $2.1.0
+ // @is "$.index[*][?(@.name=='Two')].inner.kind.tuple[1]" $2.1.1
Two(/** 2.1.0*/ bool, /** 2.1.1*/ bool),
- // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[*]" 2
- // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[0]" null
- // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[1]" $2.2.1
+ // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[*]" 2
+ // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[0]" null
+ // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[1]" $2.2.1
TwoLeftHidden(#[doc(hidden)] bool, /** 2.2.1*/ bool),
- // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[*]" 2
- // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[0]" $2.3.0
- // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[1]" null
+ // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[*]" 2
+ // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[0]" $2.3.0
+ // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[1]" null
TwoRightHidden(/** 2.3.0*/ bool, #[doc(hidden)] bool),
- // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[*]" 2
- // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[0]" null
- // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[1]" null
+ // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[*]" 2
+ // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[0]" null
+ // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[1]" null
TwoBothHidden(#[doc(hidden)] bool, #[doc(hidden)] bool),
- // @is "$.index[*][?(@.name=='Three1')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='Three1')].inner.variant_inner[*]" 3
- // @is "$.index[*][?(@.name=='Three1')].inner.variant_inner[0]" null
- // @is "$.index[*][?(@.name=='Three1')].inner.variant_inner[1]" $3.1.1
- // @is "$.index[*][?(@.name=='Three1')].inner.variant_inner[2]" $3.1.2
+ // @count "$.index[*][?(@.name=='Three1')].inner.kind.tuple[*]" 3
+ // @is "$.index[*][?(@.name=='Three1')].inner.kind.tuple[0]" null
+ // @is "$.index[*][?(@.name=='Three1')].inner.kind.tuple[1]" $3.1.1
+ // @is "$.index[*][?(@.name=='Three1')].inner.kind.tuple[2]" $3.1.2
Three1(#[doc(hidden)] bool, /** 3.1.1*/ bool, /** 3.1.2*/ bool),
- // @is "$.index[*][?(@.name=='Three2')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='Three2')].inner.variant_inner[*]" 3
- // @is "$.index[*][?(@.name=='Three2')].inner.variant_inner[0]" $3.2.0
- // @is "$.index[*][?(@.name=='Three2')].inner.variant_inner[1]" null
- // @is "$.index[*][?(@.name=='Three2')].inner.variant_inner[2]" $3.2.2
+ // @count "$.index[*][?(@.name=='Three2')].inner.kind.tuple[*]" 3
+ // @is "$.index[*][?(@.name=='Three2')].inner.kind.tuple[0]" $3.2.0
+ // @is "$.index[*][?(@.name=='Three2')].inner.kind.tuple[1]" null
+ // @is "$.index[*][?(@.name=='Three2')].inner.kind.tuple[2]" $3.2.2
Three2(/** 3.2.0*/ bool, #[doc(hidden)] bool, /** 3.2.2*/ bool),
- // @is "$.index[*][?(@.name=='Three3')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='Three3')].inner.variant_inner[*]" 3
- // @is "$.index[*][?(@.name=='Three3')].inner.variant_inner[0]" $3.3.0
- // @is "$.index[*][?(@.name=='Three3')].inner.variant_inner[1]" $3.3.1
- // @is "$.index[*][?(@.name=='Three3')].inner.variant_inner[2]" null
+ // @count "$.index[*][?(@.name=='Three3')].inner.kind.tuple[*]" 3
+ // @is "$.index[*][?(@.name=='Three3')].inner.kind.tuple[0]" $3.3.0
+ // @is "$.index[*][?(@.name=='Three3')].inner.kind.tuple[1]" $3.3.1
+ // @is "$.index[*][?(@.name=='Three3')].inner.kind.tuple[2]" null
Three3(/** 3.3.0*/ bool, /** 3.3.1*/ bool, #[doc(hidden)] bool),
}
-
// @is "$.index[*][?(@.docs=='1.1.0')].name" '"0"'
// @is "$.index[*][?(@.docs=='2.1.0')].name" '"0"'
// @is "$.index[*][?(@.docs=='2.1.1')].name" '"1"'
// @is "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\"
// @is "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\"
pub enum EnumStruct {
- // @is "$.index[*][?(@.name=='VariantS')].inner.variant_kind" \"struct\"
// @is "$.index[*][?(@.name=='x')].kind" \"struct_field\"
+ // @set x = "$.index[*][?(@.name=='x')].id"
// @is "$.index[*][?(@.name=='y')].kind" \"struct_field\"
- VariantS {
- x: u32,
- y: String,
- },
+ // @set y = "$.index[*][?(@.name=='y')].id"
+ // @ismany "$.index[*][?(@.name=='VariantS')].inner.kind.struct.fields[*]" $x $y
+ VariantS { x: u32, y: String },
}
// @is "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\"
// @is "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\"
pub enum EnumTupleStruct {
- // @is "$.index[*][?(@.name=='VariantA')].inner.variant_kind" \"tuple\"
// @is "$.index[*][?(@.name=='0')].kind" \"struct_field\"
+ // @set f0 = "$.index[*][?(@.name=='0')].id"
// @is "$.index[*][?(@.name=='1')].kind" \"struct_field\"
+ // @set f1 = "$.index[*][?(@.name=='1')].id"
+ // @ismany "$.index[*][?(@.name=='VariantA')].inner.kind.tuple[*]" $f0 $f1
VariantA(u32, String),
}
--- /dev/null
+// Regression test for <https://github.com/rust-lang/rust/issues/104064>.
+
+#![feature(no_core)]
+#![feature(rustc_attrs)]
+#![feature(rustdoc_internals)]
+#![no_core]
+#![rustc_coherence_is_core]
+
+//! Link to [i32][prim@i32] [i64][prim@i64]
+
+#[doc(primitive = "i32")]
+mod prim_i32 {}
+
+// @set local_i32 = "$.index[*][?(@.name=='i32')].id"
+
+// @has "$.index[*][?(@.name=='local_primitive')]"
+// @ismany "$.index[*][?(@.name=='local_primitive')].inner.items[*]" $local_i32
+// @is "$.index[*][?(@.name=='local_primitive')].links['prim@i32']" $local_i32
+
+// Let's ensure the `prim_i32` module isn't present in the output JSON:
+// @!has "$.index[*][?(@.name=='prim_i32')]"
--- /dev/null
+// Regression test for <https://github.com/rust-lang/rust/issues/106379>
+
+#![feature(no_core)]
+#![no_core]
+
+mod repeat_n {
+ #[doc(hidden)]
+ pub struct RepeatN {}
+}
+
+pub use repeat_n::RepeatN;
+
+// @count "$.index[*][?(@.name=='pub_use_doc_hidden')].inner.items[*]" 0
+// @!has "$.index[*][?(@.kind=='struct')]"
+// @!has "$.index[*][?(@.kind=='import')]"
--- /dev/null
+impl Vec< br##"*.."## > {}
+//~^ ERROR
--- /dev/null
+error[E0747]: constant provided when a type was expected
+ --> $DIR/issue-105334.rs:1:11
+ |
+LL | impl Vec< br##"*.."## > {}
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0747`.
--- /dev/null
+impl Vec<lol> {}
+//~^ ERROR
+
+pub fn lol() {}
--- /dev/null
+error[E0747]: constant provided when a type was expected
+ --> $DIR/issue-105737.rs:1:10
+ |
+LL | impl Vec<lol> {}
+ | ^^^
+ |
+ = help: `lol` is a function item, not a type
+ = help: function item types cannot be named directly
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0747`.
--- /dev/null
+// compile-flags: -Znormalize-docs
+
+use std::ops::Index;
+
+pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+ let _ = s;
+}
+
+pub trait SVec: Index<
+ <Self as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+ Output = <Index<<Self as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+ Output = <Self as SVec>::Item> as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+//~^^^^^ ERROR
+//~^^^^^^ ERROR
+//~^^^^^^^ ERROR
+//~^^^^^^^^ ERROR
+> {
+ type Item<'a, T>;
+
+ fn len(&self) -> <Self as SVec>::Item;
+ //~^ ERROR
+ //~^^ ERROR
+ //~^^^ ERROR
+ //~^^^^ ERROR
+}
--- /dev/null
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:13:21
+ |
+LL | <Self as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | <Self as SVec>::Item<'a>,
+ | ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:13:21
+ |
+LL | <Self as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | <Self as SVec>::Item<T>,
+ | +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:18:37
+ |
+LL | Output = <Index<<Self as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | Output = <Index<<Self as SVec>::Item<'a>,
+ | ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:18:37
+ |
+LL | Output = <Index<<Self as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | Output = <Index<<Self as SVec>::Item<T>,
+ | +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:30
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | Output = <Self as SVec>::Item<'a>> as SVec>::Item,
+ | ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:30
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | Output = <Self as SVec>::Item<T>> as SVec>::Item,
+ | +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:46
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item<'a>,
+ | ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:46
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item<T>,
+ | +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:5:40
+ |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item<'_> = T, Output = T>) {
+ | ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:5:40
+ |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item<T> = T, Output = T>) {
+ | +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:13:21
+ |
+LL | <Self as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | <Self as SVec>::Item<'a>,
+ | ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:13:21
+ |
+LL | <Self as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | <Self as SVec>::Item<T>,
+ | +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:18:37
+ |
+LL | Output = <Index<<Self as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | Output = <Index<<Self as SVec>::Item<'a>,
+ | ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:18:37
+ |
+LL | Output = <Index<<Self as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | Output = <Index<<Self as SVec>::Item<T>,
+ | +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:30
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | Output = <Self as SVec>::Item<'a>> as SVec>::Item,
+ | ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:30
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | Output = <Self as SVec>::Item<T>> as SVec>::Item,
+ | +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:46
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item<'a>,
+ | ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:46
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item<T>,
+ | +++
+
+error[E0038]: the trait `SVec` cannot be made into an object
+ --> $DIR/issue-105742.rs:5:31
+ |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` cannot be made into an object
+ |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+ --> $DIR/issue-105742.rs:12:17
+ |
+LL | pub trait SVec: Index<
+ | ____________----__^
+ | | |
+ | | this trait cannot be made into an object...
+LL | | <Self as SVec>::Item,
+LL | |
+LL | |
+... |
+LL | |/ Output = <Index<<Self as SVec>::Item,
+LL | ||
+LL | ||
+LL | ||
+LL | ||
+LL | || Output = <Self as SVec>::Item> as SVec>::Item,
+ | ||_________________________________________________^ ...because it uses `Self` as a type parameter
+... |
+LL | |
+LL | | > {
+ | |__^ ...because it uses `Self` as a type parameter
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:35:38
+ |
+LL | fn len(&self) -> <Self as SVec>::Item;
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | fn len(&self) -> <Self as SVec>::Item<'_>;
+ | ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:35:38
+ |
+LL | fn len(&self) -> <Self as SVec>::Item;
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | fn len(&self) -> <Self as SVec>::Item<T>;
+ | +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:35:38
+ |
+LL | fn len(&self) -> <Self as SVec>::Item;
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | fn len(&self) -> <Self as SVec>::Item<'_>;
+ | ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:35:38
+ |
+LL | fn len(&self) -> <Self as SVec>::Item;
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | fn len(&self) -> <Self as SVec>::Item<T>;
+ | +++
+
+error: aborting due to 23 previous errors
+
+Some errors have detailed explanations: E0038, E0107.
+For more information about an error, try `rustc --explain E0038`.
--- /dev/null
+// compile-flags: --document-private-items
+// edition:2021
+
+fn use_avx() -> dyn {
+ //~^ ERROR at least one trait is required for an object type
+ !( ident_error )
+}
--- /dev/null
+error[E0224]: at least one trait is required for an object type
+ --> $DIR/issue-106213.rs:4:17
+ |
+LL | fn use_avx() -> dyn {
+ | ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0224`.
--- /dev/null
+// This is a regression test for <https://github.com/rust-lang/rust/issues/106226>.
+type F = [_; ()];
+//~^ ERROR
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-106226.rs:2:14
+ |
+LL | type F = [_; ()];
+ | ^^ expected `usize`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+pub trait TraitWithAssoc {
+ type Assoc;
+}
+
+pub type Foo<V> = impl Trait<V::Assoc>;
+//~^ ERROR
+//~^^ ERROR
+
+pub trait Trait<U> {}
+
+impl<W> Trait<W> for () {}
+
+pub fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T> {
+ ()
+}
--- /dev/null
+error[E0220]: associated type `Assoc` not found for `V`
+ --> $DIR/issue-96287.rs:7:33
+ |
+LL | pub type Foo<V> = impl Trait<V::Assoc>;
+ | ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
+
+error[E0220]: associated type `Assoc` not found for `V`
+ --> $DIR/issue-96287.rs:7:33
+ |
+LL | pub type Foo<V> = impl Trait<V::Assoc>;
+ | ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0220`.
-Z branch-protection=val -- set options for branch target identification and pointer authentication on AArch64
-Z cf-protection=val -- instrument control-flow architecture protection
-Z cgu-partitioning-strategy=val -- the codegen unit partitioning strategy to use
- -Z chalk=val -- enable the experimental Chalk-based trait solving engine
-Z codegen-backend=val -- the backend to use
-Z combine-cgu=val -- combine CGUs into a single one
-Z crate-attr=val -- inject the given attribute in the crate
-Z dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no)
-Z dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no)
-Z dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans.
- -Z dump-mono-stats=val -- output statistics about monomorphization collection (format: markdown)
+ -Z dump-mono-stats=val -- output statistics about monomorphization collection
+ -Z dump-mono-stats-format=val -- the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)
-Z dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
-Z dylib-lto=val -- enables LTO for dylib crate type
-Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
-Z tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
-Z trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
-Z track-diagnostics=val -- tracks where in rustc a diagnostic was emitted
+ -Z trait-solver=val -- specify the trait solver mode used by rustc (default: classic)
-Z translate-additional-ftl=val -- additional fluent translation to preferentially use (for testing translation)
-Z translate-directionality-markers=val -- emit directionality isolation markers in translated diagnostics
-Z translate-lang=val -- language identifier for diagnostic output
// @has - '//pre[@class="rust fn"]' 'pub async fn elided(foo: &str) -> &str'
pub async fn elided(foo: &str) -> &str {}
// This should really be shown as written, but for implementation reasons it's difficult.
-// See `impl Clean for TyKind::Rptr`.
+// See `impl Clean for TyKind::Ref`.
// @has async_fn/fn.user_elided.html
// @has - '//pre[@class="rust fn"]' 'pub async fn user_elided(foo: &str) -> &str'
pub async fn user_elided(foo: &'_ str) -> &str {}
#[path = "src-links/mod.rs"]
pub mod qux;
+// @has src/foo/src-links.rs.html
+// @has foo/fizz/index.html '//a/@href' '../src/foo/src-links/fizz.rs.html'
+#[path = "src-links/../src-links/fizz.rs"]
+pub mod fizz;
+
// @has foo/bar/index.html '//a/@href' '../../src/foo/src-links.rs.html'
pub mod bar {
--- /dev/null
+pub struct Buzz;
extern crate rustc_macros;
extern crate rustc_serialize;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{MemDecoder, MemEncoder};
use rustc_serialize::{Decodable, Encodable, Encoder};
extern crate rustc_macros;
extern crate rustc_serialize;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{MemDecoder, MemEncoder};
use rustc_serialize::{Decodable, Encodable, Encoder};
extern crate rustc_macros;
extern crate rustc_serialize;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
mod submod {
use rustc_macros::{Decodable, Encodable};
use rustc_macros::{Decodable, Encodable};
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
pub const other: u8 = 1;
pub const f: u8 = 1;
pub const d: u8 = 1;
extern crate rustc_arena;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_arena::TypedArena;
trait HasId { fn count(&self) -> usize; }
extern crate rustc_macros;
extern crate rustc_serialize;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_macros::{Decodable, Encodable};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encodable, Decodable)]
extern crate rustc_macros;
extern crate rustc_serialize;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{MemDecoder, MemEncoder};
use rustc_serialize::{Decodable, Encodable, Encoder};
--- /dev/null
+// Test that we get the following hint when trying to use a compiler crate without rustc_driver.
+// error-pattern: try adding `extern crate rustc_driver;` at the top level of this crate
+// compile-flags: --emit link
+// The exactly list of required crates depends on the target. as such only test Unix targets.
+// only-unix
+
+#![feature(rustc_private)]
+
+extern crate rustc_serialize;
+
+fn main() {}
--- /dev/null
+error: crate `rustc_serialize` required to be available in rlib format, but was not found in this form
+ |
+ = help: try adding `extern crate rustc_driver;` at the top level of this crate
+
+error: crate `smallvec` required to be available in rlib format, but was not found in this form
+
+error: crate `thin_vec` required to be available in rlib format, but was not found in this form
+
+error: crate `indexmap` required to be available in rlib format, but was not found in this form
+
+error: crate `hashbrown` required to be available in rlib format, but was not found in this form
+
+error: crate `ahash` required to be available in rlib format, but was not found in this form
+
+error: crate `once_cell` required to be available in rlib format, but was not found in this form
+
+error: crate `getrandom` required to be available in rlib format, but was not found in this form
+
+error: crate `cfg_if` required to be available in rlib format, but was not found in this form
+
+error: crate `libc` required to be available in rlib format, but was not found in this form
+
+error: aborting due to 10 previous errors
+
extern crate rustc_session;
extern crate rustc_span;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_parse::new_parser_from_file;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::FilePathMapping;
extern crate rustc_span;
extern crate thin_vec;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_ast::mut_visit::{self, visit_clobber, MutVisitor};
use rustc_ast::ptr::P;
use rustc_ast::*;
extern crate rustc_arena;
extern crate libc;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use TypeStructure::{TypeInt, TypeFunction};
use AstKind::{ExprInt, ExprVar, ExprLambda};
use rustc_arena::TypedArena;
#[allow(dead_code)]
extern crate rustc_serialize;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_macros::{Decodable, Encodable};
#[derive(Decodable, Encodable, Debug)]
|
LL | #[alloc_error_handler]
| ---------------------- in this procedural macro expansion
-LL | fn oom(
- | __^
- | | _|
- | ||
+LL | // fn oom(
LL | || info: &Layout,
LL | || ) -> ()
| ||_______- arguments to this function are incorrect
|
LL | #[alloc_error_handler]
| ---------------------- in this procedural macro expansion
-LL | fn oom(
- | __^
- | | _|
- | ||
+LL | // fn oom(
LL | || info: &Layout,
LL | || ) -> ()
| ||_______^ expected `!`, found `()`
|
LL | #[alloc_error_handler]
| ---------------------- in this procedural macro expansion
-LL | fn oom(
- | __^
- | | _|
- | ||
+LL | // fn oom(
LL | || info: Layout,
LL | || ) {
| ||_- arguments to this function are incorrect
|
LL | #[alloc_error_handler]
| ---------------------- in this procedural macro expansion
-LL | fn oom(
- | __^
- | | _|
- | ||
+LL | // fn oom(
LL | || info: Layout,
LL | || ) {
| ||_^ expected `!`, found `()`
struct Layout;
#[alloc_error_handler]
-fn oom() -> ! { //~ ERROR this function takes 0 arguments but 1 argument was supplied
+fn oom() -> ! { //~ ERROR function takes 0 arguments but 1 argument was supplied
loop {}
}
fn main() {
invalid(1.0); //~ ERROR mismatched types
- extra(""); //~ ERROR this function takes
- missing(); //~ ERROR this function takes
+ extra(""); //~ ERROR function takes
+ missing(); //~ ERROR function takes
swapped("", 1); //~ ERROR arguments to this function are incorrect
permuted(Y {}, Z {}, X {}); //~ ERROR arguments to this function are incorrect
let closure = |x| x;
- closure(); //~ ERROR this function takes
+ closure(); //~ ERROR function takes
}
fn main() {
foo();
- //~^ ERROR this function takes 1 argument but 0 arguments were supplied
+ //~^ ERROR function takes 1 argument but 0 arguments were supplied
}
fn foo<T: Fn()>(t: T) {
t(1i32);
- //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+ //~^ ERROR function takes 0 arguments but 1 argument was supplied
}
fn bar(t: impl Fn()) {
t(1i32);
- //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+ //~^ ERROR function takes 0 arguments but 1 argument was supplied
}
fn baz() -> impl Fn() {
fn baz2() {
baz()(1i32)
- //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+ //~^ ERROR function takes 0 arguments but 1 argument was supplied
}
fn qux() {
let x = || {};
x(1i32);
- //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+ //~^ ERROR function takes 0 arguments but 1 argument was supplied
}
fn main() {}
--- /dev/null
+extern "Rust" {
+ fn dstfn(src: i32, dst: err);
+ //~^ ERROR cannot find type `err` in this scope
+}
+
+fn main() {
+ dstfn(1);
+ //~^ ERROR function takes 2 arguments but 1 argument was supplied
+}
--- /dev/null
+error[E0412]: cannot find type `err` in this scope
+ --> $DIR/extern-fn-arg-names.rs:2:29
+ |
+LL | fn dstfn(src: i32, dst: err);
+ | ^^^ not found in this scope
+
+error[E0061]: this function takes 2 arguments but 1 argument was supplied
+ --> $DIR/extern-fn-arg-names.rs:7:5
+ |
+LL | dstfn(1);
+ | ^^^^^--- an argument is missing
+ |
+note: function defined here
+ --> $DIR/extern-fn-arg-names.rs:2:8
+ |
+LL | fn dstfn(src: i32, dst: err);
+ | ^^^^^
+help: provide the argument
+ |
+LL | dstfn(1, /* dst */);
+ | ~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0061, E0412.
+For more information about an error, try `rustc --explain E0061`.
fn two_arg_diff(_a: i32, _b: &str) {}
fn main() {
- empty(""); //~ ERROR this function takes
+ empty(""); //~ ERROR function takes
- one_arg(1, 1); //~ ERROR this function takes
- one_arg(1, ""); //~ ERROR this function takes
- one_arg(1, "", 1.0); //~ ERROR this function takes
+ one_arg(1, 1); //~ ERROR function takes
+ one_arg(1, ""); //~ ERROR function takes
+ one_arg(1, "", 1.0); //~ ERROR function takes
- two_arg_same(1, 1, 1); //~ ERROR this function takes
- two_arg_same(1, 1, 1.0); //~ ERROR this function takes
+ two_arg_same(1, 1, 1); //~ ERROR function takes
+ two_arg_same(1, 1, 1.0); //~ ERROR function takes
- two_arg_diff(1, 1, ""); //~ ERROR this function takes
- two_arg_diff(1, "", ""); //~ ERROR this function takes
- two_arg_diff(1, 1, "", ""); //~ ERROR this function takes
- two_arg_diff(1, "", 1, ""); //~ ERROR this function takes
+ two_arg_diff(1, 1, ""); //~ ERROR function takes
+ two_arg_diff(1, "", ""); //~ ERROR function takes
+ two_arg_diff(1, 1, "", ""); //~ ERROR function takes
+ two_arg_diff(1, "", 1, ""); //~ ERROR function takes
// Check with weird spacing and newlines
- two_arg_same(1, 1, ""); //~ ERROR this function takes
- two_arg_diff(1, 1, ""); //~ ERROR this function takes
- two_arg_same( //~ ERROR this function takes
+ two_arg_same(1, 1, ""); //~ ERROR function takes
+ two_arg_diff(1, 1, ""); //~ ERROR function takes
+ two_arg_same( //~ ERROR function takes
1,
1,
""
);
- two_arg_diff( //~ ERROR this function takes
+ two_arg_diff( //~ ERROR function takes
1,
1,
""
fn main() {
foo::<()>(());
- //~^ ERROR this function takes 0 generic arguments but 1 generic argument was supplied
+ //~^ ERROR function takes 0 generic arguments but 1 generic argument was supplied
//~| ERROR `()` doesn't implement `std::fmt::Display`
}
fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {}
fn main() {
- three_diff(T2::new(0)); //~ ERROR this function takes
+ three_diff(T2::new(0)); //~ ERROR function takes
four_shuffle(T3::default(), T4::default(), T1::default(), T2::default()); //~ ERROR 35:5: 35:17: arguments to this function are incorrect [E0308]
four_shuffle(T3::default(), T2::default(), T1::default(), T3::default()); //~ ERROR 36:5: 36:17: arguments to this function are incorrect [E0308]
) {}
fn main() {
- f(C, A, A, A, B, B, C); //~ ERROR this function takes 6 arguments but 7 arguments were supplied [E0061]
+ f(C, A, A, A, B, B, C); //~ ERROR function takes 6 arguments but 7 arguments were supplied [E0061]
f(C, C, A, A, B, B); //~ ERROR arguments to this function are incorrect [E0308]
f(A, A, D, D, B, B); //~ arguments to this function are incorrect [E0308]
f(C, C, B, B, A, A); //~ arguments to this function are incorrect [E0308]
fn main() {
let x = arg(); // `x` must be inferred
// The reference on `&x` is important to reproduce the ICE
- f(&x, ""); //~ ERROR this function takes 3 arguments but 2 arguments were supplied
+ f(&x, ""); //~ ERROR function takes 3 arguments but 2 arguments were supplied
}
fn main() {
g((), ());
- //~^ ERROR this function takes 6 arguments but 2 arguments were supplied
+ //~^ ERROR function takes 6 arguments but 2 arguments were supplied
}
pub fn g(a1: (), a2: bool, a3: bool, a4: bool, a5: bool, a6: ()) -> () {}
fn main() {
foo(&&A, B, C, D, E, F, G);
- //~^ ERROR this function takes 4 arguments but 7 arguments were supplied
+ //~^ ERROR function takes 4 arguments but 7 arguments were supplied
}
fn main() {
(|_, ()| ())(if true {} else {return;});
- //~^ ERROR this function takes 2 arguments but 1 argument was supplied
+ //~^ ERROR function takes 2 arguments but 1 argument was supplied
}
fn main() {
(|_, ()| ())([return, ()]);
- //~^ ERROR this function takes 2 arguments but 1 argument was supplied
+ //~^ ERROR function takes 2 arguments but 1 argument was supplied
}
fn main() {
let f = |_: (), f: fn()| f;
let _f = f(main);
- //~^ ERROR this function takes 2 arguments but 1 argument was supplied
+ //~^ ERROR function takes 2 arguments but 1 argument was supplied
}
fn complex(_a: i32, _b: f32, _c: i32, _d: f32, _e: &str) {}
fn main() {
- one_arg(); //~ ERROR this function takes
+ one_arg(); //~ ERROR function takes
// The headers here show the types expected,
// with formatting to emphasize which arguments are missing
/* i32 f32 */
- two_same( ); //~ ERROR this function takes
- two_same( 1 ); //~ ERROR this function takes
- two_diff( ); //~ ERROR this function takes
- two_diff( 1 ); //~ ERROR this function takes
- two_diff( 1.0 ); //~ ERROR this function takes
+ two_same( ); //~ ERROR function takes
+ two_same( 1 ); //~ ERROR function takes
+ two_diff( ); //~ ERROR function takes
+ two_diff( 1 ); //~ ERROR function takes
+ two_diff( 1.0 ); //~ ERROR function takes
/* i32 i32 i32 */
- three_same( ); //~ ERROR this function takes
- three_same( 1 ); //~ ERROR this function takes
- three_same( 1, 1 ); //~ ERROR this function takes
+ three_same( ); //~ ERROR function takes
+ three_same( 1 ); //~ ERROR function takes
+ three_same( 1, 1 ); //~ ERROR function takes
/* i32 f32 &str */
- three_diff( 1.0, "" ); //~ ERROR this function takes
- three_diff( 1, "" ); //~ ERROR this function takes
- three_diff( 1, 1.0 ); //~ ERROR this function takes
- three_diff( "" ); //~ ERROR this function takes
- three_diff( 1.0 ); //~ ERROR this function takes
- three_diff( 1 ); //~ ERROR this function takes
+ three_diff( 1.0, "" ); //~ ERROR function takes
+ three_diff( 1, "" ); //~ ERROR function takes
+ three_diff( 1, 1.0 ); //~ ERROR function takes
+ three_diff( "" ); //~ ERROR function takes
+ three_diff( 1.0 ); //~ ERROR function takes
+ three_diff( 1 ); //~ ERROR function takes
/* i32 f32 f32 &str */
- four_repeated( ); //~ ERROR this function takes
- four_repeated( 1, "" ); //~ ERROR this function takes
+ four_repeated( ); //~ ERROR function takes
+ four_repeated( 1, "" ); //~ ERROR function takes
/* i32 f32 i32 f32 &str */
- complex( ); //~ ERROR this function takes
- complex( 1, "" ); //~ ERROR this function takes
+ complex( ); //~ ERROR function takes
+ complex( 1, "" ); //~ ERROR function takes
}
fn main() {
// Extra + Invalid
- two_args(1, "", X {}); //~ ERROR this function takes
- three_args(1, "", X {}, ""); //~ ERROR this function takes
+ two_args(1, "", X {}); //~ ERROR function takes
+ three_args(1, "", X {}, ""); //~ ERROR function takes
// Missing and Invalid
- three_args(1, X {}); //~ ERROR this function takes
+ three_args(1, X {}); //~ ERROR function takes
// Missing and Extra
three_args(1, "", X {}); //~ ERROR arguments to this function are incorrect
three_args("", X {}, 1); //~ ERROR arguments to this function are incorrect
// Swapped and missing
- three_args("", 1); //~ ERROR this function takes
+ three_args("", 1); //~ ERROR function takes
}
LL | qux.foo(a, b, c, d, e, f, g, h, i, j, k, l);
| --- ^ expected `i32`, found `&i32`
| |
- | arguments to this function are incorrect
+ | arguments to this method are incorrect
|
note: associated function defined here
--> $DIR/too-long.rs:4:8
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/slice-mut-2.rs:7:18
|
-LL | let x: &[isize] = &[1, 2, 3, 4, 5];
- | ---------------- help: consider changing this to be a mutable reference: `&mut [1, 2, 3, 4, 5]`
-...
LL | let _ = &mut x[2..4];
| ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let x: &[isize] = &mut [1, 2, 3, 4, 5];
+ | ~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
| ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^
...
-LL | m!(in out lateout inout inlateout const sym
- | _____-
- | |_____|
- | |_____|
- | |_____|
- | |
+LL | / m!(in out lateout inout inlateout const sym
LL | | pure nomem readonly preserves_flags
LL | | noreturn nostack options);
| | -
// Outputs require mutable places
- let v: Vec<u64> = vec![0, 1, 2];
+ let v: Vec<u64> = vec![0, 1, 2]; //~ ERROR cannot borrow `v` as mutable
asm!("{}", in(reg) v[0]);
asm!("{}", out(reg) v[0]);
- //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
asm!("{}", inout(reg) v[0]);
- //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
// Sym operands must point to a function or static
}
| +++
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-2-2.rs:30:29
+ --> $DIR/type-check-2-2.rs:28:13
|
LL | let v: Vec<u64> = vec![0, 1, 2];
- | - help: consider changing this to be mutable: `mut v`
+ | ^ not mutable
LL | asm!("{}", in(reg) v[0]);
LL | asm!("{}", out(reg) v[0]);
- | ^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-2-2.rs:32:31
- |
-LL | let v: Vec<u64> = vec![0, 1, 2];
- | - help: consider changing this to be mutable: `mut v`
-...
+ | - cannot borrow as mutable
LL | asm!("{}", inout(reg) v[0]);
- | ^ cannot borrow as mutable
+ | - cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut v: Vec<u64> = vec![0, 1, 2];
+ | +++
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
Some errors have detailed explanations: E0381, E0596.
For more information about an error, try `rustc --explain E0381`.
LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
| ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^
...
-LL | m!(in out lateout inout inlateout const sym
- | _____-
- | |_____|
- | |_____|
- | |_____|
- | |
+LL | / m!(in out lateout inout inlateout const sym
LL | | pure nomem readonly preserves_flags
LL | | noreturn nostack att_syntax options);
| | -
// Outputs require mutable places
let v: Vec<u64> = vec![0, 1, 2];
+ //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
asm!("{}", in(reg) v[0]);
asm!("{}", out(reg) v[0]);
- //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
asm!("{}", inout(reg) v[0]);
- //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
// Sym operands must point to a function or static
| +++
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-5.rs:26:29
+ --> $DIR/type-check-5.rs:24:13
|
LL | let v: Vec<u64> = vec![0, 1, 2];
- | - help: consider changing this to be mutable: `mut v`
-LL | asm!("{}", in(reg) v[0]);
-LL | asm!("{}", out(reg) v[0]);
- | ^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-5.rs:28:31
- |
-LL | let v: Vec<u64> = vec![0, 1, 2];
- | - help: consider changing this to be mutable: `mut v`
+ | ^ not mutable
...
+LL | asm!("{}", out(reg) v[0]);
+ | - cannot borrow as mutable
LL | asm!("{}", inout(reg) v[0]);
- | ^ cannot borrow as mutable
+ | - cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut v: Vec<u64> = vec![0, 1, 2];
+ | +++
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
Some errors have detailed explanations: E0381, E0596.
For more information about an error, try `rustc --explain E0381`.
--- /dev/null
+pub trait TraitWAssocConst {
+ const A: usize;
+}
+pub struct Demo {}
+
+impl TraitWAssocConst for impl Demo { //~ ERROR E0404
+ //~^ ERROR E0562
+ pubconst A: str = 32; //~ ERROR expected one of
+}
+
+fn foo<A: TraitWAssocConst<A=32>>() { //~ ERROR E0658
+ foo::<Demo>()(); //~ ERROR E0271
+ //~^ ERROR E0618
+ //~| ERROR E0277
+}
+
+fn main<A: TraitWAssocConst<A=32>>() { //~ ERROR E0131
+ //~^ ERROR E0658
+ foo::<Demo>(); //~ ERROR E0277
+ //~^ ERROR E0271
+}
--- /dev/null
+error: expected one of `!` or `::`, found `A`
+ --> $DIR/issue-105330.rs:8:14
+ |
+LL | impl TraitWAssocConst for impl Demo {
+ | - while parsing this item list starting here
+LL |
+LL | pubconst A: str = 32;
+ | ^ expected one of `!` or `::`
+LL | }
+ | - the item list ends here
+
+error[E0404]: expected trait, found struct `Demo`
+ --> $DIR/issue-105330.rs:6:32
+ |
+LL | impl TraitWAssocConst for impl Demo {
+ | ^^^^ not a trait
+
+error[E0658]: associated const equality is incomplete
+ --> $DIR/issue-105330.rs:11:28
+ |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+ | ^^^^
+ |
+ = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+ = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error[E0658]: associated const equality is incomplete
+ --> $DIR/issue-105330.rs:17:29
+ |
+LL | fn main<A: TraitWAssocConst<A=32>>() {
+ | ^^^^
+ |
+ = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+ = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
+ --> $DIR/issue-105330.rs:6:27
+ |
+LL | impl TraitWAssocConst for impl Demo {
+ | ^^^^^^^^^
+
+error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
+ --> $DIR/issue-105330.rs:12:11
+ |
+LL | foo::<Demo>()();
+ | ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
+ |
+note: required by a bound in `foo`
+ --> $DIR/issue-105330.rs:11:11
+ |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+ | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
+ --> $DIR/issue-105330.rs:12:11
+ |
+LL | foo::<Demo>()();
+ | ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
+ |
+ = note: expected constant `32`
+ found constant `<Demo as TraitWAssocConst>::A`
+note: required by a bound in `foo`
+ --> $DIR/issue-105330.rs:11:28
+ |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+ | ^^^^ required by this bound in `foo`
+
+error[E0618]: expected function, found `()`
+ --> $DIR/issue-105330.rs:12:5
+ |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+ | ----------------------------------- `foo::<Demo>` defined here returns `()`
+LL | foo::<Demo>()();
+ | ^^^^^^^^^^^^^--
+ | |
+ | call expression requires function
+
+error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
+ --> $DIR/issue-105330.rs:19:11
+ |
+LL | foo::<Demo>();
+ | ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
+ |
+note: required by a bound in `foo`
+ --> $DIR/issue-105330.rs:11:11
+ |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+ | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
+ --> $DIR/issue-105330.rs:19:11
+ |
+LL | foo::<Demo>();
+ | ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
+ |
+ = note: expected constant `32`
+ found constant `<Demo as TraitWAssocConst>::A`
+note: required by a bound in `foo`
+ --> $DIR/issue-105330.rs:11:28
+ |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+ | ^^^^ required by this bound in `foo`
+
+error[E0131]: `main` function is not allowed to have generic parameters
+ --> $DIR/issue-105330.rs:17:8
+ |
+LL | fn main<A: TraitWAssocConst<A=32>>() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` cannot have generic parameters
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0131, E0271, E0277, E0404, E0562, E0618, E0658.
+For more information about an error, try `rustc --explain E0131`.
LL | fn f() { ModelT.chip_paint(Blue); }
| ---------- ^^^^ expected struct `Black`, found struct `Blue`
| |
- | arguments to this function are incorrect
+ | arguments to this method are incorrect
|
note: associated function defined here
--> $DIR/associated-type-projection-from-supertrait.rs:12:8
LL | fn g() { ModelU.chip_paint(Black); }
| ---------- ^^^^^ expected struct `Blue`, found struct `Black`
| |
- | arguments to this function are incorrect
+ | arguments to this method are incorrect
|
note: associated function defined here
--> $DIR/associated-type-projection-from-supertrait.rs:12:8
error[E0277]: the trait bound `Self: Get` is not satisfied
- --> $DIR/associated-types-for-unimpl-trait.rs:10:5
+ --> $DIR/associated-types-for-unimpl-trait.rs:10:40
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+ | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|
error[E0277]: the trait bound `T: Get` is not satisfied
- --> $DIR/associated-types-no-suitable-bound.rs:11:5
+ --> $DIR/associated-types-no-suitable-bound.rs:11:21
|
LL | fn uhoh<T>(foo: <T as Get>::Value) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
+ | ^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
|
help: consider restricting type parameter `T`
|
error[E0277]: the trait bound `Self: Get` is not satisfied
- --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:5
+ --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:40
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+ | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|
error[E0277]: the trait bound `(T, U): Get` is not satisfied
- --> $DIR/associated-types-no-suitable-supertrait.rs:22:5
+ --> $DIR/associated-types-no-suitable-supertrait.rs:22:40
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`
+ | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`
error[E0277]: the trait bound `Self: Get` is not satisfied
- --> $DIR/associated-types-no-suitable-supertrait.rs:17:5
+ --> $DIR/associated-types-no-suitable-supertrait.rs:17:40
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+ | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|
error[E0277]: the trait bound `Self: Get` is not satisfied
- --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:5
+ --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:40
|
LL | fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+ | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|
|
LL | fn make() -> Self::Ty {
| ^^^^^^^^
- = note: expected fn pointer `fn() -> <A<T> as Tr>::Ty`
- found fn pointer `fn() -> u8`
+ = note: expected signature `fn() -> <A<T> as Tr>::Ty`
+ found signature `fn() -> u8`
error[E0053]: method `make` has an incompatible type for trait
--> $DIR/defaults-specialization.rs:35:18
|
LL | fn make() -> Self::Ty {
| ^^^^^^^^
- = note: expected fn pointer `fn() -> <B<T> as Tr>::Ty`
- found fn pointer `fn() -> bool`
+ = note: expected signature `fn() -> <B<T> as Tr>::Ty`
+ found signature `fn() -> bool`
error[E0308]: mismatched types
--> $DIR/defaults-specialization.rs:10:9
--- /dev/null
+// run-pass
+struct S<T: 'static>(#[allow(unused_tuple_struct_fields)] Option<&'static T>);
+
+trait Tr { type Out; }
+impl<T> Tr for T { type Out = T; }
+
+impl<T: 'static> Copy for S<T> where S<T>: Tr<Out=T> {}
+impl<T: 'static> Clone for S<T> where S<T>: Tr<Out=T> {
+ fn clone(&self) -> Self { *self }
+}
+fn main() {
+ S::<()>(None);
+}
--- /dev/null
+// run-pass
+pub trait Parser {
+ type Input;
+}
+
+pub struct Iter<P: Parser>(#[allow(unused_tuple_struct_fields)] P, P::Input);
+
+#[allow(unused_tuple_struct_fields)]
+pub struct Map<P, F>(P, F);
+impl<P, F> Parser for Map<P, F> where F: FnMut(P) {
+ type Input = u8;
+}
+
+trait AstId { type Untyped; }
+impl AstId for u32 { type Untyped = u32; }
+
+fn record_type<Id: AstId>(i: Id::Untyped) -> u8 {
+ Iter(Map(i, |_: Id::Untyped| {}), 42).1
+}
+
+pub fn main() {
+ assert_eq!(record_type::<u32>(3), 42);
+}
--- /dev/null
+struct S<T: 'static>(#[allow(unused_tuple_struct_fields)] Option<&'static T>);
+
+trait Tr { type Out; }
+impl<T> Tr for T { type Out = T; }
+
+impl<T: 'static> Copy for S<T> where S<T>: Tr<Out=T> {}
+impl<T: 'static> Clone for S<T> where S<T>: Tr<Out=T> {
+ fn clone(&self) -> Self { *self }
+}
+fn main() {
+ let t = S::<()>(None);
+ drop(t);
+ drop(t); //~ ERROR use of moved value
+}
--- /dev/null
+error[E0382]: use of moved value: `t`
+ --> $DIR/issue-25700.rs:13:10
+ |
+LL | let t = S::<()>(None);
+ | - move occurs because `t` has type `S<()>`, which does not implement the `Copy` trait
+LL | drop(t);
+ | - value moved here
+LL | drop(t);
+ | ^ value used here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
{
fn get_service(
//~^ ERROR the trait bound `Bug: Foo` is not satisfied
- //~| ERROR the trait bound `Bug: Foo` is not satisfied
&self,
) -> Self::AssocType;
+ //~^ ERROR the trait bound `Bug: Foo` is not satisfied
}
fn with_factory<H>(factory: dyn ThriftService<()>) {}
LL | |
LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
... |
-LL | | ) -> Self::AssocType;
+LL | |
LL | | }
| |_^ the trait `Foo` is not implemented for `Bug`
|
|
LL | / fn get_service(
LL | |
-LL | |
LL | | &self,
LL | | ) -> Self::AssocType;
| |_________________________^ the trait `Foo` is not implemented for `Bug`
| +++++
error[E0277]: the trait bound `(): Foo` is not satisfied
- --> $DIR/issue-59324.rs:23:1
+ --> $DIR/issue-59324.rs:23:29
|
LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+ | ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
error[E0277]: the trait bound `Bug: Foo` is not satisfied
- --> $DIR/issue-59324.rs:16:5
+ --> $DIR/issue-59324.rs:19:10
|
-LL | / fn get_service(
-LL | |
-LL | |
-LL | | &self,
-LL | | ) -> Self::AssocType;
- | |_________________________^ the trait `Foo` is not implemented for `Bug`
+LL | ) -> Self::AssocType;
+ | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
|
help: consider further restricting this bound
|
|
LL | fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: expected fn pointer `fn(&i32) -> Pin<Box<dyn Future<Output = i32>>>`
- found fn pointer `fn(&i32) -> impl Future<Output = i32>`
+ = note: expected signature `fn(&i32) -> Pin<Box<dyn Future<Output = i32>>>`
+ found signature `fn(&i32) -> impl Future<Output = i32>`
error: aborting due to previous error
--- /dev/null
+// check-pass
+// edition:2018
+
+// This is a regression test for https://github.com/rust-lang/rust/issues/105501.
+// It was minified from the published `msf-ice:0.2.1` crate which failed in a crater run.
+// A faulty compiler was triggering a `higher-ranked lifetime error`:
+//
+// > could not prove `[async block@...]: Send`
+
+use mini_futures::Stream;
+
+fn is_send(_: impl Send) {}
+
+pub fn main() {
+ let fut = async {
+ let mut stream = mini_futures::iter([()])
+ .then(|_| async {})
+ .map(|_| async { None })
+ .buffered()
+ .filter_map(std::future::ready);
+
+ stream.next().await
+ };
+
+ is_send(async move {
+ let _: Option<()> = fut.await;
+ });
+}
+
+// this is a simplified subset of `futures::StreamExt` and related types
+mod mini_futures {
+ use std::future::Future;
+ use std::pin::Pin;
+ use std::task::{Context, Poll};
+
+ pub fn iter<I>(_: I) -> Iter<I::IntoIter>
+ where
+ I: IntoIterator,
+ {
+ todo!()
+ }
+
+ pub trait Stream {
+ type Item;
+
+ fn then<Fut, F>(self, _: F) -> Then<Self, Fut, F>
+ where
+ F: FnMut(Self::Item) -> Fut,
+ Fut: Future,
+ Self: Sized,
+ {
+ todo!()
+ }
+
+ fn map<T, F>(self, _: F) -> Map<Self, F>
+ where
+ F: FnMut(Self::Item) -> T,
+ Self: Sized,
+ {
+ todo!()
+ }
+
+ fn buffered(self) -> Buffered<Self>
+ where
+ Self::Item: Future,
+ Self: Sized,
+ {
+ todo!()
+ }
+
+ fn filter_map<Fut, T, F>(self, _: F) -> FilterMap<Self, Fut, F>
+ where
+ F: FnMut(Self::Item) -> Fut,
+ Fut: Future<Output = Option<T>>,
+ Self: Sized,
+ {
+ todo!()
+ }
+
+ fn next(&mut self) -> Next<'_, Self> {
+ todo!()
+ }
+ }
+
+ pub struct Iter<I> {
+ __: I,
+ }
+ impl<I> Stream for Iter<I>
+ where
+ I: Iterator,
+ {
+ type Item = I::Item;
+ }
+
+ pub struct Then<St, Fut, F> {
+ __: (St, Fut, F),
+ }
+ impl<St, Fut, F> Stream for Then<St, Fut, F>
+ where
+ St: Stream,
+ F: FnMut(St::Item) -> Fut,
+ Fut: Future,
+ {
+ type Item = Fut::Output;
+ }
+
+ pub struct Map<St, F> {
+ __: (St, F),
+ }
+ impl<St, F> Stream for Map<St, F>
+ where
+ St: Stream,
+ F: FnMut1<St::Item>,
+ {
+ type Item = F::Output;
+ }
+
+ pub trait FnMut1<A> {
+ type Output;
+ }
+ impl<T, A, R> FnMut1<A> for T
+ where
+ T: FnMut(A) -> R,
+ {
+ type Output = R;
+ }
+
+ pub struct Buffered<St>
+ where
+ St: Stream,
+ St::Item: Future,
+ {
+ __: (St, St::Item),
+ }
+ impl<St> Stream for Buffered<St>
+ where
+ St: Stream,
+ St::Item: Future,
+ {
+ type Item = <St::Item as Future>::Output;
+ }
+
+ pub struct FilterMap<St, Fut, F> {
+ __: (St, Fut, F),
+ }
+ impl<St, Fut, F, T> Stream for FilterMap<St, Fut, F>
+ where
+ St: Stream,
+ F: FnMut1<St::Item, Output = Fut>,
+ Fut: Future<Output = Option<T>>,
+ {
+ type Item = T;
+ }
+
+ pub struct Next<'a, St: ?Sized> {
+ __: &'a mut St,
+ }
+ impl<St: ?Sized + Stream> Future for Next<'_, St> {
+ type Output = Option<St::Item>;
+
+ fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
+ todo!()
+ }
+ }
+}
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/issue-61452.rs:4:5
|
-LL | pub async fn f(x: Option<usize>) {
- | - help: consider changing this to be mutable: `mut x`
LL | x.take();
| ^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | pub async fn f(mut x: Option<usize>) {
+ | +++
error[E0384]: cannot assign twice to immutable variable `x`
--> $DIR/issue-61452.rs:9:5
error[E0596]: cannot borrow `data` as mutable, as it is not declared as mutable
--> $DIR/issue-61187.rs:6:5
|
-LL | async fn response(data: Vec<u8>) {
- | ---- help: consider changing this to be mutable: `mut data`
LL | data.reverse();
| ^^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | async fn response(mut data: Vec<u8>) {
+ | +++
error: aborting due to previous error
--- /dev/null
+// run-pass
+// This test checks if an unstable feature is enabled with the -Zcrate-attr=feature(foo) flag. If
+// the exact feature used here is causing problems feel free to replace it with another
+// perma-unstable feature.
+
+// compile-flags: -Zcrate-attr=feature(abi_unadjusted)
+
+#![allow(dead_code)]
+
+extern "unadjusted" fn foo() {}
+
+fn main() {}
let y = Int(2);
//~^ HELP consider changing this to be mutable
- //~| SUGGESTION mut y
+ //~| SUGGESTION mut
y //~ ERROR cannot borrow `y` as mutable, as it is not declared as mutable
//~| cannot borrow as mutable
+=
error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
--> $DIR/augmented-assignments.rs:23:5
|
-LL | let y = Int(2);
- | - help: consider changing this to be mutable: `mut y`
-...
LL | y
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut y = Int(2);
+ | +++
error: aborting due to 2 previous errors
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrow-raw-address-of-deref-mutability.rs:8:13
|
-LL | let x = &0;
- | -- help: consider changing this to be a mutable reference: `&mut 0`
-LL |
LL | let q = &raw mut *x;
| ^^^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let x = &mut 0;
+ | ~~~~~~
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer
--> $DIR/borrow-raw-address-of-deref-mutability.rs:14:13
|
-LL | let x = &0 as *const i32;
- | -- help: consider changing this to be a mutable pointer: `&mut 0`
-LL |
LL | let q = &raw mut *x;
| ^^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable pointer
+ |
+LL | let x = &mut 0 as *const i32;
+ | ~~~~~~
error: aborting due to 2 previous errors
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrow-raw-address-of-mutability.rs:5:13
|
-LL | let x = 0;
- | - help: consider changing this to be mutable: `mut x`
LL | let y = &raw mut x;
| ^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x = 0;
+ | +++
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrow-raw-address-of-mutability.rs:11:17
error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
--> $DIR/borrow-raw-address-of-mutability.rs:21:5
|
-LL | let f = || {
- | - help: consider changing this to be mutable: `mut f`
LL | let y = &raw mut x;
| - calling `f` requires mutable binding due to mutable borrow of `x`
LL | };
LL | f();
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut f = || {
+ | +++
error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-raw-address-of-mutability.rs:29:17
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-access-permissions.rs:9:19
|
-LL | let x = 1;
- | - help: consider changing this to be mutable: `mut x`
-...
LL | let _y1 = &mut x;
| ^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x = 1;
+ | +++
error[E0596]: cannot borrow immutable static item `static_x` as mutable
--> $DIR/borrowck-access-permissions.rs:14:19
error[E0596]: cannot borrow `*box_x` as mutable, as `box_x` is not declared as mutable
--> $DIR/borrowck-access-permissions.rs:22:19
|
-LL | let box_x = Box::new(1);
- | ----- help: consider changing this to be mutable: `mut box_x`
-...
LL | let _y1 = &mut *box_x;
| ^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut box_x = Box::new(1);
+ | +++
error[E0596]: cannot borrow `*ref_x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-access-permissions.rs:30:19
|
-LL | let ref_x = &x;
- | -- help: consider changing this to be a mutable reference: `&mut x`
-...
LL | let _y1 = &mut *ref_x;
| ^^^^^^^^^^^ `ref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let ref_x = &mut x;
+ | ~~~~~~
error[E0596]: cannot borrow `*ptr_x` as mutable, as it is behind a `*const` pointer
--> $DIR/borrowck-access-permissions.rs:39:23
|
-LL | let ptr_x : *const _ = &x;
- | -- help: consider changing this to be a mutable pointer: `&mut x`
-...
LL | let _y1 = &mut *ptr_x;
| ^^^^^^^^^^^ `ptr_x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable pointer
+ |
+LL | let ptr_x : *const _ = &mut x;
+ | ~~~~~~
error[E0596]: cannot borrow `*foo_ref.f` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-access-permissions.rs:48:18
|
-LL | let foo_ref = &foo;
- | ---- help: consider changing this to be a mutable reference: `&mut foo`
LL | let _y = &mut *foo_ref.f;
| ^^^^^^^^^^^^^^^ `foo_ref` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let foo_ref = &mut foo;
+ | ~~~~~~~~
error: aborting due to 6 previous errors
error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
--> $DIR/borrowck-argument.rs:10:5
|
-LL | fn func(arg: S) {
- | --- help: consider changing this to be mutable: `mut arg`
LL | arg.mutate();
| ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn func(mut arg: S) {
+ | +++
error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
--> $DIR/borrowck-argument.rs:15:9
|
-LL | fn method(&self, arg: S) {
- | --- help: consider changing this to be mutable: `mut arg`
LL | arg.mutate();
| ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn method(&self, mut arg: S) {
+ | +++
error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
--> $DIR/borrowck-argument.rs:21:9
|
-LL | fn default(&self, arg: S) {
- | --- help: consider changing this to be mutable: `mut arg`
LL | arg.mutate();
| ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn default(&self, mut arg: S) {
+ | +++
error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
--> $DIR/borrowck-argument.rs:32:17
|
LL | (|arg: S| { arg.mutate() })(s);
- | --- ^^^^^^^^^^^^ cannot borrow as mutable
- | |
- | help: consider changing this to be mutable: `mut arg`
+ | ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | (|mut arg: S| { arg.mutate() })(s);
+ | +++
error: aborting due to 4 previous errors
error[E0594]: cannot assign to `*s.pointer`, which is behind a `&` reference
--> $DIR/borrowck-assign-to-andmut-in-aliasable-loc.rs:9:5
|
-LL | fn a(s: &S) {
- | -- help: consider changing this to be a mutable reference: `&mut S<'_>`
LL | *s.pointer += 1;
| ^^^^^^^^^^^^^^^ `s` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn a(s: &mut S<'_>) {
+ | ~~~~~~~~~~
error[E0594]: cannot assign to `*s.pointer`, which is behind a `&` reference
--> $DIR/borrowck-assign-to-andmut-in-aliasable-loc.rs:17:5
|
-LL | fn c(s: & &mut S) {
- | -------- help: consider changing this to be a mutable reference: `&mut &mut S<'_>`
LL | *s.pointer += 1;
| ^^^^^^^^^^^^^^^ `s` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn c(s: &mut &mut S<'_>) {
+ | ~~~~~~~~~~~~~~~
error: aborting due to 2 previous errors
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-auto-mut-ref-to-immut-var.rs:15:5
|
-LL | let x = Foo { x: 3 };
- | - help: consider changing this to be mutable: `mut x`
LL | x.printme();
| ^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x = Foo { x: 3 };
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable
--> $DIR/borrowck-borrow-from-owned-ptr.rs:122:16
|
-LL | let foo = make_foo();
- | --- help: consider changing this to be mutable: `mut foo`
LL | let bar1 = &mut foo.bar1;
| ^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut foo = make_foo();
+ | +++
error: aborting due to 11 previous errors
error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable
--> $DIR/borrowck-borrow-from-stack-variable.rs:120:16
|
-LL | let foo = make_foo();
- | --- help: consider changing this to be mutable: `mut foo`
LL | let bar1 = &mut foo.bar1;
| ^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut foo = make_foo();
+ | +++
error: aborting due to 11 previous errors
error[E0596]: cannot borrow `*a` as mutable, as `a` is not declared as mutable
--> $DIR/borrowck-borrow-immut-deref-of-box-as-mut.rs:12:5
|
-LL | let a: Box<_> = Box::new(A);
- | - help: consider changing this to be mutable: `mut a`
LL | a.foo();
| ^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut a: Box<_> = Box::new(A);
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `**t0` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:19:26
|
-LL | fn foo4(t0: & &mut isize) {
- | ------------ help: consider changing this to be a mutable reference: `&mut &mut isize`
LL | let x: &mut isize = &mut **t0;
| ^^^^^^^^^ `t0` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn foo4(t0: &mut &mut isize) {
+ | ~~~~~~~~~~~~~~~
error: aborting due to 3 previous errors
+#![feature(if_let_guard)]
+
fn foo(_:String) {}
fn main()
Some(_) => {}
None => { foo(my_str); } //~ ERROR [E0382]
}
+
+ let my_str = "hello".to_owned();
+ match Some(42) {
+ Some(_) if let Some(()) = { drop(my_str); None } => {}
+ Some(_) => {}
+ None => { foo(my_str); } //~ ERROR [E0382]
+ }
}
error[E0382]: use of moved value: `my_str`
- --> $DIR/borrowck-drop-from-guard.rs:9:23
+ --> $DIR/borrowck-drop-from-guard.rs:11:23
|
LL | let my_str = "hello".to_owned();
| ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
LL | Some(_) if { drop(my_str.clone()); false } => {}
| ++++++++
-error: aborting due to previous error
+error[E0382]: use of moved value: `my_str`
+ --> $DIR/borrowck-drop-from-guard.rs:18:23
+ |
+LL | let my_str = "hello".to_owned();
+ | ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
+LL | match Some(42) {
+LL | Some(_) if let Some(()) = { drop(my_str); None } => {}
+ | ------ value moved here
+LL | Some(_) => {}
+LL | None => { foo(my_str); }
+ | ^^^^^^ value used here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | Some(_) if let Some(()) = { drop(my_str.clone()); None } => {}
+ | ++++++++
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0382`.
error[E0594]: cannot assign to `***p`, which is behind a `&` reference
--> $DIR/borrowck-issue-14498.rs:16:5
|
-LL | let p = &y;
- | -- help: consider changing this to be a mutable reference: `&mut y`
LL | ***p = 2;
| ^^^^^^^^ `p` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let p = &mut y;
+ | ~~~~~~
error[E0506]: cannot assign to `**y` because it is borrowed
--> $DIR/borrowck-issue-14498.rs:25:5
|
note: `into_iter` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+help: you can `clone` the value and consume it, but this might not be your desired behavior
+ |
+LL | let _x = Rc::new(vec![1, 2]).clone().into_iter();
+ | ++++++++
error: aborting due to previous error
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-mut-addr-of-imm-var.rs:3:25
|
-LL | let x: isize = 3;
- | - help: consider changing this to be mutable: `mut x`
LL | let y: &mut isize = &mut x;
| ^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x: isize = 3;
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
--> $DIR/borrowck-mut-slice-of-imm-vec.rs:7:11
|
-LL | let v = vec![1, 2, 3];
- | - help: consider changing this to be mutable: `mut v`
LL | write(&mut v);
| ^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut v = vec![1, 2, 3];
+ | +++
error: aborting due to previous error
+#![feature(if_let_guard)]
+
enum Enum<'a> {
A(&'a isize),
B(bool),
}
-fn foo() -> isize {
+fn if_guard() -> isize {
let mut n = 42;
let mut x = Enum::A(&mut n);
match x {
}
}
-fn main() {
- foo();
+fn if_let_guard() -> isize {
+ let mut n = 42;
+ let mut x = Enum::A(&mut n);
+ match x {
+ Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
+ //~^ ERROR cannot assign `x` in match guard
+ Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
+ //~^ ERROR cannot mutably borrow `x` in match guard
+ Enum::A(p) => *p,
+ Enum::B(_) => 2,
+ }
}
+
+fn main() {}
error[E0510]: cannot assign `x` in match guard
- --> $DIR/borrowck-mutate-in-guard.rs:10:25
+ --> $DIR/borrowck-mutate-in-guard.rs:12:25
|
LL | match x {
| - value is immutable in match guard
| ^^^^^^^^^^^^^^^^^^ cannot assign
error[E0510]: cannot mutably borrow `x` in match guard
- --> $DIR/borrowck-mutate-in-guard.rs:12:33
+ --> $DIR/borrowck-mutate-in-guard.rs:14:33
|
LL | match x {
| - value is immutable in match guard
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
| ^^^^^^ cannot mutably borrow
-error: aborting due to 2 previous errors
+error[E0510]: cannot assign `x` in match guard
+ --> $DIR/borrowck-mutate-in-guard.rs:25:40
+ |
+LL | match x {
+ | - value is immutable in match guard
+LL | Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
+ | ^^^^^^^^^^^^^^^^^^ cannot assign
+
+error[E0510]: cannot mutably borrow `x` in match guard
+ --> $DIR/borrowck-mutate-in-guard.rs:27:48
+ |
+LL | match x {
+ | - value is immutable in match guard
+...
+LL | Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
+ | ^^^^^^ cannot mutably borrow
+
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0510`.
error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable
--> $DIR/borrowck-overloaded-call.rs:67:5
|
-LL | let s = SFnMut {
- | - help: consider changing this to be mutable: `mut s`
-...
LL | s(3);
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut s = SFnMut {
+ | +++
error[E0382]: use of moved value: `s`
--> $DIR/borrowck-overloaded-call.rs:75:5
error[E0596]: cannot borrow `foo.bar1` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-reborrow-from-mut.rs:88:17
|
-LL | fn borrow_mut_from_imm(foo: &Foo) {
- | ---- help: consider changing this to be a mutable reference: `&mut Foo`
LL | let _bar1 = &mut foo.bar1;
| ^^^^^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn borrow_mut_from_imm(foo: &mut Foo) {
+ | ~~~~~~~~
error: aborting due to 11 previous errors
error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
--> $DIR/borrowck-ref-mut-of-imm.rs:4:12
|
-LL | fn destructure(x: Option<isize>) -> isize {
- | - help: consider changing this to be mutable: `mut x`
-...
LL | Some(ref mut v) => *v
| ^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn destructure(mut x: Option<isize>) -> isize {
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
--> $DIR/borrowck-unboxed-closures.rs:7:5
|
-LL | fn b<F:FnMut(isize, isize) -> isize>(f: F) {
- | - help: consider changing this to be mutable: `mut f`
LL | f(1, 2);
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn b<F:FnMut(isize, isize) -> isize>(mut f: F) {
+ | +++
error[E0382]: use of moved value: `f`
--> $DIR/borrowck-unboxed-closures.rs:12:5
error[E0594]: cannot assign to `*y`, as `y` is not declared as mutable
--> $DIR/immut-function-arguments.rs:2:5
|
-LL | fn f(y: Box<isize>) {
- | - help: consider changing this to be mutable: `mut y`
LL | *y = 5;
| ^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | fn f(mut y: Box<isize>) {
+ | +++
error[E0594]: cannot assign to `*q`, as `q` is not declared as mutable
--> $DIR/immut-function-arguments.rs:6:35
|
LL | let _frob = |q: Box<isize>| { *q = 2; };
- | - ^^^^^^ cannot assign
- | |
- | help: consider changing this to be mutable: `mut q`
+ | ^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let _frob = |mut q: Box<isize>| { *q = 2; };
+ | +++
error: aborting due to 2 previous errors
+#![feature(if_let_guard)]
+
fn main() {
let a = Some("...".to_owned());
let b = match a {
Some(_) if { drop(a); false } => None,
x => x, //~ ERROR use of moved value: `a`
};
- println!("{:?}", b);
+
+ let a = Some("...".to_owned());
+ let b = match a {
+ Some(_) if let Some(()) = { drop(a); None } => None,
+ x => x, //~ ERROR use of moved value: `a`
+ };
}
error[E0382]: use of moved value: `a`
- --> $DIR/issue-31287-drop-in-guard.rs:5:9
+ --> $DIR/issue-31287-drop-in-guard.rs:7:9
|
LL | let a = Some("...".to_owned());
| - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
LL | Some(_) if { drop(a.clone()); false } => None,
| ++++++++
-error: aborting due to previous error
+error[E0382]: use of moved value: `a`
+ --> $DIR/issue-31287-drop-in-guard.rs:13:9
+ |
+LL | let a = Some("...".to_owned());
+ | - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
+LL | let b = match a {
+LL | Some(_) if let Some(()) = { drop(a); None } => None,
+ | - value moved here
+LL | x => x,
+ | ^ value used here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | Some(_) if let Some(()) = { drop(a.clone()); None } => None,
+ | ++++++++
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0382`.
error[E0594]: cannot assign to `t.0`, as `t` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:13:9
|
-LL | let t: Tuple = (S(0), 0);
- | - help: consider changing this to be mutable: `mut t`
-LL | drop(t);
LL | t.0 = S(1);
| ^^^^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut t: Tuple = (S(0), 0);
+ | +++
error[E0382]: assign to part of moved value: `t`
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:13:9
error[E0594]: cannot assign to `t.1`, as `t` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:16:9
|
-LL | let t: Tuple = (S(0), 0);
- | - help: consider changing this to be mutable: `mut t`
-...
LL | t.1 = 2;
| ^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut t: Tuple = (S(0), 0);
+ | +++
error[E0594]: cannot assign to `u.0`, as `u` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:24:9
|
-LL | let u: Tpair = Tpair(S(0), 0);
- | - help: consider changing this to be mutable: `mut u`
-LL | drop(u);
LL | u.0 = S(1);
| ^^^^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut u: Tpair = Tpair(S(0), 0);
+ | +++
error[E0382]: assign to part of moved value: `u`
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:24:9
error[E0594]: cannot assign to `u.1`, as `u` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9
|
-LL | let u: Tpair = Tpair(S(0), 0);
- | - help: consider changing this to be mutable: `mut u`
-...
LL | u.1 = 2;
| ^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut u: Tpair = Tpair(S(0), 0);
+ | +++
error[E0594]: cannot assign to `v.x`, as `v` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:35:9
|
-LL | let v: Spair = Spair { x: S(0), y: 0 };
- | - help: consider changing this to be mutable: `mut v`
-LL | drop(v);
LL | v.x = S(1);
| ^^^^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut v: Spair = Spair { x: S(0), y: 0 };
+ | +++
error[E0382]: assign to part of moved value: `v`
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:35:9
error[E0594]: cannot assign to `v.y`, as `v` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9
|
-LL | let v: Spair = Spair { x: S(0), y: 0 };
- | - help: consider changing this to be mutable: `mut v`
-...
LL | v.y = 2;
| ^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut v: Spair = Spair { x: S(0), y: 0 };
+ | +++
error: aborting due to 9 previous errors
error[E0594]: cannot assign to `*r`, which is behind a `&` reference
--> $DIR/issue-85765.rs:12:5
|
-LL | let r = &mutvar;
- | ------- help: consider changing this to be a mutable reference: `&mut mutvar`
-LL |
LL | *r = 0;
| ^^^^^^ `r` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let r = &mut mutvar;
+ | ~~~~~~~~~~~
error[E0594]: cannot assign to `*x`, which is behind a `&` reference
--> $DIR/issue-85765.rs:19:5
--- /dev/null
+trait Modify {
+ fn modify(&mut self) ;
+}
+
+impl<T> Modify for T {
+ fn modify(&mut self) {}
+}
+
+trait Foo {
+ fn mute(&mut self) {
+ self.modify(); //~ ERROR cannot borrow `self` as mutable
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
+ --> $DIR/issue-93078.rs:11:9
+ |
+LL | self.modify();
+ | ^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+ = note: as `Self` may be unsized, this call attempts to take `&mut &mut self`
+ = note: however, `&mut self` expands to `self: &mut Self`, therefore `self` cannot be borrowed mutably
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
error[E0594]: cannot assign to `self.foo`, which is behind a `&` reference
--> $DIR/issue-93093.rs:8:9
|
-LL | async fn bar(&self) {
- | ----- help: consider changing this to be a mutable reference: `&mut self`
-LL |
LL | self.foo += 1;
| ^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | async fn bar(&mut self) {
+ | ~~~~~~~~~
error: aborting due to previous error
--- /dev/null
+fn main() {
+ let v = Vec::new(); //~ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+}
--- /dev/null
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+ --> $DIR/many-mutable-borrows.rs:2:9
+ |
+LL | let v = Vec::new();
+ | ^ not mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+ |
+ = note: ...and 5 other attempted mutable borrows
+help: consider changing this to be mutable
+ |
+LL | let mut v = Vec::new();
+ | +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
#![crate_type = "rlib"]
pub fn f(b: &mut i32) {
- //~^ NOTE the binding is already a mutable borrow
+ //~^ ERROR cannot borrow
+ //~| NOTE not mutable
//~| NOTE the binding is already a mutable borrow
h(&mut b);
- //~^ ERROR cannot borrow
- //~| NOTE cannot borrow as mutable
+ //~^ NOTE cannot borrow as mutable
//~| HELP try removing `&mut` here
g(&mut &mut b);
- //~^ ERROR cannot borrow
- //~| NOTE cannot borrow as mutable
+ //~^ NOTE cannot borrow as mutable
//~| HELP try removing `&mut` here
}
error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
- --> $DIR/mut-borrow-of-mut-ref.rs:7:7
+ --> $DIR/mut-borrow-of-mut-ref.rs:4:10
|
+LL | pub fn f(b: &mut i32) {
+ | ^ not mutable
+...
LL | h(&mut b);
- | ^^^^^^ cannot borrow as mutable
+ | ------ cannot borrow as mutable
+...
+LL | g(&mut &mut b);
+ | ------ cannot borrow as mutable
|
note: the binding is already a mutable borrow
--> $DIR/mut-borrow-of-mut-ref.rs:4:13
LL - h(&mut b);
LL + h(b);
|
-
-error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
- --> $DIR/mut-borrow-of-mut-ref.rs:11:12
- |
-LL | g(&mut &mut b);
- | ^^^^^^ cannot borrow as mutable
- |
-note: the binding is already a mutable borrow
- --> $DIR/mut-borrow-of-mut-ref.rs:4:13
- |
-LL | pub fn f(b: &mut i32) {
- | ^^^^^^^^
help: try removing `&mut` here
|
LL - g(&mut &mut b);
|
error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
- --> $DIR/mut-borrow-of-mut-ref.rs:18:12
+ --> $DIR/mut-borrow-of-mut-ref.rs:17:12
|
LL | h(&mut &mut b);
| ^^^^^^ cannot borrow as mutable
|
note: the binding is already a mutable borrow
- --> $DIR/mut-borrow-of-mut-ref.rs:17:13
+ --> $DIR/mut-borrow-of-mut-ref.rs:16:13
|
LL | pub fn g(b: &mut i32) {
| ^^^^^^^^
|
error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
- --> $DIR/mut-borrow-of-mut-ref.rs:35:5
+ --> $DIR/mut-borrow-of-mut-ref.rs:34:5
|
LL | f.bar();
| ^^^^^^^ cannot borrow as mutable
LL | pub fn baz(mut f: &mut String) {
| +++
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0596`.
});
}
-fn imm_local(x: (i32,)) {
- &mut x; //~ ERROR
- &mut x.0; //~ ERROR
+fn imm_local(x: (i32,)) { //~ ERROR
+ &mut x;
+ &mut x.0;
}
fn imm_capture(x: (i32,)) {
error[E0594]: cannot assign to `*x`, which is behind a `&` reference
--> $DIR/mutability-errors.rs:9:5
|
-LL | fn named_ref(x: &(i32,)) {
- | ------- help: consider changing this to be a mutable reference: `&mut (i32,)`
LL | *x = (1,);
| ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn named_ref(x: &mut (i32,)) {
+ | ~~~~~~~~~~~
error[E0594]: cannot assign to `x.0`, which is behind a `&` reference
--> $DIR/mutability-errors.rs:10:5
|
-LL | fn named_ref(x: &(i32,)) {
- | ------- help: consider changing this to be a mutable reference: `&mut (i32,)`
-LL | *x = (1,);
LL | x.0 = 1;
| ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn named_ref(x: &mut (i32,)) {
+ | ~~~~~~~~~~~
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/mutability-errors.rs:11:5
|
-LL | fn named_ref(x: &(i32,)) {
- | ------- help: consider changing this to be a mutable reference: `&mut (i32,)`
-...
LL | &mut *x;
| ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn named_ref(x: &mut (i32,)) {
+ | ~~~~~~~~~~~
error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `&` reference
--> $DIR/mutability-errors.rs:12:5
|
-LL | fn named_ref(x: &(i32,)) {
- | ------- help: consider changing this to be a mutable reference: `&mut (i32,)`
-...
LL | &mut x.0;
| ^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn named_ref(x: &mut (i32,)) {
+ | ~~~~~~~~~~~
error[E0594]: cannot assign to data in a `&` reference
--> $DIR/mutability-errors.rs:16:5
error[E0594]: cannot assign to `*x`, which is behind a `*const` pointer
--> $DIR/mutability-errors.rs:23:5
|
-LL | unsafe fn named_ptr(x: *const (i32,)) {
- | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)`
LL | *x = (1,);
| ^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable pointer
+ |
+LL | unsafe fn named_ptr(x: *mut (i32,)) {
+ | ~~~~~~~~~~~
error[E0594]: cannot assign to `x.0`, which is behind a `*const` pointer
--> $DIR/mutability-errors.rs:24:5
|
-LL | unsafe fn named_ptr(x: *const (i32,)) {
- | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)`
-LL | *x = (1,);
LL | (*x).0 = 1;
| ^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable pointer
+ |
+LL | unsafe fn named_ptr(x: *mut (i32,)) {
+ | ~~~~~~~~~~~
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer
--> $DIR/mutability-errors.rs:25:5
|
-LL | unsafe fn named_ptr(x: *const (i32,)) {
- | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)`
-...
LL | &mut *x;
| ^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable pointer
+ |
+LL | unsafe fn named_ptr(x: *mut (i32,)) {
+ | ~~~~~~~~~~~
error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `*const` pointer
--> $DIR/mutability-errors.rs:26:5
|
-LL | unsafe fn named_ptr(x: *const (i32,)) {
- | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)`
-...
LL | &mut (*x).0;
| ^^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable pointer
+ |
+LL | unsafe fn named_ptr(x: *mut (i32,)) {
+ | ~~~~~~~~~~~
error[E0594]: cannot assign to data in a `*const` pointer
--> $DIR/mutability-errors.rs:30:5
| ^^^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
- --> $DIR/mutability-errors.rs:54:5
+ --> $DIR/mutability-errors.rs:53:14
|
LL | fn imm_local(x: (i32,)) {
- | - help: consider changing this to be mutable: `mut x`
-LL | &mut x;
- | ^^^^^^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
- --> $DIR/mutability-errors.rs:55:5
- |
-LL | fn imm_local(x: (i32,)) {
- | - help: consider changing this to be mutable: `mut x`
+ | ^ not mutable
LL | &mut x;
+ | ------ cannot borrow as mutable
LL | &mut x.0;
- | ^^^^^^^^ cannot borrow as mutable
+ | -------- cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn imm_local(mut x: (i32,)) {
+ | +++
error[E0594]: cannot assign to `x`, as it is not declared as mutable
--> $DIR/mutability-errors.rs:60:9
LL | &mut X.0;
| ^^^^^^^^ cannot borrow as mutable
-error: aborting due to 38 previous errors
+error: aborting due to 37 previous errors
Some errors have detailed explanations: E0594, E0596.
For more information about an error, try `rustc --explain E0594`.
error[E0594]: cannot assign to `x.b`, as `x` is not declared as mutable
--> $DIR/reassignment_immutable_fields_overlapping.rs:13:5
|
-LL | let x: Foo;
- | - help: consider changing this to be mutable: `mut x`
-LL | x.a = 1;
LL | x.b = 22;
| ^^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x: Foo;
+ | +++
error: aborting due to 2 previous errors
error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
--> $DIR/reassignment_immutable_fields_twice.rs:7:5
|
-LL | let x: (u32, u32);
- | - help: consider changing this to be mutable: `mut x`
-LL | x = (22, 44);
LL | x.0 = 1;
| ^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x: (u32, u32);
+ | +++
error[E0381]: partially assigned binding `x` isn't fully initialized
--> $DIR/reassignment_immutable_fields_twice.rs:12:5
LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
- = note: expected fn pointer `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)`
- found fn pointer `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)`
+ = note: expected signature `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)`
+ found signature `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)`
note: the lifetime `'c` as defined here...
--> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
|
LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
- = note: expected fn pointer `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)`
- found fn pointer `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)`
+ = note: expected signature `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)`
+ found signature `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)`
note: the lifetime `'c` as defined here...
--> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
|
--- /dev/null
+// run-rustfix
+// Test that a by-ref `FnMut` closure gets an error when it tries to
+// consume a value.
+
+fn call<F>(f: F) where F : Fn() {
+ f();
+}
+
+fn main() {
+ let y = vec![format!("World")];
+ call(|| {
+ y.clone().into_iter();
+ //~^ ERROR cannot move out of `y`, a captured variable in an `Fn` closure
+ });
+}
+// run-rustfix
// Test that a by-ref `FnMut` closure gets an error when it tries to
// consume a value.
error[E0507]: cannot move out of `y`, a captured variable in an `Fn` closure
- --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:11:9
+ --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:12:9
|
LL | let y = vec![format!("World")];
| - captured outer variable
|
note: `into_iter` takes ownership of the receiver `self`, which moves `y`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+help: you can `clone` the value and consume it, but this might not be your desired behavior
+ |
+LL | y.clone().into_iter();
+ | ++++++++
error: aborting due to previous error
fn main() {
unsafe {
- foo(); //~ ERROR this function takes at least 2 arguments but 0 arguments were supplied
- foo(1); //~ ERROR this function takes at least 2 arguments but 1 argument was supplied
+ foo(); //~ ERROR function takes at least 2 arguments but 0 arguments were supplied
+ foo(1); //~ ERROR function takes at least 2 arguments but 1 argument was supplied
let x: unsafe extern "C" fn(f: isize, x: u8) = foo; //~ ERROR mismatched types
let y: extern "C" fn(f: isize, x: u8, ...) = bar; //~ ERROR mismatched types
// check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
fn main() {
1 + 2;
// run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
fn main() {
assert_eq!(1, 1);
// check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Foo {}
// check-fail
// known-bug: unknown
-// compile-flags: -Z chalk --edition=2021
+// compile-flags: -Z trait-solver=chalk --edition=2021
fn main() -> () {}
// run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
// Test that `Clone` is correctly implemented for builtin types.
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Foo { }
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
fn main() -> () {
let t = || {};
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Foo { }
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Foo: Sized { }
// Split out of impl_wf.rs to work around rust aborting compilation early
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Foo: Sized { }
// run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Foo { }
// run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Foo { }
// check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
#![allow(dead_code)]
// check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
#![allow(dead_code)]
// check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
#![allow(dead_code)]
// check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Foo { }
// check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
struct Foo<'a, T> where Box<T>: Clone {
_x: std::marker::PhantomData<&'a T>,
// check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Bar { }
// check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Foo<F: ?Sized> where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8
{
// check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
use std::borrow::Borrow;
// check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
fn main() {
println!("hello");
// run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Foo { }
// FIXME(chalk): should fail, see comments
// check-fail
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
#![feature(trivial_bounds)]
fn main() {
// For some reason, the error is duplicated...
- 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
+ //~^ ERROR the type `S` is not well-formed
}
-error: the type `S` is not well-formed (chalk)
+error: the type `S` is not well-formed
--> $DIR/recursive_where_clause_on_type.rs:28:11
|
LL | foo::<S>()
| ^
-error: the type `S` is not well-formed (chalk)
+error: the type `S` is not well-formed
--> $DIR/recursive_where_clause_on_type.rs:28:5
|
LL | foo::<S>()
// run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Foo { }
trait Bar: Foo { }
// check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
use std::fmt::Display;
// run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Foo { }
trait Bar<U> where U: Foo { }
// run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Eq { }
trait Hash: Eq { }
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Foo { }
impl Foo for i32 { }
// check-fail
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
trait Foo { }
| |
| help: did you mean: `"linux"`
|
- = note: expected values for `target_os` are: aix, android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vxworks, wasi, watchos, windows, xous
+ = note: expected values for `target_os` are: aix, android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vita, vxworks, wasi, watchos, windows, xous
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition value
fn main() {
let mut c = {
let mut p = Point {x: "1".to_string(), y: "2".to_string() };
- || {
+ || { //~ ERROR closure may outlive the current block, but it borrows `p`
let x = &mut p.x;
println!("{:?}", p);
- //~^ ERROR `p` does not live long enough
}
};
c();
-error[E0597]: `p` does not live long enough
- --> $DIR/borrowck-3.rs:13:29
+error[E0373]: closure may outlive the current block, but it borrows `p`, which is owned by the current block
+ --> $DIR/borrowck-3.rs:11:9
|
-LL | let mut c = {
- | ----- borrow later stored here
-LL | let mut p = Point {x: "1".to_string(), y: "2".to_string() };
LL | || {
- | -- value captured here
+ | ^^ may outlive borrowed value `p`
LL | let x = &mut p.x;
LL | println!("{:?}", p);
- | ^ borrowed value does not live long enough
-...
-LL | };
- | - `p` dropped here while still borrowed
+ | - `p` is borrowed here
+ |
+note: block requires argument type to outlive `'1`
+ --> $DIR/borrowck-3.rs:9:9
+ |
+LL | let mut c = {
+ | ^^^^^
+help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword
+ |
+LL | move || {
+ | ++++
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0597`.
+For more information about this error, try `rustc --explain E0373`.
error[E0596]: cannot borrow `**ref_mref_x` as mutable, as it is behind a `&` reference
--> $DIR/mut_ref.rs:12:13
|
-LL | let ref_mref_x = &mref_x;
- | ------- help: consider changing this to be a mutable reference: `&mut mref_x`
-LL |
LL | let c = || {
| ^^ `ref_mref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
LL |
LL | **ref_mref_x = y;
| ------------ mutable borrow occurs due to use of `**ref_mref_x` in closure
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let ref_mref_x = &mut mref_x;
+ | ~~~~~~~~~~~
error[E0596]: cannot borrow `**mref_ref_x` as mutable, as it is behind a `&` reference
--> $DIR/mut_ref.rs:26:13
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
--> $DIR/issue-80313-mutable-borrow-in-closure.rs:6:5
|
-LL | let callback = || {
- | -------- help: consider changing this to be mutable: `mut callback`
LL | &mut my_var;
| ------ calling `callback` requires mutable binding due to mutable borrow of `my_var`
LL | };
LL | callback();
| ^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut callback = || {
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
--> $DIR/issue-80313-mutable-borrow-in-move-closure.rs:6:5
|
-LL | let callback = move || {
- | -------- help: consider changing this to be mutable: `mut callback`
LL | &mut my_var;
| ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
LL | };
LL | callback();
| ^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut callback = move || {
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
--> $DIR/issue-80313-mutation-in-closure.rs:6:5
|
-LL | let callback = || {
- | -------- help: consider changing this to be mutable: `mut callback`
LL | my_var = true;
| ------ calling `callback` requires mutable binding due to mutable borrow of `my_var`
LL | };
LL | callback();
| ^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut callback = || {
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
--> $DIR/issue-80313-mutation-in-move-closure.rs:6:5
|
-LL | let callback = move || {
- | -------- help: consider changing this to be mutable: `mut callback`
LL | my_var = true;
| ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
LL | };
LL | callback();
| ^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut callback = move || {
+ | +++
error: aborting due to previous error
--> $DIR/issue-81700-mut-borrow.rs:3:5
|
LL | let bar = || { foo(x); };
- | --- - calling `bar` requires mutable binding due to mutable borrow of `x`
- | |
- | help: consider changing this to be mutable: `mut bar`
+ | - calling `bar` requires mutable binding due to mutable borrow of `x`
LL | bar();
| ^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut bar = || { foo(x); };
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `c` as mutable, as it is not declared as mutable
--> $DIR/issue-82438-mut-without-upvar.rs:27:27
|
-LL | let c = |a, b, c, d| {};
- | - help: consider changing this to be mutable: `mut c`
-LL |
LL | A.f(participant_name, &mut c);
| ^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut c = |a, b, c, d| {};
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
--> $DIR/issue-84044-drop-non-mut.rs:5:10
|
-LL | let f = || {};
- | - help: consider changing this to be mutable: `mut f`
LL | drop(&mut f);
| ^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut f = || {};
+ | +++
error: aborting due to previous error
--- /dev/null
+// check-pass
+
+trait Foo<'a> {
+ type Input;
+}
+
+impl<F: Fn(u32)> Foo<'_> for F {
+ type Input = u32;
+}
+
+trait SuperFn: for<'a> Foo<'a> + for<'a> Fn(<Self as Foo<'a>>::Input) {}
+impl<T> SuperFn for T where T: for<'a> Fn(<Self as Foo<'a>>::Input) + for<'a> Foo<'a> {}
+
+fn needs_super(_: impl SuperFn) {}
+
+fn main() {
+ needs_super(|_: u32| {});
+}
--- /dev/null
+// check-pass
+
+
+trait Foo<'a> {
+ type Input;
+}
+
+impl<F: Fn(u32)> Foo<'_> for F {
+ type Input = u32;
+}
+
+fn needs_super<F: for<'a> Fn(<F as Foo<'a>>::Input) + for<'a> Foo<'a>>(_: F) {}
+
+fn main() {
+ needs_super(|_: u32| {});
+}
--- /dev/null
+// edition:2021
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+#![feature(closure_lifetime_binder)]
+
+use std::future::Future;
+
+trait AsyncFn<I, R>: FnMut(I) -> Self::Fut {
+ type Fut: Future<Output = R>;
+}
+
+impl<F, I, R, Fut> AsyncFn<I, R> for F
+where
+ Fut: Future<Output = R>,
+ F: FnMut(I) -> Fut,
+{
+ type Fut = Fut;
+}
+
+async fn call<C, R, F>(mut ctx: C, mut f: F) -> Result<R, ()>
+where
+ F: for<'a> AsyncFn<&'a mut C, Result<R, ()>>,
+{
+ loop {
+ match f(&mut ctx).await {
+ Ok(val) => return Ok(val),
+ Err(_) => continue,
+ }
+ }
+}
+
+trait Cap<'a> {}
+impl<T> Cap<'_> for T {}
+
+fn works(ctx: &mut usize) {
+ let mut inner = 0;
+
+ type Ret<'a, 'b: 'a> = impl Future<Output = Result<usize, ()>> + 'a + Cap<'b>;
+
+ let callback = for<'a, 'b> |c: &'a mut &'b mut usize| -> Ret<'a, 'b> {
+ inner += 1;
+ async move {
+ let _c = c;
+ Ok(1usize)
+ }
+ };
+ call(ctx, callback);
+}
+
+fn doesnt_work_but_should(ctx: &mut usize) {
+ let mut inner = 0;
+
+ type Ret<'a, 'b: 'a> = impl Future<Output = Result<usize, ()>> + 'a + Cap<'b>;
+
+ call(ctx, for<'a, 'b> |c: &'a mut &'b mut usize| -> Ret<'a, 'b> {
+ inner += 1;
+ async move {
+ let _c = c;
+ Ok(1usize)
+ }
+ });
+}
+
+fn main() {}
--- /dev/null
+// run-pass
+// compile-flags: -Copt-level=0 -Cdebuginfo=2
+
+// Make sure LLVM does not miscompile this.
+
+fn indirect_get_slice() -> &'static [usize] {
+ &[]
+}
+
+#[inline(always)]
+fn get_slice() -> &'static [usize] {
+ let ret = indirect_get_slice();
+ ret
+}
+
+fn main() {
+ let output = get_slice().len();
+ assert_eq!(output, 0);
+}
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/huge_multispan_highlight.rs:90:13
|
-LL | let x = "foo";
- | - help: consider changing this to be mutable: `mut x`
-...
LL | let y = &mut x;
| ^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x = "foo";
+ | +++
error: aborting due to previous error
note: `into_iter` takes ownership of the receiver `self`, which moves `some_vec`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider cloning the value if the performance cost is acceptable
+help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | some_vec.clone().into_iter();
- | ++++++++
+ | ++++++++
error: aborting due to previous error
--> $DIR/coherence-default-trait-impl.rs:8:1
|
LL | unsafe impl MySafeTrait for Foo {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: remove `unsafe` from this trait implementation
|
--> $DIR/coherence-default-trait-impl.rs:13:1
|
LL | impl MyUnsafeTrait for Foo {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the trait `MyUnsafeTrait` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
help: add `unsafe` to this trait implementation
+++ /dev/null
-// run-pass
-
-// ignore-windows - this is a unix-specific test
-// ignore-emscripten no processes
-// ignore-sgx no processes
-use std::os::unix::process::CommandExt;
-use std::process::Command;
-
-fn main() {
- let mut command = Command::new("some-boring-name");
-
- assert_eq!(format!("{:?}", command), r#""some-boring-name""#);
-
- command.args(&["1", "2", "3"]);
-
- assert_eq!(format!("{:?}", command), r#""some-boring-name" "1" "2" "3""#);
-
- command.arg0("exciting-name");
-
- assert_eq!(format!("{:?}", command), r#"["some-boring-name"] "exciting-name" "1" "2" "3""#);
-}
--- /dev/null
+// run-pass
+// ignore-emscripten no processes
+// ignore-sgx no processes
+
+// Make sure that if a process doesn't have its stdio/stderr descriptors set up
+// that we don't die in a large ball of fire
+
+use std::env;
+use std::process::{Command, Stdio};
+
+pub fn main () {
+ let args: Vec<String> = env::args().collect();
+ if args.len() > 1 && args[1] == "child" {
+ for _ in 0..1000 {
+ println!("hello?");
+ }
+ for _ in 0..1000 {
+ println!("hello?");
+ }
+ return;
+ }
+
+ let mut p = Command::new(&args[0]);
+ p.arg("child").stdout(Stdio::null()).stderr(Stdio::null());
+ println!("{:?}", p.spawn().unwrap().wait());
+}
| expected struct `Pin`, found struct `MyFuture`
| help: change the self-receiver type to match the trait: `self: Pin<&mut MyFuture>`
|
- = note: expected fn pointer `fn(Pin<&mut MyFuture>, &mut Context<'_>) -> Poll<_>`
- found fn pointer `fn(MyFuture, &mut Context<'_>) -> Poll<_>`
+ = note: expected signature `fn(Pin<&mut MyFuture>, &mut Context<'_>) -> Poll<_>`
+ found signature `fn(MyFuture, &mut Context<'_>) -> Poll<_>`
error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/bad-self-type.rs:22:18
|
LL | fn foo(self);
| ^^^^
- = note: expected fn pointer `fn(MyFuture)`
- found fn pointer `fn(Box<MyFuture>)`
+ = note: expected signature `fn(MyFuture)`
+ found signature `fn(Box<MyFuture>)`
error[E0053]: method `bar` has an incompatible type for trait
--> $DIR/bad-self-type.rs:24:18
|
LL | fn bar(self) -> Option<()>;
| ^^^^^^^^^^
- = note: expected fn pointer `fn(MyFuture) -> Option<()>`
- found fn pointer `fn(MyFuture)`
+ = note: expected signature `fn(MyFuture) -> Option<()>`
+ found signature `fn(MyFuture)`
help: change the output type to match the trait
|
LL | fn bar(self) -> Option<()> {}
| types differ in mutability
| help: change the parameter type to match the trait: `for<'a> fn((), (), &'a ())`
|
- = note: expected fn pointer `fn(for<'a> fn((), (), &'a ())) -> A`
- found fn pointer `fn(for<'a> fn((), (), &'a mut ())) -> A`
+ = note: expected signature `fn(for<'a> fn((), (), &'a ())) -> A`
+ found signature `fn(for<'a> fn((), (), &'a mut ())) -> A`
error[E0053]: method `from` has an incompatible type for trait
--> $DIR/issue-90444.rs:11:16
| expected `u32`, found `u64`
| help: change the parameter type to match the trait: `fn((), (), u32)`
|
- = note: expected fn pointer `fn(fn((), (), u32)) -> B`
- found fn pointer `fn(fn((), (), u64)) -> B`
+ = note: expected signature `fn(fn((), (), u32)) -> B`
+ found signature `fn(fn((), (), u64)) -> B`
error: aborting due to 2 previous errors
...
LL | fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
| ^^ impl has extra requirement `'a: 'b`
+ |
+help: copy the `where` clause predicates from the trait
+ |
+LL | fn renew<'b: 'a>(self) -> &'b mut [T] where 'b: 'a {
+ | ~~~~~~~~~~~~
error: aborting due to previous error
...
LL | fn foo() where 'a: 'b { }
| ^^ impl has extra requirement `'a: 'b`
+ |
+help: remove the `where` clause
+ |
+LL - fn foo() where 'a: 'b { }
+LL + fn foo() { }
+ |
error: aborting due to previous error
|
LL | fn b<C:Clone,D>(&self, x: C) -> C;
| ^
- = note: expected fn pointer `fn(&E, F) -> F`
- found fn pointer `fn(&E, G) -> G`
+ = note: expected signature `fn(&E, F) -> F`
+ found signature `fn(&E, G) -> G`
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
--- /dev/null
+#![feature(associated_const_equality)]
+
+pub enum Mode {
+ Cool,
+}
+
+pub trait Parse {
+ const MODE: Mode;
+}
+
+pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
+//~^ ERROR expected associated constant bound
+//~| ERROR expected type
+
+fn no_help() -> Mode::Cool {}
+//~^ ERROR expected type, found variant
+
+fn main() {}
--- /dev/null
+error[E0573]: expected type, found variant `Mode::Cool`
+ --> $DIR/assoc_const_eq_diagnostic.rs:11:35
+ |
+LL | pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
+ | ^^^^^^^^^^
+ | |
+ | not a type
+ | help: try using the variant's enum: `Mode`
+
+error[E0573]: expected type, found variant `Mode::Cool`
+ --> $DIR/assoc_const_eq_diagnostic.rs:15:17
+ |
+LL | fn no_help() -> Mode::Cool {}
+ | ^^^^^^^^^^
+ | |
+ | not a type
+ | help: try using the variant's enum: `Mode`
+
+error: expected associated constant bound, found type
+ --> $DIR/assoc_const_eq_diagnostic.rs:11:28
+ |
+LL | pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
+ | ^^^^^^^^^^^^^^^^^ help: if equating a const, try wrapping with braces: `MODE = { const }`
+ |
+note: associated constant defined here
+ --> $DIR/assoc_const_eq_diagnostic.rs:8:5
+ |
+LL | const MODE: Mode;
+ | ^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0573`.
--- /dev/null
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn foo<const N: usize, const M: usize>() -> [(); N+2]
+where
+ [(); N + 1]:,
+ [(); M + 1]:,
+{
+ bar()
+ //~^ ERROR: unconstrained
+}
+
+fn bar<const N: usize>() -> [(); N]
+where
+ [(); N + 1]:,
+{
+ [(); N]
+}
+
+fn main() {}
--- /dev/null
+error: unconstrained generic constant
+ --> $DIR/ensure_is_evaluatable.rs:9:5
+ |
+LL | bar()
+ | ^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); N + 1]:`
+note: required by a bound in `bar`
+ --> $DIR/ensure_is_evaluatable.rs:15:10
+ |
+LL | fn bar<const N: usize>() -> [(); N]
+ | --- required by a bound in this
+LL | where
+LL | [(); N + 1]:,
+ | ^^^^^ required by this bound in `bar`
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+const fn both(_: usize, b: usize) -> usize {
+ b
+}
+
+fn foo<const N: usize, const M: usize>() -> [(); N + 2]
+where
+ [(); both(N + 1, M + 1)]:,
+{
+ bar()
+ //~^ ERROR: unconstrained generic constant
+}
+
+fn bar<const N: usize>() -> [(); N]
+where
+ [(); N + 1]:,
+{
+ [(); N]
+}
+
+fn main() {}
--- /dev/null
+error: unconstrained generic constant
+ --> $DIR/fn_with_two_const_inputs.rs:12:5
+ |
+LL | bar()
+ | ^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); N + 1]:`
+note: required by a bound in `bar`
+ --> $DIR/fn_with_two_const_inputs.rs:18:10
+ |
+LL | fn bar<const N: usize>() -> [(); N]
+ | --- required by a bound in this
+LL | where
+LL | [(); N + 1]:,
+ | ^^^^^ required by this bound in `bar`
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+const fn both(_: usize, b: usize) -> usize {
+ b
+}
+
+fn foo<const N: usize>()
+where
+ [(); both(N + 1, N + 1)]:,
+{
+ bar::<N>();
+}
+
+fn bar<const N: usize>()
+where
+ [(); N + 1]:,
+{
+}
+
+fn main() {}
fn main() {
test::<2>();
- //~^ ERROR this function takes 2 generic arguments
+ //~^ ERROR function takes 2 generic arguments
}
--- /dev/null
+// edition:2018
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+#[allow(unused)]
+async fn foo<'a>() {
+ let _data = &mut [0u8; { 1 + 4 }];
+ bar().await
+}
+
+async fn bar() {}
+
+fn main() {}
fn main() {
foo::<0>();
- //~^ ERROR this function takes 2
+ //~^ ERROR function takes 2
foo::<0, 0, 0>();
- //~^ ERROR this function takes 2
+ //~^ ERROR function takes 2
}
--- /dev/null
+// run-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+#![allow(dead_code)]
+
+trait Table<const D: usize>: Sync {
+ const COLUMNS: usize;
+}
+
+struct Table1<const D: usize>;
+impl<const D: usize> Table<D> for Table1<D> {
+ const COLUMNS: usize = 123;
+}
+
+struct Table2<const D: usize>;
+impl<const D: usize> Table<D> for Table2<D> {
+ const COLUMNS: usize = 456;
+}
+
+fn process_table<T: Table<D>, const D: usize>(_table: T)
+where
+ [(); T::COLUMNS]:,
+{
+}
+
+fn process_all_tables<const D: usize>()
+where
+ [(); Table2::<D>::COLUMNS]:,
+ [(); Table1::<D>::COLUMNS]:,
+{
+ process_table(Table1::<D>);
+ process_table(Table2::<D>);
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn foo<const N: usize>()
+where
+ [(); N + 1]:,
+ [(); N + 1]:,
+{
+ bar::<N>();
+}
+
+fn bar<const N: usize>()
+where
+ [(); N + 1]:,
+{
+}
+
+fn main() {}
--- /dev/null
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn foo<const N: usize>()
+where
+ [(); N + 1 + 1]:,
+{
+ bar();
+ //~^ ERROR: type annotations
+}
+
+fn bar<const N: usize>()
+where
+ [(); N + 1]:,
+{
+}
+
+fn main() {}
--- /dev/null
+error[E0284]: type annotations needed
+ --> $DIR/unify_with_nested_expr.rs:8:5
+ |
+LL | bar();
+ | ^^^ cannot infer the value of the const parameter `N` declared on the function `bar`
+ |
+note: required by a bound in `bar`
+ --> $DIR/unify_with_nested_expr.rs:14:10
+ |
+LL | fn bar<const N: usize>()
+ | --- required by a bound in this
+LL | where
+LL | [(); N + 1]:,
+ | ^^^^^ required by this bound in `bar`
+help: consider specifying the generic argument
+ |
+LL | bar::<N>();
+ | +++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0284`.
+++ /dev/null
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
- = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
- |
-note: inside `std::slice::from_raw_parts::<'_, u32>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S0`
- --> $DIR/forbidden_slices.rs:18:34
- |
-LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
- = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
- |
-note: inside `std::slice::from_raw_parts::<'_, ()>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S1`
- --> $DIR/forbidden_slices.rs:19:33
- |
-LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
- = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
- |
-note: inside `std::slice::from_raw_parts::<'_, u32>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S2`
- --> $DIR/forbidden_slices.rs:22:34
- |
-LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:25:1
- |
-LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
- | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:27:1
- |
-LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
- | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:29:1
- |
-LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
- | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:32:1
- |
-LL | pub static S7: &[u16] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID+0x2╼ 04 00 00 00 │ ╾──╼....
- }
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
- = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
- |
-note: inside `std::slice::from_raw_parts::<'_, u64>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S8`
- --> $DIR/forbidden_slices.rs:43:5
- |
-LL | from_raw_parts(ptr, 1)
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
- = note: out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
- |
-note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, u32>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R0`
- --> $DIR/forbidden_slices.rs:46:34
- |
-LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
- = note: the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-note: inside `ptr::const_ptr::<impl *const ()>::sub_ptr`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, ()>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R1`
- --> $DIR/forbidden_slices.rs:47:33
- |
-LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
- = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
- |
-note: inside `ptr::const_ptr::<impl *const u32>::offset`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::add`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `R2`
- --> $DIR/forbidden_slices.rs:50:25
- |
-LL | from_ptr_range(ptr..ptr.add(2))
- | ^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:52:1
- |
-LL | pub static R4: &[u8] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:57:1
- |
-LL | pub static R5: &[u8] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:62:1
- |
-LL | pub static R6: &[bool] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
- }
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
- = note: accessing memory with alignment 1, but alignment 2 is required
- |
-note: inside `std::slice::from_raw_parts::<'_, u16>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `from_ptr_range::<'_, u16>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R7`
- --> $DIR/forbidden_slices.rs:69:5
- |
-LL | from_ptr_range(ptr..ptr.add(4))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
- = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
- |
-note: inside `ptr::const_ptr::<impl *const u64>::offset`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u64>::add`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `R8`
- --> $DIR/forbidden_slices.rs:73:25
- |
-LL | from_ptr_range(ptr..ptr.add(1))
- | ^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
- = note: `ptr_offset_from_unsigned` called on pointers into different allocations
- |
-note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, u32>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R9`
- --> $DIR/forbidden_slices.rs:78:34
- |
-LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
- = note: `ptr_offset_from_unsigned` called on pointers into different allocations
- |
-note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, u32>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R10`
- --> $DIR/forbidden_slices.rs:79:35
- |
-LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 18 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
+++ /dev/null
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
- = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
- |
-note: inside `std::slice::from_raw_parts::<'_, u32>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S0`
- --> $DIR/forbidden_slices.rs:18:34
- |
-LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
- = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
- |
-note: inside `std::slice::from_raw_parts::<'_, ()>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S1`
- --> $DIR/forbidden_slices.rs:19:33
- |
-LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
- = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
- |
-note: inside `std::slice::from_raw_parts::<'_, u32>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S2`
- --> $DIR/forbidden_slices.rs:22:34
- |
-LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:25:1
- |
-LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
- | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:27:1
- |
-LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
- | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:29:1
- |
-LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
- | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:32:1
- |
-LL | pub static S7: &[u16] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID+0x2╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
- = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
- |
-note: inside `std::slice::from_raw_parts::<'_, u64>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S8`
- --> $DIR/forbidden_slices.rs:43:5
- |
-LL | from_raw_parts(ptr, 1)
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
- = note: out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
- |
-note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, u32>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R0`
- --> $DIR/forbidden_slices.rs:46:34
- |
-LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
- = note: the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-note: inside `ptr::const_ptr::<impl *const ()>::sub_ptr`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, ()>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R1`
- --> $DIR/forbidden_slices.rs:47:33
- |
-LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
- = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
- |
-note: inside `ptr::const_ptr::<impl *const u32>::offset`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::add`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `R2`
- --> $DIR/forbidden_slices.rs:50:25
- |
-LL | from_ptr_range(ptr..ptr.add(2))
- | ^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:52:1
- |
-LL | pub static R4: &[u8] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:57:1
- |
-LL | pub static R5: &[u8] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:62:1
- |
-LL | pub static R6: &[bool] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
- = note: accessing memory with alignment 1, but alignment 2 is required
- |
-note: inside `std::slice::from_raw_parts::<'_, u16>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `from_ptr_range::<'_, u16>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R7`
- --> $DIR/forbidden_slices.rs:69:5
- |
-LL | from_ptr_range(ptr..ptr.add(4))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
- = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
- |
-note: inside `ptr::const_ptr::<impl *const u64>::offset`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u64>::add`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `R8`
- --> $DIR/forbidden_slices.rs:73:25
- |
-LL | from_ptr_range(ptr..ptr.add(1))
- | ^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
- = note: `ptr_offset_from_unsigned` called on pointers into different allocations
- |
-note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, u32>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R9`
- --> $DIR/forbidden_slices.rs:78:34
- |
-LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
- = note: `ptr_offset_from_unsigned` called on pointers into different allocations
- |
-note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, u32>`
- --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R10`
- --> $DIR/forbidden_slices.rs:79:35
- |
-LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 18 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
-// stderr-per-bitwidth
-// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼"
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
// normalize-stderr-test "alloc\d+" -> "allocN"
// error-pattern: could not evaluate static initializer
#![feature(
pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
-const D0: u32 = 0x11;
+const D0: u32 = 0x11111111; // Constant chosen for endianness-independent behavior.
const D1: MaybeUninit<&u32> = MaybeUninit::uninit();
const D2: Struct = Struct { a: 1, b: 2, c: 3, d: 4 };
const D3: &u32 = &42;
--- /dev/null
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
+ |
+note: inside `std::slice::from_raw_parts::<'_, u32>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `S0`
+ --> $DIR/forbidden_slices.rs:19:34
+ |
+LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
+ |
+note: inside `std::slice::from_raw_parts::<'_, ()>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `S1`
+ --> $DIR/forbidden_slices.rs:20:33
+ |
+LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+ |
+note: inside `std::slice::from_raw_parts::<'_, u32>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `S2`
+ --> $DIR/forbidden_slices.rs:23:34
+ |
+LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:26:1
+ |
+LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
+ | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:28:1
+ |
+LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
+ | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:30:1
+ |
+LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
+ | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:33:1
+ |
+LL | pub static S7: &[u16] = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+ |
+note: inside `std::slice::from_raw_parts::<'_, u64>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `S8`
+ --> $DIR/forbidden_slices.rs:44:5
+ |
+LL | from_raw_parts(ptr, 1)
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ = note: out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
+ |
+note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `from_ptr_range::<'_, u32>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R0`
+ --> $DIR/forbidden_slices.rs:47:34
+ |
+LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ = note: the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+note: inside `ptr::const_ptr::<impl *const ()>::sub_ptr`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `from_ptr_range::<'_, ()>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R1`
+ --> $DIR/forbidden_slices.rs:48:33
+ |
+LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+ |
+note: inside `ptr::const_ptr::<impl *const u32>::offset`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::add`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `R2`
+ --> $DIR/forbidden_slices.rs:51:25
+ |
+LL | from_ptr_range(ptr..ptr.add(2))
+ | ^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:53:1
+ |
+LL | pub static R4: &[u8] = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:58:1
+ |
+LL | pub static R5: &[u8] = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:63:1
+ |
+LL | pub static R6: &[bool] = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ = note: accessing memory with alignment 1, but alignment 2 is required
+ |
+note: inside `std::slice::from_raw_parts::<'_, u16>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `from_ptr_range::<'_, u16>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R7`
+ --> $DIR/forbidden_slices.rs:70:5
+ |
+LL | from_ptr_range(ptr..ptr.add(4))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+ |
+note: inside `ptr::const_ptr::<impl *const u64>::offset`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u64>::add`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `R8`
+ --> $DIR/forbidden_slices.rs:74:25
+ |
+LL | from_ptr_range(ptr..ptr.add(1))
+ | ^^^^^^^^^^
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ = note: `ptr_offset_from_unsigned` called on pointers into different allocations
+ |
+note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `from_ptr_range::<'_, u32>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R9`
+ --> $DIR/forbidden_slices.rs:79:34
+ |
+LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ = note: `ptr_offset_from_unsigned` called on pointers into different allocations
+ |
+note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `from_ptr_range::<'_, u32>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R10`
+ --> $DIR/forbidden_slices.rs:80:35
+ |
+LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 18 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:20:1
+ |
+LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
+ | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 01 00 00 00 │ ....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:28:1
+ |
+LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 00 00 00 00 │ ....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:42:1
+ |
+LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!`
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 1, align: 1) {
+ 01 │ .
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:44:1
+ |
+LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 1, align: 1) {
+ 03 │ .
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:50:1
+ |
+LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ 78 00 00 00 ff ff ff ff │ x.......
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:54:1
+ |
+LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 00 00 00 00 │ ....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:57:1
+ |
+LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 1, align: 1) {
+ 00 │ .
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:59:1
+ |
+LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 00 00 00 00 │ ....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:65:1
+ |
+LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 2a 00 00 00 │ *...
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:71:1
+ |
+LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 14 00 00 00 │ ....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:74:1
+ |
+LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ 00 00 00 00 ╾ALLOC_ID╼ │ ....╾──╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:82:1
+ |
+LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
+ | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ ╾ALLOC_ID╼ │ ╾──╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:86:1
+ |
+LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ ╾ALLOC_ID╼ │ ╾──╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:90:1
+ |
+LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 00 00 00 00 │ ....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:93:1
+ |
+LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 00 00 00 00 │ ....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:96:1
+ |
+LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 39 05 00 00 │ 9...
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:99:1
+ |
+LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 39 05 00 00 │ 9...
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:102:1
+ |
+LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 00 00 00 00 │ ....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:104:1
+ |
+LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 0d 00 00 00 │ ....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:106:1
+ |
+LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a function pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ ╾ALLOC_ID╼ │ ╾──╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:112:1
+ |
+LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 01 00 00 00 │ ....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:137:1
+ |
+LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:139:1
+ |
+LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:141:1
+ |
+LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:144:1
+ |
+LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:146:1
+ |
+LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:148:1
+ |
+LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:152:1
+ |
+LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:154:1
+ |
+LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ ff ff ff 7f │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:157:1
+ |
+LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:160:1
+ |
+LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ ╾ALLOC_ID╼ │ ╾──╼
+ }
+
+note: erroneous constant used
+ --> $DIR/raw-bytes.rs:160:40
+ |
+LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:166:1
+ |
+LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ ╾ALLOC_ID╼ │ ╾──╼
+ }
+
+note: erroneous constant used
+ --> $DIR/raw-bytes.rs:166:42
+ |
+LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:170:1
+ |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ ╾ALLOC_ID╼ │ ╾──╼
+ }
+
+note: erroneous constant used
+ --> $DIR/raw-bytes.rs:170:42
+ |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:175:1
+ |
+LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:179:1
+ |
+LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:183:1
+ |
+LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:186:1
+ |
+LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:190:1
+ |
+LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:194:1
+ |
+LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ 00 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:196:1
+ |
+LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:201:1
+ |
+LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ 00 10 00 00 00 00 00 00 │ ........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:205:1
+ |
+LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000003, 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ 09 00 00 00 03 00 00 00 │ ........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:209:1
+ |
+LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
+ | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1]
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 01 00 00 00 │ ....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:210:1
+ |
+LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
+ | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ 01 00 00 00 01 00 00 00 │ ........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:211:1
+ |
+LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
+ | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ 01 00 00 00 2a 00 00 00 │ ....*...
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:215:1
+ |
+LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
+ | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:218:1
+ |
+LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) };
+ | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:221:1
+ |
+LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
+ | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:225:1
+ |
+LL | pub static S7: &[u16] = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID+0x2╼ 04 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:232:1
+ |
+LL | pub static R4: &[u8] = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:237:1
+ |
+LL | pub static R5: &[u8] = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:242:1
+ |
+LL | pub static R6: &[bool] = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
+ }
+
+error: aborting due to 52 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:20:1
+ |
+LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
+ | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000001, 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ 01 00 00 00 00 00 00 00 │ ........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:28:1
+ |
+LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000000, 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ 00 00 00 00 00 00 00 00 │ ........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:42:1
+ |
+LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!`
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 1, align: 1) {
+ 01 │ .
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:44:1
+ |
+LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 1, align: 1) {
+ 03 │ .
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:50:1
+ |
+LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ 78 00 00 00 ff ff ff ff │ x.......
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:54:1
+ |
+LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ 00 00 00 00 00 00 00 00 │ ........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:57:1
+ |
+LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 1, align: 1) {
+ 00 │ .
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:59:1
+ |
+LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ 00 00 00 00 00 00 00 00 │ ........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:65:1
+ |
+LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 2a 00 00 00 │ *...
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:71:1
+ |
+LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 4, align: 4) {
+ 14 00 00 00 │ ....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:74:1
+ |
+LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ 00 00 00 00 00 00 00 00 ╾ALLOC_ID╼ │ ........╾──────╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:82:1
+ |
+LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
+ | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ ╾ALLOC_ID╼ │ ╾──────╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:86:1
+ |
+LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ ╾ALLOC_ID╼ │ ╾──────╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:90:1
+ |
+LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ 00 00 00 00 00 00 00 00 │ ........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:93:1
+ |
+LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ 00 00 00 00 00 00 00 00 │ ........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:96:1
+ |
+LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ 39 05 00 00 00 00 00 00 │ 9.......
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:99:1
+ |
+LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ 39 05 00 00 00 00 00 00 │ 9.......
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:102:1
+ |
+LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ 00 00 00 00 00 00 00 00 │ ........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:104:1
+ |
+LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ 0d 00 00 00 00 00 00 00 │ ........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:106:1
+ |
+LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a function pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ ╾ALLOC_ID╼ │ ╾──────╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:112:1
+ |
+LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ 01 00 00 00 00 00 00 00 │ ........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:137:1
+ |
+LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:139:1
+ |
+LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:141:1
+ |
+LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:144:1
+ |
+LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:146:1
+ |
+LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:148:1
+ |
+LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:152:1
+ |
+LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:154:1
+ |
+LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:157:1
+ |
+LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:160:1
+ |
+LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ ╾ALLOC_ID╼ │ ╾──────╼
+ }
+
+note: erroneous constant used
+ --> $DIR/raw-bytes.rs:160:40
+ |
+LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:166:1
+ |
+LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ ╾ALLOC_ID╼ │ ╾──────╼
+ }
+
+note: erroneous constant used
+ --> $DIR/raw-bytes.rs:166:42
+ |
+LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:170:1
+ |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ ╾ALLOC_ID╼ │ ╾──────╼
+ }
+
+note: erroneous constant used
+ --> $DIR/raw-bytes.rs:170:42
+ |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:175:1
+ |
+LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:179:1
+ |
+LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:183:1
+ |
+LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:186:1
+ |
+LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:190:1
+ |
+LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:194:1
+ |
+LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:196:1
+ |
+LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:201:1
+ |
+LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000000, 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:205:1
+ |
+LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000003, 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ 09 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 │ ................
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:209:1
+ |
+LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
+ | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1]
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 8, align: 8) {
+ 01 00 00 00 00 00 00 00 │ ........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:210:1
+ |
+LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
+ | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:211:1
+ |
+LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
+ | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ 01 00 00 00 00 00 00 00 2a 00 00 00 00 00 00 00 │ ........*.......
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:215:1
+ |
+LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
+ | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:218:1
+ |
+LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) };
+ | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:221:1
+ |
+LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
+ | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:225:1
+ |
+LL | pub static S7: &[u16] = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID+0x2╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:232:1
+ |
+LL | pub static R4: &[u8] = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:237:1
+ |
+LL | pub static R5: &[u8] = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/raw-bytes.rs:242:1
+ |
+LL | pub static R6: &[bool] = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error: aborting due to 52 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+// stderr-per-bitwidth
+// ignore-endian-big
+// ignore-tidy-linelength
+// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼"
+// normalize-stderr-test "alloc\d+" -> "allocN"
+#![feature(never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)]
+#![allow(invalid_value)]
+
+use std::mem;
+use std::alloc::Layout;
+use std::ptr::NonNull;
+use std::num::{NonZeroU8, NonZeroUsize};
+use std::slice::{from_ptr_range, from_raw_parts};
+
+#[repr(usize)]
+#[derive(Copy, Clone)]
+enum Enum {
+ A = 0,
+}
+const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
+//~^ ERROR is undefined behavior
+
+#[repr(usize)]
+#[derive(Copy, Clone)]
+enum Enum2 {
+ A = 2,
+}
+const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
+//~^ ERROR is undefined behavior
+
+#[derive(Copy, Clone)]
+enum Never {}
+
+// An enum with 3 variants of which some are uninhabited -- so the uninhabited variants *do*
+// have a discriminant.
+enum UninhDiscriminant {
+ A,
+ B(!),
+ C,
+ D(Never),
+}
+const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
+//~^ ERROR is undefined behavior
+const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
+//~^ ERROR is undefined behavior
+
+// Invalid enum field content (mostly to test printing of paths for enum tuple
+// variants and tuples).
+// Need to create something which does not clash with enum layout optimizations.
+const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
+//~^ ERROR is undefined behavior
+
+
+const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
+//~^ ERROR it is undefined behavior to use this value
+
+const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
+//~^ ERROR it is undefined behavior to use this value
+const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
+//~^ ERROR it is undefined behavior to use this value
+
+#[rustc_layout_scalar_valid_range_start(10)]
+#[rustc_layout_scalar_valid_range_end(30)]
+struct RestrictedRange1(u32);
+const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
+//~^ ERROR it is undefined behavior to use this value
+
+#[rustc_layout_scalar_valid_range_start(30)]
+#[rustc_layout_scalar_valid_range_end(10)]
+struct RestrictedRange2(u32);
+const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
+//~^ ERROR it is undefined behavior to use this value
+
+const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
+//~^ ERROR it is undefined behavior to use this value
+ let x: &dyn Send = &42;
+ let meta = std::ptr::metadata(x);
+ mem::transmute((0_usize, meta))
+};
+
+
+const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
+//~^ ERROR it is undefined behavior to use this value
+//~| constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+
+const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
+//~^ ERROR it is undefined behavior to use this value
+//~| constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
+
+const NULL: &u16 = unsafe { mem::transmute(0usize) };
+//~^ ERROR it is undefined behavior to use this value
+
+const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
+//~^ ERROR it is undefined behavior to use this value
+
+const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
+//~^ ERROR it is undefined behavior to use this value
+
+const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
+//~^ ERROR it is undefined behavior to use this value
+
+const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
+//~^ ERROR it is undefined behavior to use this value
+const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
+//~^ ERROR it is undefined behavior to use this value
+const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
+//~^ ERROR it is undefined behavior to use this value
+
+#[derive(Copy, Clone)]
+enum Bar {}
+
+const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
+//~^ ERROR it is undefined behavior to use this value
+
+
+/// A newtype wrapper to prevent MIR generation from inserting reborrows that would affect the error
+/// message.
+#[repr(transparent)]
+struct W<T>(T);
+
+#[repr(C)]
+union MaybeUninit<T: Copy> {
+ uninit: (),
+ init: T,
+}
+
+trait Trait {}
+impl Trait for bool {}
+
+// custom unsized type
+struct MyStr(str);
+
+// custom unsized type with sized fields
+struct MySlice<T: ?Sized>(bool, T);
+type MySliceBool = MySlice<[bool]>;
+
+const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
+//~^ ERROR it is undefined behavior to use this value
+const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
+//~^ ERROR it is undefined behavior to use this value
+const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
+//~^ ERROR it is undefined behavior to use this value
+
+const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+//~^ ERROR it is undefined behavior to use this value
+const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+//~^ ERROR it is undefined behavior to use this value
+const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
+//~^ ERROR: it is undefined behavior to use this value
+
+// # slice
+const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
+//~^ ERROR it is undefined behavior to use this value
+const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
+//~^ ERROR it is undefined behavior to use this value
+// bad slice box: length too big
+const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
+//~^ ERROR it is undefined behavior to use this value
+// bad data *inside* the slice
+const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+//~^ ERROR it is undefined behavior to use this value
+//~| constant
+
+
+// bad: sized field is not okay
+const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+//~^ ERROR it is undefined behavior to use this value
+//~| constant
+// bad: unsized part is not okay
+const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+//~^ ERROR it is undefined behavior to use this value
+//~| constant
+
+// bad trait object
+const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
+//~^ ERROR it is undefined behavior to use this value
+//~| expected a vtable
+// bad trait object
+const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
+//~^ ERROR it is undefined behavior to use this value
+//~| expected a vtable
+// bad trait object
+const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
+//~^ ERROR it is undefined behavior to use this value
+//~| expected a vtable
+const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
+//~^ ERROR it is undefined behavior to use this value
+//~| expected a vtable
+// bad data *inside* the trait object
+const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
+//~^ ERROR it is undefined behavior to use this value
+//~| expected a boolean
+
+const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
+//~^ ERROR it is undefined behavior to use this value
+const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
+//~^ ERROR it is undefined behavior to use this value
+
+
+// not ok, since alignment needs to be non-zero.
+const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
+//~^ ERROR it is undefined behavior to use this value
+
+// not ok, since alignment needs to be a power of two.
+const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
+//~^ ERROR it is undefined behavior to use this value
+
+
+const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior
+const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior
+const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; //~ ERROR undefined behavior
+
+
+// Reading uninitialized data
+pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
+//~^ ERROR: it is undefined behavior to use this value
+// Reinterpret pointers as integers (UB in CTFE.)
+pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) };
+//~^ ERROR: it is undefined behavior to use this value
+// Layout mismatch
+pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
+//~^ ERROR: it is undefined behavior to use this value
+
+// Reading padding is not ok
+pub static S7: &[u16] = unsafe {
+ //~^ ERROR: it is undefined behavior to use this value
+ let ptr = (&D2 as *const Struct as *const u16).add(1);
+
+ from_raw_parts(ptr, 4)
+};
+
+pub static R4: &[u8] = unsafe {
+ //~^ ERROR: it is undefined behavior to use this value
+ let ptr = (&D1) as *const mem::MaybeUninit<&u32> as *const u8;
+ from_ptr_range(ptr..ptr.add(1))
+};
+pub static R5: &[u8] = unsafe {
+ //~^ ERROR: it is undefined behavior to use this value
+ let ptr = &D3 as *const &u32;
+ from_ptr_range(ptr.cast()..ptr.add(1).cast())
+};
+pub static R6: &[bool] = unsafe {
+ //~^ ERROR: it is undefined behavior to use this value
+ let ptr = &D0 as *const u32 as *const bool;
+ from_ptr_range(ptr..ptr.add(4))
+};
+
+const D0: u32 = 0x11111111; // Constant chosen for endianness-independent behavior.
+const D1: mem::MaybeUninit<&u32> = mem::MaybeUninit::uninit();
+const D2: Struct = Struct { a: 1, b: 2, c: 3, d: 4 };
+const D3: &u32 = &42;
+
+#[repr(C)]
+struct Struct {
+ a: u8,
+ // _pad: [mem::MaybeUninit<u8>; 3]
+ b: u32,
+ c: u16,
+ d: u8,
+ // _pad: [mem::MaybeUninit<u8>; 1]
+}
+
+fn main() {}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:24:1
+ --> $DIR/ub-enum.rs:27:1
|
LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 01 00 00 00 │ ....
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:27:1
+ --> $DIR/ub-enum.rs:30:1
|
LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
| ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:30:1
+ --> $DIR/ub-enum.rs:33:1
|
LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:42:1
+ --> $DIR/ub-enum.rs:45:1
|
LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 00 00 00 00 │ ....
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:44:1
+ --> $DIR/ub-enum.rs:47:1
|
LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:47:1
+ --> $DIR/ub-enum.rs:50:1
|
LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:56:42
+ --> $DIR/ub-enum.rs:59:42
|
LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:61:1
+ --> $DIR/ub-enum.rs:64:1
|
LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:78:1
+ --> $DIR/ub-enum.rs:81:1
|
LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!`
|
= 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.
- = note: the raw bytes of the constant (size: 1, align: 1) {
- 01 │ .
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:80:1
+ --> $DIR/ub-enum.rs:83:1
|
LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never
|
= 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.
- = note: the raw bytes of the constant (size: 1, align: 1) {
- 03 │ .
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:88:1
+ --> $DIR/ub-enum.rs:91:1
|
LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
|
= 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 78 00 00 00 ff ff ff ff │ x.......
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:93:77
+ --> $DIR/ub-enum.rs:96:77
|
LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
| ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:95:77
+ --> $DIR/ub-enum.rs:98:77
|
LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
| ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:24:1
+ --> $DIR/ub-enum.rs:27:1
|
LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000001, 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- 01 00 00 00 00 00 00 00 │ ........
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:27:1
+ --> $DIR/ub-enum.rs:30:1
|
LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
| ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:30:1
+ --> $DIR/ub-enum.rs:33:1
|
LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:42:1
+ --> $DIR/ub-enum.rs:45:1
|
LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000000, 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- 00 00 00 00 00 00 00 00 │ ........
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:44:1
+ --> $DIR/ub-enum.rs:47:1
|
LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:47:1
+ --> $DIR/ub-enum.rs:50:1
|
LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:56:42
+ --> $DIR/ub-enum.rs:59:42
|
LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:61:1
+ --> $DIR/ub-enum.rs:64:1
|
LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:78:1
+ --> $DIR/ub-enum.rs:81:1
|
LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!`
|
= 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.
- = note: the raw bytes of the constant (size: 1, align: 1) {
- 01 │ .
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:80:1
+ --> $DIR/ub-enum.rs:83:1
|
LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never
|
= 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.
- = note: the raw bytes of the constant (size: 1, align: 1) {
- 03 │ .
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:88:1
+ --> $DIR/ub-enum.rs:91:1
|
LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
|
= 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 78 00 00 00 ff ff ff ff │ x.......
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:93:77
+ --> $DIR/ub-enum.rs:96:77
|
LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
| ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-enum.rs:95:77
+ --> $DIR/ub-enum.rs:98:77
|
LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
| ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
// stderr-per-bitwidth
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
#![feature(never_type)]
#![allow(invalid_value)]
+++ /dev/null
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-nonnull.rs:12:1
- |
-LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 00 00 00 00 │ ....
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-nonnull.rs:18:30
- |
-LL | let out_of_bounds_ptr = &ptr[255];
- | ^^^^^^^^ dereferencing pointer failed: alloc11 has size 1, so pointer to 256 bytes starting at offset 0 is out-of-bounds
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-nonnull.rs:22:1
- |
-LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
- |
- = 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.
- = note: the raw bytes of the constant (size: 1, align: 1) {
- 00 │ .
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-nonnull.rs:24:1
- |
-LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 00 00 00 00 │ ....
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-nonnull.rs:32:36
- |
-LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-nonnull.rs:41:1
- |
-LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 2a 00 00 00 │ *...
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-nonnull.rs:47:1
- |
-LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 14 00 00 00 │ ....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-nonnull.rs:50:1
- |
-LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 00 00 00 00 ╾─alloc26─╼ │ ....╾──╼
- }
-
-error: aborting due to 8 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
+++ /dev/null
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-nonnull.rs:12:1
- |
-LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- 00 00 00 00 00 00 00 00 │ ........
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-nonnull.rs:18:30
- |
-LL | let out_of_bounds_ptr = &ptr[255];
- | ^^^^^^^^ dereferencing pointer failed: alloc11 has size 1, so pointer to 256 bytes starting at offset 0 is out-of-bounds
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-nonnull.rs:22:1
- |
-LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
- |
- = 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.
- = note: the raw bytes of the constant (size: 1, align: 1) {
- 00 │ .
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-nonnull.rs:24:1
- |
-LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- 00 00 00 00 00 00 00 00 │ ........
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-nonnull.rs:32:36
- |
-LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-nonnull.rs:41:1
- |
-LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 2a 00 00 00 │ *...
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-nonnull.rs:47:1
- |
-LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 14 00 00 00 │ ....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-nonnull.rs:50:1
- |
-LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- 00 00 00 00 00 00 00 00 ╾───────alloc26───────╼ │ ........╾──────╼
- }
-
-error: aborting due to 8 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
-// stderr-per-bitwidth
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
#![feature(rustc_attrs, ptr_metadata)]
#![allow(invalid_value)] // make sure we cannot allow away the errors tested here
--- /dev/null
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-nonnull.rs:14:1
+ |
+LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-nonnull.rs:20:30
+ |
+LL | let out_of_bounds_ptr = &ptr[255];
+ | ^^^^^^^^ dereferencing pointer failed: alloc11 has size 1, so pointer to 256 bytes starting at offset 0 is out-of-bounds
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-nonnull.rs:24:1
+ |
+LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-nonnull.rs:26:1
+ |
+LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-nonnull.rs:34:36
+ |
+LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-nonnull.rs:43:1
+ |
+LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-nonnull.rs:49:1
+ |
+LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-nonnull.rs:52:1
+ |
+LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
+++ /dev/null
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:14:1
- |
-LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
- | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- ╾─alloc3──╼ │ ╾──╼
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:18:1
- |
-LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- ╾─alloc7──╼ │ ╾──╼
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:22:1
- |
-LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 00 00 00 00 │ ....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:25:1
- |
-LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 00 00 00 00 │ ....
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:32:1
- |
-LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:35:39
- |
-LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-note: erroneous constant used
- --> $DIR/ub-ref-ptr.rs:35:38
- |
-LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:38:86
- |
-LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
- | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-note: erroneous constant used
- --> $DIR/ub-ref-ptr.rs:38:85
- |
-LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:41:1
- |
-LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 39 05 00 00 │ 9...
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:44:1
- |
-LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 39 05 00 00 │ 9...
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:47:41
- |
-LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:51:1
- |
-LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 00 00 00 00 │ ....
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:53:38
- |
-LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:56:1
- |
-LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 0d 00 00 00 │ ....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:58:1
- |
-LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
- | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- ╾─alloc41─╼ │ ╾──╼
- }
-
-error: accessing memory with alignment 1, but alignment 4 is required
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
- = 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 #68585 <https://github.com/rust-lang/rust/issues/104616>
-note: inside `std::ptr::read::<u32>`
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::read`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `UNALIGNED_READ`
- --> $DIR/ub-ref-ptr.rs:65:5
- |
-LL | ptr.read();
- | ^^^^^^^^^^
- = note: `#[deny(invalid_alignment)]` on by default
-
-error: aborting due to 15 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
-Future incompatibility report: Future breakage diagnostic:
-error: accessing memory with alignment 1, but alignment 4 is required
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
- = 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 #68585 <https://github.com/rust-lang/rust/issues/104616>
-note: inside `std::ptr::read::<u32>`
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::read`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `UNALIGNED_READ`
- --> $DIR/ub-ref-ptr.rs:65:5
- |
-LL | ptr.read();
- | ^^^^^^^^^^
- = note: `#[deny(invalid_alignment)]` on by default
-
+++ /dev/null
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:14:1
- |
-LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
- | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- ╾───────alloc3────────╼ │ ╾──────╼
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:18:1
- |
-LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- ╾───────alloc7────────╼ │ ╾──────╼
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:22:1
- |
-LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- 00 00 00 00 00 00 00 00 │ ........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:25:1
- |
-LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- 00 00 00 00 00 00 00 00 │ ........
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:32:1
- |
-LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:35:39
- |
-LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-note: erroneous constant used
- --> $DIR/ub-ref-ptr.rs:35:38
- |
-LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:38:86
- |
-LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
- | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-note: erroneous constant used
- --> $DIR/ub-ref-ptr.rs:38:85
- |
-LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:41:1
- |
-LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- 39 05 00 00 00 00 00 00 │ 9.......
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:44:1
- |
-LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- 39 05 00 00 00 00 00 00 │ 9.......
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:47:41
- |
-LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:51:1
- |
-LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- 00 00 00 00 00 00 00 00 │ ........
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:53:38
- |
-LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:56:1
- |
-LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- 0d 00 00 00 00 00 00 00 │ ........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:58:1
- |
-LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
- | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- ╾───────alloc41───────╼ │ ╾──────╼
- }
-
-error: accessing memory with alignment 1, but alignment 4 is required
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
- = 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 #68585 <https://github.com/rust-lang/rust/issues/104616>
-note: inside `std::ptr::read::<u32>`
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::read`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `UNALIGNED_READ`
- --> $DIR/ub-ref-ptr.rs:65:5
- |
-LL | ptr.read();
- | ^^^^^^^^^^
- = note: `#[deny(invalid_alignment)]` on by default
-
-error: aborting due to 15 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
-Future incompatibility report: Future breakage diagnostic:
-error: accessing memory with alignment 1, but alignment 4 is required
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
- = 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 #68585 <https://github.com/rust-lang/rust/issues/104616>
-note: inside `std::ptr::read::<u32>`
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::read`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `UNALIGNED_READ`
- --> $DIR/ub-ref-ptr.rs:65:5
- |
-LL | ptr.read();
- | ^^^^^^^^^^
- = note: `#[deny(invalid_alignment)]` on by default
-
// ignore-tidy-linelength
-// stderr-per-bitwidth
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
#![allow(invalid_value)]
#![feature(const_ptr_read)]
--- /dev/null
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-ref-ptr.rs:16:1
+ |
+LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
+ | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-ref-ptr.rs:20:1
+ |
+LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-ref-ptr.rs:24:1
+ |
+LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-ref-ptr.rs:27:1
+ |
+LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-ref-ptr.rs:34:1
+ |
+LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-ref-ptr.rs:37:39
+ |
+LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+note: erroneous constant used
+ --> $DIR/ub-ref-ptr.rs:37:38
+ |
+LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-ref-ptr.rs:40:86
+ |
+LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
+ | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+note: erroneous constant used
+ --> $DIR/ub-ref-ptr.rs:40:85
+ |
+LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-ref-ptr.rs:43:1
+ |
+LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-ref-ptr.rs:46:1
+ |
+LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-ref-ptr.rs:49:41
+ |
+LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-ref-ptr.rs:53:1
+ |
+LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-ref-ptr.rs:55:38
+ |
+LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-ref-ptr.rs:58:1
+ |
+LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-ref-ptr.rs:60:1
+ |
+LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error: accessing memory with alignment 1, but alignment 4 is required
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ |
+ = 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 #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+ --> $DIR/ub-ref-ptr.rs:67:5
+ |
+LL | ptr.read();
+ | ^^^^^^^^^^
+ = note: `#[deny(invalid_alignment)]` on by default
+
+error: aborting due to 15 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: accessing memory with alignment 1, but alignment 4 is required
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ |
+ = 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 #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+ --> $DIR/ub-ref-ptr.rs:67:5
+ |
+LL | ptr.read();
+ | ^^^^^^^^^^
+ = note: `#[deny(invalid_alignment)]` on by default
+
+++ /dev/null
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-uninhabit.rs:14:1
- |
-LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar
- |
- = 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.
- = note: the raw bytes of the constant (size: 0, align: 1) {}
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-uninhabit.rs:17:1
- |
-LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 01 00 00 00 │ ....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-uninhabit.rs:20:1
- |
-LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar
- |
- = 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.
- = note: the raw bytes of the constant (size: 0, align: 1) {}
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
+++ /dev/null
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-uninhabit.rs:14:1
- |
-LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar
- |
- = 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.
- = note: the raw bytes of the constant (size: 0, align: 1) {}
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-uninhabit.rs:17:1
- |
-LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- 01 00 00 00 00 00 00 00 │ ........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-uninhabit.rs:20:1
- |
-LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar
- |
- = 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.
- = note: the raw bytes of the constant (size: 0, align: 1) {}
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
-// stderr-per-bitwidth
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
use std::mem;
--- /dev/null
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-uninhabit.rs:16:1
+ |
+LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init };
+ | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {}
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-uninhabit.rs:19:1
+ |
+LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-uninhabit.rs:22:1
+ |
+LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {}
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
+++ /dev/null
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:37:1
- |
-LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:39:1
- |
-LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼....
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:42:1
- |
-LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:45:1
- |
-LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:47:1
- |
-LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:51:1
- |
-LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:54:1
- |
-LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:61:1
- |
-LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:68:1
- |
-LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:71:1
- |
-LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ ff ff ff 7f │ ╾──╼....
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:74:1
- |
-LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:77:1
- |
-LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼....
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:80:1
- |
-LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:84:1
- |
-LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- ╾ALLOC_ID╼ │ ╾──╼
- }
-
-note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:84:40
- |
-LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:91:1
- |
-LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- ╾ALLOC_ID╼ │ ╾──╼
- }
-
-note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:91:42
- |
-LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:95:1
- |
-LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- ╾ALLOC_ID╼ │ ╾──╼
- }
-
-note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:95:42
- |
-LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:103:1
- |
-LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:112:1
- |
-LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:116:1
- |
-LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:120:1
- |
-LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:123:57
- |
-LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:126:57
- |
-LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:129:56
- |
-LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:132:1
- |
-LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:137:1
- |
-LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:142:1
- |
-LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ 00 00 00 00 │ ╾──╼....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:144:1
- |
-LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
- }
-
-error[E0080]: could not evaluate static initializer
- --> $DIR/ub-wide-ptr.rs:150:5
- |
-LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
-
-error[E0080]: could not evaluate static initializer
- --> $DIR/ub-wide-ptr.rs:154:5
- |
-LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error: aborting due to 29 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
+++ /dev/null
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:37:1
- |
-LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:39:1
- |
-LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:42:1
- |
-LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:45:1
- |
-LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:47:1
- |
-LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:51:1
- |
-LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:54:1
- |
-LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:61:1
- |
-LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:68:1
- |
-LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:71:1
- |
-LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:74:1
- |
-LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:77:1
- |
-LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:80:1
- |
-LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:84:1
- |
-LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- ╾ALLOC_ID╼ │ ╾──────╼
- }
-
-note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:84:40
- |
-LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:91:1
- |
-LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- ╾ALLOC_ID╼ │ ╾──────╼
- }
-
-note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:91:42
- |
-LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:95:1
- |
-LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- ╾ALLOC_ID╼ │ ╾──────╼
- }
-
-note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:95:42
- |
-LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:103:1
- |
-LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:112:1
- |
-LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:116:1
- |
-LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:120:1
- |
-LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:123:57
- |
-LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:126:57
- |
-LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:129:56
- |
-LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:132:1
- |
-LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:137:1
- |
-LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:142:1
- |
-LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:144:1
- |
-LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
- }
-
-error[E0080]: could not evaluate static initializer
- --> $DIR/ub-wide-ptr.rs:150:5
- |
-LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
-
-error[E0080]: could not evaluate static initializer
- --> $DIR/ub-wide-ptr.rs:154:5
- |
-LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error: aborting due to 29 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
-// stderr-per-bitwidth
// ignore-tidy-linelength
#![allow(unused)]
use std::mem;
-// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼"
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
// normalize-stderr-test "offset \d+" -> "offset N"
// normalize-stderr-test "alloc\d+" -> "allocN"
// normalize-stderr-test "size \d+" -> "size N"
--- /dev/null
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:38:1
+ |
+LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:40:1
+ |
+LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:43:1
+ |
+LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:46:1
+ |
+LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:48:1
+ |
+LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:52:1
+ |
+LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:55:1
+ |
+LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:62:1
+ |
+LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:69:1
+ |
+LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:72:1
+ |
+LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:75:1
+ |
+LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:78:1
+ |
+LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:81:1
+ |
+LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:85:1
+ |
+LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+note: erroneous constant used
+ --> $DIR/ub-wide-ptr.rs:85:40
+ |
+LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:92:1
+ |
+LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+note: erroneous constant used
+ --> $DIR/ub-wide-ptr.rs:92:42
+ |
+LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:96:1
+ |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+note: erroneous constant used
+ --> $DIR/ub-wide-ptr.rs:96:42
+ |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:104:1
+ |
+LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:113:1
+ |
+LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:117:1
+ |
+LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:121:1
+ |
+LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:124:57
+ |
+LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:127:57
+ |
+LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:130:56
+ |
+LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:133:1
+ |
+LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:138:1
+ |
+LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:143:1
+ |
+LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-wide-ptr.rs:145:1
+ |
+LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: could not evaluate static initializer
+ --> $DIR/ub-wide-ptr.rs:151:5
+ |
+LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
+
+error[E0080]: could not evaluate static initializer
+ --> $DIR/ub-wide-ptr.rs:155:5
+ |
+LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
+
+error: aborting due to 29 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
LL | let _: &'static _ = &C;
| ^^
-note: erroneous constant used
- --> $DIR/invalid-union.rs:43:25
- |
-LL | let _: &'static _ = &C;
- | ^^
-
error: aborting due to previous error
For more information about this error, try `rustc --explain E0080`.
LL | let _: &'static _ = &C;
| ^^
-note: erroneous constant used
- --> $DIR/invalid-union.rs:43:25
- |
-LL | let _: &'static _ = &C;
- | ^^
-
error: aborting due to previous error
For more information about this error, try `rustc --explain E0080`.
help: add missing generic argument
|
LL | struct S<const S: (), const S: S<S> = { S }>;
- | ~~~~
+ | +++
error[E0391]: cycle detected when computing type of `S::S`
--> $DIR/issue-103790.rs:4:32
+++ /dev/null
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/issue-83182.rs:5:1
- |
-LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─alloc4──╼ 01 00 00 00 │ ╾──╼....
- }
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0080`.
+++ /dev/null
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/issue-83182.rs:5:1
- |
-LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
- |
- = help: this code performed an operation that depends on the underlying bytes representing a pointer
- = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────alloc4────────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0080`.
-// stderr-per-bitwidth
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
use std::mem;
struct MyStr(str);
--- /dev/null
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/issue-83182.rs:7:1
+ |
+LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+ |
+ = help: this code performed an operation that depends on the underlying bytes representing a pointer
+ = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
error[E0080]: it is undefined behavior to use this value
- --> $DIR/alloc.rs:9:1
+ --> $DIR/alloc.rs:12:1
|
LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 00 10 00 00 00 00 00 00 │ ........
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/alloc.rs:13:1
+ --> $DIR/alloc.rs:16:1
|
LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000003, 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 09 00 00 00 03 00 00 00 │ ........
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
}
error: aborting due to 2 previous errors
error[E0080]: it is undefined behavior to use this value
- --> $DIR/alloc.rs:9:1
+ --> $DIR/alloc.rs:12:1
|
LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000000, 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/alloc.rs:13:1
+ --> $DIR/alloc.rs:16:1
|
LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000003, 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- 09 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 │ ................
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
}
error: aborting due to 2 previous errors
// stderr-per-bitwidth
// ignore-debug (the debug assertions change the error)
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
use std::alloc::Layout;
// ok
+++ /dev/null
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/validate_never_arrays.rs:4:1
- |
-LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
- | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1]
- |
- = 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.
- = note: the raw bytes of the constant (size: 4, align: 4) {
- 01 00 00 00 │ ....
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/validate_never_arrays.rs:7:1
- |
-LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
- | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 01 00 00 00 01 00 00 00 │ ........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/validate_never_arrays.rs:8:1
- |
-LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
- | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 01 00 00 00 2a 00 00 00 │ ....*...
- }
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
+++ /dev/null
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/validate_never_arrays.rs:4:1
- |
-LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
- | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1]
- |
- = 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.
- = note: the raw bytes of the constant (size: 8, align: 8) {
- 01 00 00 00 00 00 00 00 │ ........
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/validate_never_arrays.rs:7:1
- |
-LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
- | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................
- }
-
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/validate_never_arrays.rs:8:1
- |
-LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
- | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
- |
- = 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.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- 01 00 00 00 00 00 00 00 2a 00 00 00 00 00 00 00 │ ........*.......
- }
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
-// stderr-per-bitwidth
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
#![feature(never_type)]
const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior
--- /dev/null
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/validate_never_arrays.rs:6:1
+ |
+LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
+ | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1]
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/validate_never_arrays.rs:9:1
+ |
+LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
+ | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/validate_never_arrays.rs:10:1
+ |
+LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
+ | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
+ |
+ = 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.
+ = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+ HEX_DUMP
+ }
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
// compile-flags:-C extra-filename=-1
+// no-prefer-dynamic
#![crate_name = "crateresolve1"]
#![crate_type = "lib"]
// compile-flags:-C extra-filename=-2
+// no-prefer-dynamic
#![crate_name = "crateresolve1"]
#![crate_type = "lib"]
// compile-flags:-C extra-filename=-3
+// no-prefer-dynamic
#![crate_name = "crateresolve1"]
#![crate_type = "lib"]
// NOTE: This test is duplicated at `src/test/ui/error-codes/E0464.rs`.
extern crate crateresolve1;
-//~^ ERROR multiple matching crates for `crateresolve1`
+//~^ ERROR multiple candidates for `rlib` dependency `crateresolve1` found
-fn main() {
-}
+fn main() {}
-error[E0464]: multiple matching crates for `crateresolve1`
+error[E0464]: multiple candidates for `rlib` dependency `crateresolve1` found
--> $DIR/crateresolve1.rs:11:1
|
LL | extern crate crateresolve1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: candidates:
- crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-1.somelib
- crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-2.somelib
- crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-3.somelib
+ = note: candidate #1: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-1.somelib
+ = note: candidate #2: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-2.somelib
+ = note: candidate #3: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-3.somelib
error: aborting due to previous error
// normalize-stderr-test: "\\\?\\" -> ""
extern crate crateresolve2;
-//~^ ERROR multiple matching crates for `crateresolve2`
+//~^ ERROR multiple candidates for `rmeta` dependency `crateresolve2` found
-fn main() {
-}
+fn main() {}
-error[E0464]: multiple matching crates for `crateresolve2`
+error[E0464]: multiple candidates for `rmeta` dependency `crateresolve2` found
--> $DIR/crateresolve2.rs:10:1
|
LL | extern crate crateresolve2;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: candidates:
- crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-1.rmeta
- crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-2.rmeta
- crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-3.rmeta
+ = note: candidate #1: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-1.rmeta
+ = note: candidate #2: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-2.rmeta
+ = note: candidate #3: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-3.rmeta
error: aborting due to previous error
error[E0596]: cannot borrow `f.v` as mutable, as `f` is not declared as mutable
--> $DIR/issue-35937.rs:7:5
|
-LL | let f = Foo { v: Vec::new() };
- | - help: consider changing this to be mutable: `mut f`
LL | f.v.push("cat".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut f = Foo { v: Vec::new() };
+ | +++
error[E0594]: cannot assign to `s.x`, as `s` is not declared as mutable
--> $DIR/issue-35937.rs:16:5
|
-LL | let s = S { x: 42 };
- | - help: consider changing this to be mutable: `mut s`
LL | s.x += 1;
| ^^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut s = S { x: 42 };
+ | +++
error[E0594]: cannot assign to `s.x`, as `s` is not declared as mutable
--> $DIR/issue-35937.rs:20:5
|
-LL | fn bar(s: S) {
- | - help: consider changing this to be mutable: `mut s`
LL | s.x += 1;
| ^^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | fn bar(mut s: S) {
+ | +++
error: aborting due to 3 previous errors
error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference
--> $DIR/issue-38147-1.rs:17:9
|
-LL | fn f(&self) {
- | ----- help: consider changing this to be a mutable reference: `&mut self`
LL | self.s.push('x');
| ^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn f(&mut self) {
+ | ~~~~~~~~~
error: aborting due to previous error
error[E0596]: cannot borrow `*f.s` as mutable, as it is behind a `&` reference
--> $DIR/issue-38147-4.rs:6:5
|
-LL | fn f(x: usize, f: &Foo) {
- | ---- help: consider changing this to be a mutable reference: `&mut Foo<'_>`
LL | f.s.push('x');
| ^^^^^^^^^^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn f(x: usize, f: &mut Foo<'_>) {
+ | ~~~~~~~~~~~~
error: aborting due to previous error
error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable
--> $DIR/issue-39544.rs:11:13
|
-LL | let z = Z { x: X::Y };
- | - help: consider changing this to be mutable: `mut z`
LL | let _ = &mut z.x;
| ^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut z = Z { x: X::Y };
+ | +++
error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference
--> $DIR/issue-39544.rs:16:17
|
-LL | fn foo<'z>(&'z self) {
- | -------- help: consider changing this to be a mutable reference: `&'z mut self`
LL | let _ = &mut self.x;
| ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn foo<'z>(&'z mut self) {
+ | ~~~~~~~~~~~~
error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference
--> $DIR/issue-39544.rs:20:17
|
-LL | fn foo1(&self, other: &Z) {
- | ----- help: consider changing this to be a mutable reference: `&mut self`
LL | let _ = &mut self.x;
| ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn foo1(&mut self, other: &Z) {
+ | ~~~~~~~~~
error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference
--> $DIR/issue-39544.rs:21:17
|
-LL | fn foo1(&self, other: &Z) {
- | -- help: consider changing this to be a mutable reference: `&mut Z`
-LL | let _ = &mut self.x;
LL | let _ = &mut other.x;
| ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn foo1(&self, other: &mut Z) {
+ | ~~~~~~
error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference
--> $DIR/issue-39544.rs:25:17
|
-LL | fn foo2<'a>(&'a self, other: &Z) {
- | -------- help: consider changing this to be a mutable reference: `&'a mut self`
LL | let _ = &mut self.x;
| ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn foo2<'a>(&'a mut self, other: &Z) {
+ | ~~~~~~~~~~~~
error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference
--> $DIR/issue-39544.rs:26:17
|
-LL | fn foo2<'a>(&'a self, other: &Z) {
- | -- help: consider changing this to be a mutable reference: `&mut Z`
-LL | let _ = &mut self.x;
LL | let _ = &mut other.x;
| ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn foo2<'a>(&'a self, other: &mut Z) {
+ | ~~~~~~
error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference
--> $DIR/issue-39544.rs:30:17
|
-LL | fn foo3<'a>(self: &'a Self, other: &Z) {
- | -------- help: consider changing this to be a mutable reference: `&'a mut Self`
LL | let _ = &mut self.x;
| ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn foo3<'a>(self: &'a mut Self, other: &Z) {
+ | ~~~~~~~~~~~~
error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference
--> $DIR/issue-39544.rs:31:17
|
-LL | fn foo3<'a>(self: &'a Self, other: &Z) {
- | -- help: consider changing this to be a mutable reference: `&mut Z`
-LL | let _ = &mut self.x;
LL | let _ = &mut other.x;
| ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn foo3<'a>(self: &'a Self, other: &mut Z) {
+ | ~~~~~~
error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference
--> $DIR/issue-39544.rs:35:17
|
-LL | fn foo4(other: &Z) {
- | -- help: consider changing this to be a mutable reference: `&mut Z`
LL | let _ = &mut other.x;
| ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn foo4(other: &mut Z) {
+ | ~~~~~~
error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable
--> $DIR/issue-39544.rs:41:13
|
-LL | pub fn with_arg(z: Z, w: &Z) {
- | - help: consider changing this to be mutable: `mut z`
LL | let _ = &mut z.x;
| ^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | pub fn with_arg(mut z: Z, w: &Z) {
+ | +++
error[E0596]: cannot borrow `w.x` as mutable, as it is behind a `&` reference
--> $DIR/issue-39544.rs:42:13
|
-LL | pub fn with_arg(z: Z, w: &Z) {
- | -- help: consider changing this to be a mutable reference: `&mut Z`
-LL | let _ = &mut z.x;
LL | let _ = &mut w.x;
| ^^^^^^^^ `w` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | pub fn with_arg(z: Z, w: &mut Z) {
+ | ~~~~~~
error[E0594]: cannot assign to `*x.0`, which is behind a `&` reference
--> $DIR/issue-39544.rs:48:5
error[E0596]: cannot borrow `*buf` as mutable, as it is behind a `&` reference
--> $DIR/issue-40823.rs:3:5
|
-LL | let mut buf = &[1, 2, 3, 4];
- | ------------- help: consider changing this to be a mutable reference: `&mut [1, 2, 3, 4]`
LL | buf.iter_mut();
| ^^^^^^^^^^^^^^ `buf` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let mut buf = &mut [1, 2, 3, 4];
+ | ~~~~~~~~~~~~~~~~~
error: aborting due to previous error
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+
+// pretty-expanded FIXME #23616
+
+trait hax {
+ fn dummy(&self) { }
+}
+impl<A> hax for A { }
+
+fn perform_hax<T: 'static>(x: Box<T>) -> Box<dyn hax+'static> {
+ Box::new(x) as Box<dyn hax+'static>
+}
+
+fn deadcode() {
+ perform_hax(Box::new("deadcode".to_string()));
+}
+
+pub fn main() {
+ let _ = perform_hax(Box::new(42));
+}
error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
--> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:21:1
|
-LL | / impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
-LL | |
-LL | |
-LL | | // (unsafe to access self.1 due to #[may_dangle] on A)
-LL | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
-LL | | }
- | |_^
+LL | impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the trait `Drop` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
help: add `unsafe` to this trait implementation
error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
--> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:27:1
|
-LL | / impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
-LL | |
-LL | |
-LL | | // (unsafe to access self.1 due to #[may_dangle] on 'a)
-LL | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
-LL | | }
- | |_^
+LL | impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the trait `Drop` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
help: add `unsafe` to this trait implementation
--- /dev/null
+// run-pass
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
+
+struct A(i32);
+
+impl Drop for A {
+ fn drop(&mut self) {
+ // update global drop count
+ DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
+ }
+}
+
+static FOO: A = A(123);
+const BAR: A = A(456);
+
+impl A {
+ const BAZ: A = A(789);
+}
+
+fn main() {
+ assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 0);
+ assert_eq!(&FOO.0, &123);
+ assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 0);
+ assert_eq!(BAR.0, 456);
+ assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 1);
+ assert_eq!(A::BAZ.0, 789);
+ assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2);
+}
LL | #![feature(dyn_star)]
| ^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted
LL | #![feature(dyn_star)]
| ^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0277]: `AlignedUsize` needs to be a pointer-sized type
LL | #![feature(dyn_star)]
| ^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted
LL | #![feature(dyn_star)]
| ^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted
LL | pub fn dyn_star_parameter(_: &dyn* Send) {
| ^^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= help: add `#![feature(dyn_star)]` to the crate attributes to enable
error: aborting due to previous error
LL | let dyn_i: dyn* Debug = i as dyn* Debug;
| ^^^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= help: add `#![feature(dyn_star)]` to the crate attributes to enable
error[E0658]: dyn* trait objects are unstable
LL | let dyn_i: dyn* Debug = i as dyn* Debug;
| ^^^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= help: add `#![feature(dyn_star)]` to the crate attributes to enable
error[E0606]: casting `usize` as `dyn* Debug` is invalid
LL | #![feature(dyn_star, trait_upcasting)]
| ^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0308]: mismatched types
LL | #![feature(dyn_star)]
| ^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted
LL | #![feature(dyn_star, trait_upcasting)]
| ^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0277]: `dyn* Foo` needs to be a pointer-sized type
--- /dev/null
+use std::collections::BTreeSet;
+
+#[derive(Hash)]
+pub enum ElemDerived {
+ //~^ ERROR recursive type `ElemDerived` has infinite size
+ A(ElemDerived)
+}
+
+
+pub enum Elem {
+ Derived(ElemDerived)
+}
+
+pub struct Set(BTreeSet<Elem>);
+
+impl Set {
+ pub fn into_iter(self) -> impl Iterator<Item = Elem> {
+ self.0.into_iter()
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0072]: recursive type `ElemDerived` has infinite size
+ --> $DIR/issue-72554.rs:4:1
+ |
+LL | pub enum ElemDerived {
+ | ^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | A(ElemDerived)
+ | ----------- recursive without indirection
+ |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
+ |
+LL | A(Box<ElemDerived>)
+ | ++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0072`.
--- /dev/null
+static X: i32 = 42;
+const Y: i32 = X; //~ ERROR constants cannot refer to statics [E0013]
+
+fn main() {}
--- /dev/null
+error[E0013]: constants cannot refer to statics
+ --> $DIR/E0013.rs:2:16
+ |
+LL | const Y: i32 = X;
+ | ^
+ |
+ = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0013`.
--- /dev/null
+fn create_some() -> Option<u8> {
+ Some(1)
+}
+
+const FOO: Option<u8> = create_some();
+//~^ ERROR cannot call non-const fn `create_some` in constants [E0015]
+
+fn main() {}
--- /dev/null
+error[E0015]: cannot call non-const fn `create_some` in constants
+ --> $DIR/E0015.rs:5:25
+ |
+LL | const FOO: Option<u8> = create_some();
+ | ^^^^^^^^^^^^^
+ |
+ = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
// compile-flags: -Z teach
-
trait SomeTrait {
- fn foo(); //~ associated function `foo` has no `self` parameter
+ fn foo(&self);
+}
+struct S;
+impl SomeTrait for S {
+ fn foo(&self) {}
}
-
fn main() {
- let trait_obj: &dyn SomeTrait = SomeTrait;
- //~^ ERROR expected value, found trait `SomeTrait`
- //~| ERROR E0038
+ let trait_obj: &dyn SomeTrait = &S;
let &invalid = trait_obj;
//~^ ERROR E0033
-error[E0423]: expected value, found trait `SomeTrait`
- --> $DIR/E0033-teach.rs:8:37
- |
-LL | let trait_obj: &dyn SomeTrait = SomeTrait;
- | ^^^^^^^^^ not a value
-
-error[E0038]: the trait `SomeTrait` cannot be made into an object
- --> $DIR/E0033-teach.rs:8:20
- |
-LL | let trait_obj: &dyn SomeTrait = SomeTrait;
- | ^^^^^^^^^^^^^^ `SomeTrait` cannot be made into an object
- |
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
- --> $DIR/E0033-teach.rs:4:8
- |
-LL | trait SomeTrait {
- | --------- this trait cannot be made into an object...
-LL | fn foo();
- | ^^^ ...because associated function `foo` has no `self` parameter
-help: consider turning `foo` into a method by giving it a `&self` argument
- |
-LL | fn foo(&self);
- | +++++
-help: alternatively, consider constraining `foo` so it does not apply to trait objects
- |
-LL | fn foo() where Self: Sized;
- | +++++++++++++++++
-
error[E0033]: type `&dyn SomeTrait` cannot be dereferenced
--> $DIR/E0033-teach.rs:12:9
|
You can read more about trait objects in the Trait Objects section of the Reference: https://doc.rust-lang.org/reference/types.html#trait-objects
-error: aborting due to 3 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0033, E0038, E0423.
-For more information about an error, try `rustc --explain E0033`.
+For more information about this error, try `rustc --explain E0033`.
trait SomeTrait {
- fn foo(); //~ associated function `foo` has no `self` parameter
+ fn foo(&self);
+}
+struct S;
+impl SomeTrait for S {
+ fn foo(&self) {}
}
-
fn main() {
- let trait_obj: &dyn SomeTrait = SomeTrait;
- //~^ ERROR expected value, found trait `SomeTrait`
- //~| ERROR E0038
+ let trait_obj: &dyn SomeTrait = &S;
let &invalid = trait_obj;
//~^ ERROR E0033
-error[E0423]: expected value, found trait `SomeTrait`
- --> $DIR/E0033.rs:6:37
- |
-LL | let trait_obj: &dyn SomeTrait = SomeTrait;
- | ^^^^^^^^^ not a value
-
-error[E0038]: the trait `SomeTrait` cannot be made into an object
- --> $DIR/E0033.rs:6:20
- |
-LL | let trait_obj: &dyn SomeTrait = SomeTrait;
- | ^^^^^^^^^^^^^^ `SomeTrait` cannot be made into an object
- |
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
- --> $DIR/E0033.rs:2:8
- |
-LL | trait SomeTrait {
- | --------- this trait cannot be made into an object...
-LL | fn foo();
- | ^^^ ...because associated function `foo` has no `self` parameter
-help: consider turning `foo` into a method by giving it a `&self` argument
- |
-LL | fn foo(&self);
- | +++++
-help: alternatively, consider constraining `foo` so it does not apply to trait objects
- |
-LL | fn foo() where Self: Sized;
- | +++++++++++++++++
-
error[E0033]: type `&dyn SomeTrait` cannot be dereferenced
- --> $DIR/E0033.rs:10:9
+ --> $DIR/E0033.rs:11:9
|
LL | let &invalid = trait_obj;
| ^^^^^^^^ type `&dyn SomeTrait` cannot be dereferenced
-error: aborting due to 3 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0033, E0038, E0423.
-For more information about an error, try `rustc --explain E0033`.
+For more information about this error, try `rustc --explain E0033`.
--> $DIR/E0199.rs:6:1
|
LL | unsafe impl Bar for Foo { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^
|
help: remove `unsafe` from this trait implementation
|
--> $DIR/E0200.rs:5:1
|
LL | impl Bar for Foo { }
- | ^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^
|
= note: the trait `Bar` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
help: add `unsafe` to this trait implementation
error[E0594]: cannot assign to `fancy_ref.num`, which is behind a `&` reference
--> $DIR/E0389.rs:8:5
|
-LL | let fancy_ref = &(&mut fancy);
- | ------------- help: consider changing this to be a mutable reference: `&mut (&mut fancy)`
LL | fancy_ref.num = 6;
| ^^^^^^^^^^^^^^^^^ `fancy_ref` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let fancy_ref = &mut (&mut fancy);
+ | ~~~~~~~~~~~~~~~~~
error: aborting due to previous error
// NOTE: This test is duplicated from `src/test/ui/crate-loading/crateresolve1.rs`.
extern crate crateresolve1;
-//~^ ERROR multiple matching crates for `crateresolve1`
+//~^ ERROR multiple candidates for `rlib` dependency `crateresolve1` found
-fn main() {
-}
+fn main() {}
-error[E0464]: multiple matching crates for `crateresolve1`
+error[E0464]: multiple candidates for `rlib` dependency `crateresolve1` found
--> $DIR/E0464.rs:11:1
|
LL | extern crate crateresolve1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: candidates:
- crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-1.somelib
- crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-2.somelib
- crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-3.somelib
+ = note: candidate #1: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-1.somelib
+ = note: candidate #2: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-2.somelib
+ = note: candidate #3: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-3.somelib
error: aborting due to previous error
--- /dev/null
+// no need to create a new aux file, we can use an existing.
+// aux-build: crateresolve1-1.rs
+
+// set same metadata as `crateresolve1`
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+extern crate crateresolve1; //~ ERROR E0519
--- /dev/null
+error[E0519]: the current crate is indistinguishable from one of its dependencies: it has the same crate-name `crateresolve1` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two.
+ --> $DIR/E0519.rs:8:1
+ |
+LL | extern crate crateresolve1;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0519`.
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/E0596.rs:3:13
|
-LL | let x = 1;
- | - help: consider changing this to be mutable: `mut x`
LL | let y = &mut x;
| ^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x = 1;
+ | +++
error: aborting due to previous error
|
LL | T: Into<&u32>,
| ^ explicit lifetime name needed here
+ |
+help: consider introducing a higher-ranked lifetime here with `for<'a>`
+ --> $DIR/E0637.rs:13:8
+ |
+LL | T: Into<&u32>,
+ | ^
error: aborting due to 3 previous errors
--- /dev/null
+// copied from: src/test/ui/feature-gates/stability-attribute-consistency.rs
+
+#![feature(staged_api)]
+
+#![stable(feature = "stable_test_feature", since = "1.0.0")]
+
+#[stable(feature = "foo", since = "1.0.0")]
+fn foo_stable_1_0_0() {}
+
+#[stable(feature = "foo", since = "1.29.0")]
+//~^ ERROR feature `foo` is declared stable since 1.29.0
+fn foo_stable_1_29_0() {}
+
+#[unstable(feature = "foo", issue = "none")]
+//~^ ERROR feature `foo` is declared unstable
+fn foo_unstable() {}
+
+fn main() {}
--- /dev/null
+error[E0711]: feature `foo` is declared stable since 1.29.0, but was previously declared stable since 1.0.0
+ --> $DIR/E0711.rs:10:1
+ |
+LL | #[stable(feature = "foo", since = "1.29.0")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0711]: feature `foo` is declared unstable, but was previously declared stable
+ --> $DIR/E0711.rs:14:1
+ |
+LL | #[unstable(feature = "foo", issue = "none")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0711`.
// compile-flags:-C extra-filename=-1
+// no-prefer-dynamic
#![crate_name = "crateresolve1"]
#![crate_type = "lib"]
// compile-flags:-C extra-filename=-2
+// no-prefer-dynamic
#![crate_name = "crateresolve1"]
#![crate_type = "lib"]
// compile-flags:-C extra-filename=-3
+// no-prefer-dynamic
#![crate_name = "crateresolve1"]
#![crate_type = "lib"]
fn main() {
let p = Some(45).and_then({
- //~^ expected a `FnOnce<({integer},)>` closure, found `Option<_>`
|x| println!("doubling {}", x);
Some(x * 2)
//~^ ERROR: cannot find value `x` in this scope
error[E0425]: cannot find value `x` in this scope
- --> $DIR/ruby_style_closure.rs:13:14
+ --> $DIR/ruby_style_closure.rs:12:14
|
LL | Some(x * 2)
| ^ not found in this scope
-error[E0277]: expected a `FnOnce<({integer},)>` closure, found `Option<_>`
- --> $DIR/ruby_style_closure.rs:10:31
- |
-LL | let p = Some(45).and_then({
- | ______________________--------_^
- | | |
- | | required by a bound introduced by this call
-LL | |
-LL | | |x| println!("doubling {}", x);
-LL | | Some(x * 2)
- | | ----------- this tail expression is of type `Option<_>`
-LL | |
-LL | | });
- | |_____^ expected an `FnOnce<({integer},)>` closure, found `Option<_>`
- |
- = help: the trait `FnOnce<({integer},)>` is not implemented for `Option<_>`
-note: required by a bound in `Option::<T>::and_then`
- --> $SRC_DIR/core/src/option.rs:LL:COL
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0277, E0425.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0425`.
--- /dev/null
+// run-pass
+#![feature(fn_traits, unboxed_closures)]
+use std::ops::Fn;
+
+struct Foo<T>(T);
+
+impl<T: Copy> Fn<()> for Foo<T> {
+ extern "rust-call" fn call(&self, _: ()) -> T {
+ match *self {
+ Foo(t) => t
+ }
+ }
+}
+
+impl<T: Copy> FnMut<()> for Foo<T> {
+ extern "rust-call" fn call_mut(&mut self, _: ()) -> T {
+ self.call(())
+ }
+}
+
+impl<T: Copy> FnOnce<()> for Foo<T> {
+ type Output = T;
+
+ extern "rust-call" fn call_once(self, _: ()) -> T {
+ self.call(())
+ }
+}
+
+fn main() {
+ let t: u8 = 1;
+ println!("{}", Foo(t)());
+}
error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0711`.
extern crate proc_macro;
-use proc_macro::{Literal, Span, TokenStream, TokenTree};
+use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
+use std::iter::FromIterator;
#[proc_macro]
pub fn foo_with_input_span(input: TokenStream) -> TokenStream {
TokenStream::from(TokenTree::Literal(lit))
}
+
+#[proc_macro]
+pub fn respan_to_invalid_format_literal(input: TokenStream) -> TokenStream {
+ let mut s = Literal::string("{");
+ s.set_span(input.into_iter().next().unwrap().span());
+ TokenStream::from_iter([
+ TokenTree::from(Ident::new("format", Span::call_site())),
+ TokenTree::from(Punct::new('!', Spacing::Alone)),
+ TokenTree::from(Group::new(Delimiter::Parenthesis, TokenTree::from(s).into())),
+ ])
+}
| |
| help: format specifiers use curly braces: `{}`
|
- = note: printf formatting not supported; see the documentation for `std::fmt`
+ = note: printf formatting is not supported; see the documentation for `std::fmt`
error: invalid format string: expected `'}'`, found `'t'`
--> $DIR/ifmt-bad-arg.rs:75:1
//~| NOTE: argument never used
//~| NOTE: argument never used
//~| NOTE: format specifiers use curly braces, and you have to use a positional or named parameter for the width
- //~| NOTE: printf formatting not supported
+ //~| NOTE: printf formatting is not supported
}
|
LL | print!("%0*x", width, num);
| ^^^^
- = note: printf formatting not supported; see the documentation for `std::fmt`
+ = note: printf formatting is not supported; see the documentation for `std::fmt`
error: aborting due to previous error
--- /dev/null
+// aux-build:format-string-proc-macro.rs
+
+extern crate format_string_proc_macro;
+
+fn main() {
+ format_string_proc_macro::respan_to_invalid_format_literal!("¡");
+ //~^ ERROR invalid format string: expected `'}'` but string was terminated
+ format_args!(r#concat!("¡ {"));
+ //~^ ERROR invalid format string: expected `'}'` but string was terminated
+}
--- /dev/null
+error: invalid format string: expected `'}'` but string was terminated
+ --> $DIR/respanned-literal-issue-106191.rs:6:65
+ |
+LL | format_string_proc_macro::respan_to_invalid_format_literal!("¡");
+ | ^^^ expected `'}'` in format string
+ |
+ = note: if you intended to print `{`, you can escape it using `{{`
+
+error: invalid format string: expected `'}'` but string was terminated
+ --> $DIR/respanned-literal-issue-106191.rs:8:18
+ |
+LL | format_args!(r#concat!("¡ {"));
+ | ^^^^^^^^^^^^^^^^^^^^^^^ expected `'}'` in format string
+ |
+ = note: if you intended to print `{`, you can escape it using `{{`
+ = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
fn main() {
let needlesArr: Vec<char> = vec!['a', 'f'];
needlesArr.iter().fold(|x, y| {
- //~^ ERROR this function takes 2 arguments but 1 argument was supplied
+ //~^ ERROR this method takes 2 arguments but 1 argument was supplied
});
}
-error[E0061]: this function takes 2 arguments but 1 argument was supplied
+error[E0061]: this method takes 2 arguments but 1 argument was supplied
--> $DIR/issue-3044.rs:3:23
|
LL | needlesArr.iter().fold(|x, y| {
fn returns_closure() -> _ {
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
//~| NOTE not allowed in type signatures
-//~| HELP consider using an `Fn`, `FnMut`, or `FnOnce` trait bound
-//~| NOTE for more information on `Fn` traits and closure types, see
-// https://doc.rust-lang.org/book/ch13-01-closures.html
+//~| HELP replace with an appropriate return type
+//~| SUGGESTION impl Fn() -> i32
+//~| NOTE for more information on `Fn` traits and closure types
|| 0
}
--> $DIR/issue-80179.rs:18:25
|
LL | fn returns_closure() -> _ {
- | ^ not allowed in type signatures
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace with an appropriate return type: `impl Fn() -> i32`
|
- = help: consider using an `Fn`, `FnMut`, or `FnOnce` trait bound
= note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
error: aborting due to 2 previous errors
--- /dev/null
+fn fn_once() -> _ {
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
+ //~| NOTE not allowed in type signatures
+ //~| HELP replace with an appropriate return type
+ //~| SUGGESTION impl FnOnce()
+ //~| NOTE for more information on `Fn` traits and closure types
+ let x = String::new();
+ || {
+ drop(x);
+ }
+}
+
+fn fn_mut() -> _ {
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
+ //~| NOTE not allowed in type signatures
+ //~| HELP replace with an appropriate return type
+ //~| SUGGESTION impl FnMut(char)
+ //~| NOTE for more information on `Fn` traits and closure types
+ let x = String::new();
+ |c| {
+ x.push(c);
+ }
+}
+
+fn fun() -> _ {
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
+ //~| NOTE not allowed in type signatures
+ //~| HELP replace with an appropriate return type
+ //~| SUGGESTION impl Fn() -> i32
+ //~| NOTE for more information on `Fn` traits and closure types
+ || 1i32
+}
+
+fn main() {}
--- /dev/null
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+ --> $DIR/suggest-return-closure.rs:1:17
+ |
+LL | fn fn_once() -> _ {
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace with an appropriate return type: `impl FnOnce()`
+ |
+ = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+ --> $DIR/suggest-return-closure.rs:13:16
+ |
+LL | fn fn_mut() -> _ {
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace with an appropriate return type: `impl FnMut(char)`
+ |
+ = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+ --> $DIR/suggest-return-closure.rs:25:13
+ |
+LL | fn fun() -> _ {
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace with an appropriate return type: `impl Fn() -> i32`
+ |
+ = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0121`.
--- /dev/null
+// edition: 2021
+
+async fn a() -> i32 {
+ 0
+}
+
+fn foo() -> _ {
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
+ //~| NOTE not allowed in type signatures
+ //~| HELP replace with an appropriate return type
+ //~| SUGGESTION impl Future<Output = i32>
+ a()
+}
+
+fn bar() -> _ {
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
+ //~| NOTE not allowed in type signatures
+ //~| HELP replace with an appropriate return type
+ //~| SUGGESTION impl Future<Output = i32>
+ async { a().await }
+}
+
+fn main() {}
--- /dev/null
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+ --> $DIR/suggest-return-future.rs:7:13
+ |
+LL | fn foo() -> _ {
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace with an appropriate return type: `impl Future<Output = i32>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+ --> $DIR/suggest-return-future.rs:15:13
+ |
+LL | fn bar() -> _ {
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace with an appropriate return type: `impl Future<Output = i32>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0121`.
| required by a bound introduced by this call
|
= help: within `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`, the trait `for<'a> Sized` is not implemented for `(dyn std::fmt::Display + 'a)`
- = note: required because it appears within the type `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`
+ = note: required because it appears within the type `for<'a> fn(&'a ()) -> (dyn Display + 'a)`
note: required by a bound in `foo`
--> $DIR/unsized-ret.rs:5:11
|
trait Bar {
//~^ NOTE `Bar` defines an item `bar`, perhaps you need to implement it
- //~| NOTE `Bar` defines an item `bar`, perhaps you need to implement it
fn bar(&self) {}
}
//~^ ERROR cannot find value `oops` in this scope
//~| NOTE not found
arc.bar();
- //~^ ERROR no method named `bar`
- //~| NOTE method not found
- //~| HELP items from traits can only be used if the trait is implemented and in scope
let arc2 = std::sync::Arc::new(|| Foo);
arc2.bar();
error[E0425]: cannot find value `oops` in this scope
- --> $DIR/fn-help-with-err.rs:14:35
+ --> $DIR/fn-help-with-err.rs:13:35
|
LL | let arc = std::sync::Arc::new(oops);
| ^^^^ not found in this scope
-error[E0599]: no method named `bar` found for struct `Arc<_>` in the current scope
- --> $DIR/fn-help-with-err.rs:17:9
- |
-LL | arc.bar();
- | ^^^ method not found in `Arc<_>`
- |
- = help: items from traits can only be used if the trait is implemented and in scope
-note: `Bar` defines an item `bar`, perhaps you need to implement it
- --> $DIR/fn-help-with-err.rs:5:1
- |
-LL | trait Bar {
- | ^^^^^^^^^
-
-error[E0599]: no method named `bar` found for struct `Arc<[closure@fn-help-with-err.rs:22:36]>` in the current scope
- --> $DIR/fn-help-with-err.rs:23:10
+error[E0599]: no method named `bar` found for struct `Arc<[closure@fn-help-with-err.rs:18:36]>` in the current scope
+ --> $DIR/fn-help-with-err.rs:19:10
|
LL | arc2.bar();
- | ^^^ method not found in `Arc<[closure@fn-help-with-err.rs:22:36]>`
+ | ^^^ method not found in `Arc<[closure@fn-help-with-err.rs:18:36]>`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `Bar` defines an item `bar`, perhaps you need to implement it
LL | arc2().bar();
| ++
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
Some errors have detailed explanations: E0425, E0599.
For more information about an error, try `rustc --explain E0425`.
a = d;
};
Pin::new(&mut b).resume();
- //~^ ERROR this function takes 1 argument but 0 arguments were supplied
+ //~^ ERROR this method takes 1 argument but 0 arguments were supplied
// This type error is required to reproduce the ICE...
}
-error[E0061]: this function takes 1 argument but 0 arguments were supplied
+error[E0061]: this method takes 1 argument but 0 arguments were supplied
--> $DIR/issue-102645.rs:16:22
|
LL | Pin::new(&mut b).resume();
|
LL | || {
| ^^
-note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
+note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])`
--> $DIR/generator-print-verbose-1.rs:41:30
|
LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> {
help: add missing lifetime argument
|
LL | fn g(&self) -> Self::Assoc<'_>;
- | ~~~~~~~~~
+ | ++++
error[E0107]: missing generics for associated type `Trait::Assoc`
--> $DIR/elided-in-expr-position.rs:31:26
help: add missing lifetime argument
|
LL | fn g(&self) -> Self::Assoc<'_> {
- | ~~~~~~~~~
+ | ++++
error: aborting due to 2 previous errors
help: add missing lifetime argument
|
LL | fn foo<'a, T1: X<Y<'a> = T1>>(t : T1) -> T1::Y<'a> {
- | ~~~~~
+ | ++++
error[E0107]: missing generics for associated type `X::Y`
--> $DIR/gat-trait-path-missing-lifetime.rs:8:20
help: add missing lifetime argument
|
LL | fn foo<'a, T1: X<Y<'a> = T1>>(t : T1) -> T1::Y<'a> {
- | ~~~~~
+ | ++++
error: aborting due to 2 previous errors
//~^ ERROR impl has stricter requirements than trait
type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
//~^ ERROR impl has stricter requirements than trait
- //~| ERROR lifetime bound not satisfied
type C = String where Self: Copy;
//~^ ERROR the trait bound `T: Copy` is not satisfied
fn d() where Self: Copy {}
...
LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
| ^^ impl has extra requirement `'b: 'a`
-
-error[E0478]: lifetime bound not satisfied
- --> $DIR/impl_bounds.rs:16:22
|
-LL | type B<'a, 'b> where 'a: 'b;
- | -------------- definition of `B` from trait
-...
-LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
- | ^^^^^^^^^^^^^^^ - help: try copying this clause from the trait: `, 'a: 'b`
+help: copy the `where` clause predicates from the trait
|
-note: lifetime parameter instantiated with the lifetime `'a` as defined here
- --> $DIR/impl_bounds.rs:16:12
- |
-LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
- | ^^
-note: but lifetime parameter must outlive the lifetime `'b` as defined here
- --> $DIR/impl_bounds.rs:16:16
- |
-LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
- | ^^
+LL | type B<'a, 'b> = (&'a(), &'b ()) where 'a: 'b;
+ | ~~~~~~~~~~~~
error[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/impl_bounds.rs:19:33
+ --> $DIR/impl_bounds.rs:18:33
|
LL | type C = String where Self: Copy;
| ^^^^ the trait `Copy` is not implemented for `T`
| +++++++++++++++++++
error[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/impl_bounds.rs:21:24
+ --> $DIR/impl_bounds.rs:20:24
|
LL | fn d() where Self: Copy {}
| ^^^^ the trait `Copy` is not implemented for `T`
LL | impl<T: std::marker::Copy> Foo for Fooy<T> {
| +++++++++++++++++++
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0276, E0277, E0478.
+Some errors have detailed explanations: E0276, E0277.
For more information about an error, try `rustc --explain E0276`.
help: add missing lifetime argument
|
LL | inner: Box<dyn Provider<A<'a> = B>>,
- | ~~~~~
+ | ++++
error: aborting due to previous error
help: add missing lifetime argument
|
LL | let sub: Box<dyn SuperTrait<SubType<'a> = SubStruct>> = Box::new(SuperStruct::new(0));
- | ~~~~~~~~~~~
+ | ++++
error[E0038]: the trait `SuperTrait` cannot be made into an object
--> $DIR/issue-76535.rs:39:14
help: add missing lifetime argument
|
LL | let sub: Box<dyn SuperTrait<SubType<'a> = SubStruct>> = Box::new(SuperStruct::new(0));
- | ~~~~~~~~~~~
+ | ++++
error: aborting due to previous error
help: add missing generic argument
|
LL | Box::new(Family) as &dyn CollectionFamily<Member<T>=usize>
- | ~~~~~~~~~
+ | +++
error[E0038]: the trait `CollectionFamily` cannot be made into an object
--> $DIR/issue-78671.rs:10:25
help: add missing generic argument
|
LL | Box::new(Family) as &dyn CollectionFamily<Member<T>=usize>
- | ~~~~~~~~~
+ | +++
error: aborting due to previous error
help: add missing lifetime argument
|
LL | as Box<dyn MapLike<u8, u8, VRefCont<'a> = dyn RefCont<'_, u8>>>;
- | ~~~~~~~~~~~~
+ | ++++
error[E0038]: the trait `MapLike` cannot be made into an object
--> $DIR/issue-79422.rs:47:12
help: add missing lifetime argument
|
LL | as Box<dyn MapLike<u8, u8, VRefCont<'a> = dyn RefCont<'_, u8>>>;
- | ~~~~~~~~~~~~
+ | ++++
error[E0271]: type mismatch resolving `<BTreeMap<u8, u8> as MapLike<u8, u8>>::VRefCont<'_> == (dyn RefCont<'_, u8> + 'static)`
--> $DIR/issue-79422.rs:44:13
help: add missing generic argument
|
LL | MInner: Monad<Unwrapped = A, Wrapped<B> = MOuter::Wrapped<A>>,
- | ~~~~~~~~~~
+ | +++
error: aborting due to previous error
help: add missing generic argument
|
LL | W: SomeTrait<Wrapped<A> = W>,
- | ~~~~~~~~~~
+ | +++
error: aborting due to previous error
help: add missing lifetime argument
|
LL | fn test_simpler<'a>(dst: &'a mut impl TestMut<Output<'a> = &'a mut f32>)
- | ~~~~~~~~~~
+ | ++++
error: aborting due to previous error
help: add missing generic argument
|
LL | type CType: C<DType<T> = Self>;
- | ~~~~~~~~
+ | +++
error: aborting due to previous error
help: add missing lifetime argument
|
LL | fn next(&mut self) -> Option<Self::Item<'_>>;
- | ~~~~~~~~
+ | ++++
error: aborting due to previous error
| ------------ definition of `Fut` from trait
...
LL | type Fut<'a> = impl Future<Output = ()>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
|
note: type must outlive the lifetime `'a` as defined here
--> $DIR/issue-90014.rs:13:14
|
LL | type Fut<'a> = impl Future<Output = ()>;
| ^^
+help: copy the `where` clause predicates from the trait
+ |
+LL | type Fut<'a> = impl Future<Output = ()> where Self: 'a;
+ | ++++++++++++++
error: aborting due to previous error
let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
//~^ ERROR `T` does not live long enough
//~| ERROR `T` does not live long enough
- //~| ERROR `T` does not live long enough
- //~| ERROR `T` does not live long enough
- //~| ERROR `T` does not live long enough
- //~| ERROR `T` does not live long enough
- //~| ERROR `T` does not live long enough
- //~| ERROR `T` does not live long enough
- //~| ERROR `T` may not live long enough
- //~| ERROR `T` may not live long enough
//
// FIXME: This error is bogus, but it arises because we try to validate
// that `<() as Foo<T>>::Type<'a>` is valid, which requires proving
LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: `T` does not live long enough
- --> $DIR/issue-91139.rs:14:12
- |
-LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `T` does not live long enough
- --> $DIR/issue-91139.rs:14:12
- |
-LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/issue-91139.rs:14:58
- |
-LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
- | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds
- |
-help: consider adding an explicit lifetime bound...
- |
-LL | fn foo<T: 'static>() {
- | +++++++++
-
-error: `T` does not live long enough
- --> $DIR/issue-91139.rs:14:58
- |
-LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
- | ^^^^^^^^^
-
-error: `T` does not live long enough
- --> $DIR/issue-91139.rs:14:58
- |
-LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
- | ^^^^^^^^^
-
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/issue-91139.rs:14:58
- |
-LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
- | ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
- |
-help: consider adding an explicit lifetime bound...
- |
-LL | fn foo<T: 'static>() {
- | +++++++++
-
-error: `T` does not live long enough
- --> $DIR/issue-91139.rs:14:58
- |
-LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
- | ^^^^^^^^^
-
-error: `T` does not live long enough
- --> $DIR/issue-91139.rs:14:58
- |
-LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
- | ^^^^^^^^^
-
-error: aborting due to 10 previous errors
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0310`.
| ----------------------------- definition of `Cursor` from trait
...
LL | type Cursor<'tx> = CursorImpl<'tx>;
- | ^^^^^^^^^^^^^^^- help: try copying these clauses from the trait: `where 'db: 'tx, Self: 'tx`
+ | ^^^^^^^^^^^^^^^
|
note: lifetime parameter instantiated with the lifetime `'db` as defined here
--> $DIR/issue-91883.rs:29:6
|
LL | type Cursor<'tx> = CursorImpl<'tx>;
| ^^^
+help: copy the `where` clause predicates from the trait
+ |
+LL | type Cursor<'tx> = CursorImpl<'tx> where 'db: 'tx, Self: 'tx;
+ | +++++++++++++++++++++++++
error: aborting due to previous error
| -------------------------------------------------- definition of `TextureIter` from trait
...
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: type must outlive the lifetime `'a` as defined here
--> $DIR/issue-92033.rs:20:22
|
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
| ^^
+help: copy the `where` clause predicates from the trait
+ |
+LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture> where Self: 'a;
+ | ++++++++++++++
error: aborting due to previous error
--- /dev/null
+trait Foo {
+ type T<'a1, 'b1>
+ where
+ 'a1: 'b1;
+}
+
+impl Foo for () {
+ type T<'a2, 'b2> = () where 'b2: 'a2;
+ //~^ ERROR impl has stricter requirements than trait
+}
+
+fn main() {}
--- /dev/null
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/mismatched-where-clause-regions.rs:8:38
+ |
+LL | type T<'a1, 'b1>
+ | ---------------- definition of `T` from trait
+...
+LL | type T<'a2, 'b2> = () where 'b2: 'a2;
+ | ^^^ impl has extra requirement `'b2: 'a2`
+ |
+help: copy the `where` clause predicates from the trait
+ |
+LL | type T<'a2, 'b2> = () where 'a2: 'b2;
+ | ~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0276`.
...
LL | type Assoc<'a, 'b> = () where 'a: 'b;
| ^^ impl has extra requirement `'a: 'b`
+ |
+help: remove the `where` clause
+ |
+LL - type Assoc<'a, 'b> = () where 'a: 'b;
+LL + type Assoc<'a, 'b> = () ;
+ |
error: aborting due to previous error
help: add missing lifetime arguments
|
LL | fn foo<'c, 'd>(_arg: Box<dyn X<Y<'_, '_> = (&'c u32, &'d u32)>>) {}
- | ~~~~~~~~~
+ | ++++++++
error[E0107]: this struct takes 3 lifetime arguments but 2 lifetime arguments were supplied
--> $DIR/missing_lifetime_args.rs:14:26
help: add missing generic argument
|
LL | let _: Vec<T>;
- | ~~~~~~
+ | +++
error: aborting due to previous error
|
LL | fn should_error<T>() where T : Into<&u32> {}
| ^ explicit lifetime name needed here
+ |
+help: consider introducing a higher-ranked lifetime here with `for<'a>`
+ --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:5:32
+ |
+LL | fn should_error<T>() where T : Into<&u32> {}
+ | ^
error[E0106]: missing lifetime specifier
--> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:20
help: add missing generic arguments
|
LL | type A = Ty<A, B>;
- | ~~~~~~~~
+ | ++++++
error[E0107]: this struct takes 2 generic arguments but 1 generic argument was supplied
--> $DIR/wrong-number-of-args.rs:30:14
help: add missing generic argument
|
LL | type A = Ty<T>;
- | ~~~~~
+ | +++
error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
--> $DIR/wrong-number-of-args.rs:54:14
help: add missing generic arguments
|
LL | type A = Ty<A, B>;
- | ~~~~~~~~
+ | ++++++
error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
--> $DIR/wrong-number-of-args.rs:84:14
help: add missing generic argument
|
LL | type D = Box<dyn GenericType<A>>;
- | ~~~~~~~~~~~~~~
+ | +++
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
--> $DIR/wrong-number-of-args.rs:133:22
help: add missing generic arguments
|
LL | type A = HashMap<K, V>;
- | ~~~~~~~~~~~~~
+ | ++++++
error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
--> $DIR/wrong-number-of-args.rs:314:18
help: add missing generic arguments
|
LL | type A = Result<T, E>;
- | ~~~~~~~~~~~~
+ | ++++++
error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied
--> $DIR/wrong-number-of-args.rs:338:18
--- /dev/null
+// Test that Fn-family traits with lifetime parameters shouldn't compile and
+// we suggest the usage of higher-rank trait bounds instead.
+
+fn fa(_: impl Fn<'a>(&'a str) -> bool) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+use std::ops::Fn as AliasedFn;
+fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn fe<F>(_: F) where F: Fn<'a>(&'a str) -> bool {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn main() {}
--- /dev/null
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:4:17
+ |
+LL | fn fa(_: impl Fn<'a>(&'a str) -> bool) {}
+ | ^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fa(_: impl Fn<'a>(&'a str) -> bool) {}
+LL + fn fa(_: impl for<'a> Fn(&'a str) -> bool) {}
+ |
+
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:7:20
+ |
+LL | fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {}
+ | ^^^^^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {}
+LL + fn fb(_: impl for<'a, 'b> FnMut(&'a str, &'b str) -> bool) {}
+ |
+
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:10:41
+ |
+LL | fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {}
+ | ^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {}
+LL + fn fc(_: impl std::fmt::Display + for<'a> FnOnce(&'a str) -> bool + std::fmt::Debug) {}
+ |
+
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:14:24
+ |
+LL | fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {}
+ | ^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {}
+LL + fn fd(_: impl for<'a> AliasedFn(&'a str) -> bool) {}
+ |
+
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:17:27
+ |
+LL | fn fe<F>(_: F) where F: Fn<'a>(&'a str) -> bool {}
+ | ^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fe<F>(_: F) where F: Fn<'a>(&'a str) -> bool {}
+LL + fn fe<F>(_: F) where F: for<'a> Fn(&'a str) -> bool {}
+ |
+
+error: aborting due to 5 previous errors
+
{}
fn main() {
- f(&[f()]); //~ ERROR this function takes 1 argument
+ f(&[f()]); //~ ERROR function takes 1 argument
}
fn give_me_ice<T>() {
callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
//~^ ERROR the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied [E0277]
+ //~| ERROR the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied [E0277]
}
fn callee<T: Fn<(&'static (),)>>() {
+error[E0277]: the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied
+ --> $DIR/issue-85455.rs:8:14
+ |
+LL | callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> SomeTrait<'a>` is not implemented for `T`
+ |
+help: consider restricting type parameter `T`
+ |
+LL | fn give_me_ice<T: for<'a> SomeTrait<'a>>() {
+ | +++++++++++++++++++++++
+
error[E0277]: the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied
--> $DIR/issue-85455.rs:8:5
|
LL | fn give_me_ice<T: for<'a> SomeTrait<'a>>() {
| +++++++++++++++++++++++
-error: aborting due to previous error
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// run-rustfix
+fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
+ *t.min().unwrap() //~ ERROR the `min` method cannot be invoked on
+}
+
+fn main() {
+ let array = [0u64];
+ test(&mut array.iter());
+}
--- /dev/null
+// run-rustfix
+fn test(t: &dyn Iterator<Item=&u64>) -> u64 {
+ *t.min().unwrap() //~ ERROR the `min` method cannot be invoked on
+}
+
+fn main() {
+ let array = [0u64];
+ test(&mut array.iter());
+}
--- /dev/null
+error: the `min` method cannot be invoked on `&dyn Iterator<Item = &u64>`
+ --> $DIR/mutability-mismatch-arg.rs:3:9
+ |
+LL | *t.min().unwrap()
+ | ^^^
+ |
+help: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
+ |
+LL | fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
+ | +++
+
+error: aborting due to previous error
+
fn function(&mut self)
where
Self: Sized;
- //~^ this has a `Sized` requirement
}
impl MutTrait for MutType {
fn function(&self)
where
Self: Sized;
- //~^ this has a `Sized` requirement
}
impl Trait for Type {
fn main() {
(&MutType as &dyn MutTrait).function();
- //~^ ERROR the `function` method cannot be invoked on a trait object
- //~| NOTE you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
+ //~^ ERROR the `function` method cannot be invoked on `&dyn MutTrait`
+ //~| HELP you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
(&mut Type as &mut dyn Trait).function();
- //~^ ERROR the `function` method cannot be invoked on a trait object
- //~| NOTE you need `&dyn Trait` instead of `&mut dyn Trait`
+ //~^ ERROR the `function` method cannot be invoked on `&mut dyn Trait`
+ //~| HELP you need `&dyn Trait` instead of `&mut dyn Trait`
}
-error: the `function` method cannot be invoked on a trait object
- --> $DIR/mutability-mismatch.rs:28:33
+error: the `function` method cannot be invoked on `&dyn MutTrait`
+ --> $DIR/mutability-mismatch.rs:26:33
|
-LL | Self: Sized;
- | ----- this has a `Sized` requirement
-...
LL | (&MutType as &dyn MutTrait).function();
| ^^^^^^^^
|
- = note: you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
+ = help: you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
-error: the `function` method cannot be invoked on a trait object
- --> $DIR/mutability-mismatch.rs:31:35
+error: the `function` method cannot be invoked on `&mut dyn Trait`
+ --> $DIR/mutability-mismatch.rs:29:35
|
-LL | Self: Sized;
- | ----- this has a `Sized` requirement
-...
LL | (&mut Type as &mut dyn Trait).function();
| ^^^^^^^^
|
- = note: you need `&dyn Trait` instead of `&mut dyn Trait`
+ = help: you need `&dyn Trait` instead of `&mut dyn Trait`
error: aborting due to 2 previous errors
fn main() {
f::<[u8]>("a", b"a");
- //~^ ERROR: this function takes 2 generic arguments but 1 generic argument was supplied
+ //~^ ERROR function takes 2 generic arguments but 1 generic argument was supplied
}
|
LL | fn foo<A: Debug>(&self, a: &A, b: &impl Debug);
| ^^
- = note: expected fn pointer `fn(&(), &B, &impl Debug)`
- found fn pointer `fn(&(), &impl Debug, &B)`
+ = note: expected signature `fn(&(), &B, &impl Debug)`
+ found signature `fn(&(), &impl Debug, &B)`
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
--- /dev/null
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+//~^ WARN the feature `return_position_impl_trait_in_trait` is incomplete
+
+struct TestA {}
+struct TestB {}
+
+impl TestTrait for TestA {
+ type Output = ();
+}
+impl TestTrait for TestB {
+ type Output = ();
+}
+
+trait TestTrait {
+ type Output;
+}
+
+impl<A, B> TestTrait for GreeterOutput<A, B>
+where
+ A: TestTrait<Output = ()>,
+ B: TestTrait<Output = ()>,
+{
+ type Output = ();
+}
+
+enum GreeterOutput<A, B>
+where
+ A: TestTrait<Output = ()>,
+ B: TestTrait<Output = ()>,
+{
+ SayHello(A),
+ SayGoodbye(B),
+}
+
+trait Greeter {
+ fn test_func(&self, func: &str) -> impl TestTrait<Output = ()> {
+ match func {
+ "SayHello" => GreeterOutput::SayHello(TestA {}),
+ "SayGoodbye" => GreeterOutput::SayGoodbye(TestB {}),
+ _ => GreeterOutput::SayHello(TestA {}),
+ }
+ }
+}
+
+fn main() {
+ println!("Hello, world!");
+}
--- /dev/null
+warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/box-coerce-span-in-default.rs:3:12
+ |
+LL | #![feature(return_position_impl_trait_in_trait)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
|
LL | fn owo(x: ()) -> impl Sized;
| ^^
- = note: expected fn pointer `fn(())`
- found fn pointer `fn(u8)`
+ = note: expected signature `fn(())`
+ found signature `fn(u8)`
error[E0053]: method `owo` has an incompatible type for trait
--> $DIR/method-signature-matches.rs:20:21
|
LL | async fn owo(x: ()) {}
| ^^
- = note: expected fn pointer `fn(()) -> _`
- found fn pointer `fn(u8) -> _`
+ = note: expected signature `fn(()) -> _`
+ found signature `fn(u8) -> _`
error[E0050]: method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
--> $DIR/method-signature-matches.rs:29:28
|
LL | fn early<'early, T>(x: &'early T) -> impl Sized;
| ^^^^^^^^^
- = note: expected fn pointer `fn(&'early T)`
- found fn pointer `fn(&())`
+ = note: expected signature `fn(&'early T)`
+ found signature `fn(&())`
error: aborting due to 5 previous errors
LL | fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2`
|
- = note: expected `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + 'static`
- found `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2`
+ = note: expected signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + 'static`
+ found signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
|
LL | fn bar(&self) -> impl Sized;
| ^^^^^^^^^^
- = note: expected fn pointer `fn(&U) -> impl Sized`
- found fn pointer `fn(&U) -> U`
+ = note: expected signature `fn(&U) -> impl Sized`
+ found signature `fn(&U) -> U`
error: aborting due to previous error
impl Lint {}
pub fn gather_all() -> impl Iterator<Item = Lint> {
- //~^ ERROR type annotations needed
lint_files().flat_map(|f| gather_from_file(&f))
}
error[E0433]: failed to resolve: use of undeclared crate or module `foo`
- --> $DIR/issue-72911.rs:12:33
+ --> $DIR/issue-72911.rs:11:33
|
LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator<Item = Lint> {
| ^^^ use of undeclared crate or module `foo`
error[E0433]: failed to resolve: use of undeclared crate or module `foo`
- --> $DIR/issue-72911.rs:17:41
+ --> $DIR/issue-72911.rs:16:41
|
LL | fn lint_files() -> impl Iterator<Item = foo::MissingItem> {
| ^^^ use of undeclared crate or module `foo`
-error[E0282]: type annotations needed
- --> $DIR/issue-72911.rs:7:24
- |
-LL | pub fn gather_all() -> impl Iterator<Item = Lint> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0282, E0433.
-For more information about an error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0433`.
help: add missing generic argument
|
LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec<T>> {
- | ~~~~~~
+ | +++
error: aborting due to previous error
| expected struct `Bar`, found opaque type
| help: change the parameter type to match the trait: `&(a::Bar, i32)`
|
- = note: expected fn pointer `fn(&a::Bar, &(a::Bar, i32)) -> _`
- found fn pointer `fn(&a::Bar, &(a::Foo, i32)) -> _`
+ = note: expected signature `fn(&a::Bar, &(a::Bar, i32)) -> _`
+ found signature `fn(&a::Bar, &(a::Foo, i32)) -> _`
error: unconstrained opaque type
--> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:18:16
| expected opaque type, found struct `Bar`
| help: change the parameter type to match the trait: `&(b::Foo, i32)`
|
- = note: expected fn pointer `fn(&b::Bar, &(b::Foo, i32)) -> _`
- found fn pointer `fn(&b::Bar, &(b::Bar, i32)) -> _`
+ = note: expected signature `fn(&b::Bar, &(b::Foo, i32)) -> _`
+ found signature `fn(&b::Bar, &(b::Bar, i32)) -> _`
error: aborting due to 4 previous errors
fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
self.x.iter().map(|a| a.0)
//~^ ERROR: captures lifetime that does not appear in bounds
- //~| ERROR: captures lifetime that does not appear in bounds
}
fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
self.x.iter().map(|a| a.0)
//~^ ERROR: captures lifetime that does not appear in bounds
- //~| ERROR: captures lifetime that does not appear in bounds
}
}
| ++++
error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
- --> $DIR/static-return-lifetime-infered.rs:7:9
- |
-LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
- | ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:30]>` captures the anonymous lifetime defined here
-LL | self.x.iter().map(|a| a.0)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: to declare that `impl Iterator<Item = u32>` captures `'_`, you can add an explicit `'_` lifetime bound
- |
-LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
- | ++++
-
-error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
- --> $DIR/static-return-lifetime-infered.rs:12:9
- |
-LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
- | -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:30]>` captures the lifetime `'a` as defined here
-LL | self.x.iter().map(|a| a.0)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: to declare that `impl Iterator<Item = u32>` captures `'a`, you can add an explicit `'a` lifetime bound
- |
-LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
- | ++++
-
-error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
- --> $DIR/static-return-lifetime-infered.rs:12:9
+ --> $DIR/static-return-lifetime-infered.rs:11:9
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
- | -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:30]>` captures the lifetime `'a` as defined here
+ | -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:11:27: 11:30]>` captures the lifetime `'a` as defined here
LL | self.x.iter().map(|a| a.0)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
| ++++
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0700`.
| types differ in mutability
| help: change the parameter type to match the trait: `&mut Formatter<'_>`
|
- = note: expected fn pointer `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>`
- found fn pointer `fn(&MyType, &str)`
+ = note: expected signature `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>`
+ found signature `fn(&MyType, &str)`
error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fmt::Display::fmt` has 2
--> $DIR/trait_type.rs:12:11
// A test exploiting the bug behind #25860 except with
-// implied trait bounds which currently don't exist without `-Zchalk`.
+// implied trait bounds which currently don't exist without `-Ztrait-solver=chalk`.
use std::marker::PhantomData;
struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
where
+++ /dev/null
-pub trait TraitWAssocConst {
- const A: usize;
-}
-pub struct Demo {}
-
-impl TraitWAssocConst for impl Demo { //~ ERROR E0404
- //~^ ERROR E0562
- pubconst A: str = 32; //~ ERROR expected one of
-}
-
-fn foo<A: TraitWAssocConst<A=32>>() { //~ ERROR E0658
- foo::<Demo>()(); //~ ERROR E0271
- //~^ ERROR E0618
- //~| ERROR E0277
-}
-
-fn main<A: TraitWAssocConst<A=32>>() { //~ ERROR E0131
- //~^ ERROR E0658
- foo::<Demo>(); //~ ERROR E0277
- //~^ ERROR E0271
-}
+++ /dev/null
-error: expected one of `!` or `::`, found `A`
- --> $DIR/issue-105330.rs:8:14
- |
-LL | impl TraitWAssocConst for impl Demo {
- | - while parsing this item list starting here
-LL |
-LL | pubconst A: str = 32;
- | ^ expected one of `!` or `::`
-LL | }
- | - the item list ends here
-
-error[E0404]: expected trait, found struct `Demo`
- --> $DIR/issue-105330.rs:6:32
- |
-LL | impl TraitWAssocConst for impl Demo {
- | ^^^^ not a trait
-
-error[E0658]: associated const equality is incomplete
- --> $DIR/issue-105330.rs:11:28
- |
-LL | fn foo<A: TraitWAssocConst<A=32>>() {
- | ^^^^
- |
- = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
- = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
-
-error[E0658]: associated const equality is incomplete
- --> $DIR/issue-105330.rs:17:29
- |
-LL | fn main<A: TraitWAssocConst<A=32>>() {
- | ^^^^
- |
- = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
- = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
-
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/issue-105330.rs:6:27
- |
-LL | impl TraitWAssocConst for impl Demo {
- | ^^^^^^^^^
-
-error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
- --> $DIR/issue-105330.rs:12:11
- |
-LL | foo::<Demo>()();
- | ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
- |
-note: required by a bound in `foo`
- --> $DIR/issue-105330.rs:11:11
- |
-LL | fn foo<A: TraitWAssocConst<A=32>>() {
- | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
-
-error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
- --> $DIR/issue-105330.rs:12:11
- |
-LL | foo::<Demo>()();
- | ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
- |
- = note: expected constant `32`
- found constant `<Demo as TraitWAssocConst>::A`
-note: required by a bound in `foo`
- --> $DIR/issue-105330.rs:11:28
- |
-LL | fn foo<A: TraitWAssocConst<A=32>>() {
- | ^^^^ required by this bound in `foo`
-
-error[E0618]: expected function, found `()`
- --> $DIR/issue-105330.rs:12:5
- |
-LL | fn foo<A: TraitWAssocConst<A=32>>() {
- | ----------------------------------- `foo::<Demo>` defined here returns `()`
-LL | foo::<Demo>()();
- | ^^^^^^^^^^^^^--
- | |
- | call expression requires function
-
-error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
- --> $DIR/issue-105330.rs:19:11
- |
-LL | foo::<Demo>();
- | ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
- |
-note: required by a bound in `foo`
- --> $DIR/issue-105330.rs:11:11
- |
-LL | fn foo<A: TraitWAssocConst<A=32>>() {
- | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
-
-error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
- --> $DIR/issue-105330.rs:19:11
- |
-LL | foo::<Demo>();
- | ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
- |
- = note: expected constant `32`
- found constant `<Demo as TraitWAssocConst>::A`
-note: required by a bound in `foo`
- --> $DIR/issue-105330.rs:11:28
- |
-LL | fn foo<A: TraitWAssocConst<A=32>>() {
- | ^^^^ required by this bound in `foo`
-
-error[E0131]: `main` function is not allowed to have generic parameters
- --> $DIR/issue-105330.rs:17:8
- |
-LL | fn main<A: TraitWAssocConst<A=32>>() {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` cannot have generic parameters
-
-error: aborting due to 11 previous errors
-
-Some errors have detailed explanations: E0131, E0271, E0277, E0404, E0562, E0618, E0658.
-For more information about an error, try `rustc --explain E0131`.
+++ /dev/null
-// We only want to assert that this doesn't ICE, we don't particularly care
-// about whether it nor it fails to compile.
-
-macro_rules! foo{
- () => {{
- macro_rules! bar{() => (())}
- 1
- }}
-}
-
-pub fn main() {
- foo!();
-
- assert!({one! two()}); //~ ERROR expected one of `(`, `[`, or `{`, found `two`
-
- // regardless of whether nested macro_rules works, the following should at
- // least throw a conventional error.
- assert!({one! two}); //~ ERROR expected one of `(`, `[`, or `{`, found `two`
-}
+++ /dev/null
-error: expected one of `(`, `[`, or `{`, found `two`
- --> $DIR/issue-10536.rs:14:19
- |
-LL | assert!({one! two()});
- | ^^^ expected one of `(`, `[`, or `{`
-
-error: expected one of `(`, `[`, or `{`, found `two`
- --> $DIR/issue-10536.rs:18:19
- |
-LL | assert!({one! two});
- | ^^^ expected one of `(`, `[`, or `{`
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-// run-pass
-// ignore-emscripten no processes
-// ignore-sgx no processes
-
-// Make sure that if a process doesn't have its stdio/stderr descriptors set up
-// that we don't die in a large ball of fire
-
-use std::env;
-use std::process::{Command, Stdio};
-
-pub fn main () {
- let args: Vec<String> = env::args().collect();
- if args.len() > 1 && args[1] == "child" {
- for _ in 0..1000 {
- println!("hello?");
- }
- for _ in 0..1000 {
- println!("hello?");
- }
- return;
- }
-
- let mut p = Command::new(&args[0]);
- p.arg("child").stdout(Stdio::null()).stderr(Stdio::null());
- println!("{:?}", p.spawn().unwrap().wait());
-}
| | |
| | expected `&mut [u8]`, found struct `Vec`
| | help: consider mutably borrowing here: `&mut v`
- | arguments to this function are incorrect
+ | arguments to this method are incorrect
|
= note: expected mutable reference `&mut [u8]`
found struct `Vec<_>`
impl Foo for Baz {
fn bar(&mut self, other: &dyn Foo) {}
//~^ ERROR method `bar` has an incompatible type for trait
- //~| expected fn pointer `fn(&mut Baz, &mut dyn Foo)`
- //~| found fn pointer `fn(&mut Baz, &dyn Foo)`
+ //~| expected signature `fn(&mut Baz, &mut dyn Foo)`
+ //~| found signature `fn(&mut Baz, &dyn Foo)`
}
fn main() {}
|
LL | fn bar(&mut self, other: &mut dyn Foo);
| ^^^^^^^^^^^^
- = note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)`
- found fn pointer `fn(&mut Baz, &dyn Foo)`
+ = note: expected signature `fn(&mut Baz, &mut dyn Foo)`
+ found signature `fn(&mut Baz, &dyn Foo)`
error: aborting due to previous error
error[E0515]: cannot return value referencing local variable `rawLines`
--> $DIR/issue-13497-2.rs:3:5
|
-LL | rawLines
- | ______^
- | | _____|
- | ||
+LL | // rawLines
LL | || .iter().map(|l| l.trim()).collect()
| ||_______________-___________________________^ returns a value referencing data owned by the current function
| |_______________|
+++ /dev/null
-// run-pass
-#![feature(fn_traits, unboxed_closures)]
-use std::ops::Fn;
-
-struct Foo<T>(T);
-
-impl<T: Copy> Fn<()> for Foo<T> {
- extern "rust-call" fn call(&self, _: ()) -> T {
- match *self {
- Foo(t) => t
- }
- }
-}
-
-impl<T: Copy> FnMut<()> for Foo<T> {
- extern "rust-call" fn call_mut(&mut self, _: ()) -> T {
- self.call(())
- }
-}
-
-impl<T: Copy> FnOnce<()> for Foo<T> {
- type Output = T;
-
- extern "rust-call" fn call_once(self, _: ()) -> T {
- self.call(())
- }
-}
-
-fn main() {
- let t: u8 = 1;
- println!("{}", Foo(t)());
-}
help: add missing generic argument
|
LL | fn fn1(0: Box<T>) {}
- | ~~~~~~
+ | +++
error: aborting due to previous error
type Output = ();
fn call_once(self, _args: ()) {
//~^ ERROR `call_once` has an incompatible type for trait
- //~| expected fn pointer `extern "rust-call" fn
- //~| found fn pointer `fn
+ //~| expected signature `extern "rust-call" fn
+ //~| found signature `fn
println!("{:?}", self.x);
}
}
LL | fn call_once(self, _args: ()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected "rust-call" fn, found "Rust" fn
|
- = note: expected fn pointer `extern "rust-call" fn(Debuger<_>, ())`
- found fn pointer `fn(Debuger<_>, ())`
+ = note: expected signature `extern "rust-call" fn(Debuger<_>, ())`
+ found signature `fn(Debuger<_>, ())`
error: aborting due to previous error
error[E0277]: the trait bound `isize: HasState` is not satisfied
- --> $DIR/issue-18611.rs:1:1
+ --> $DIR/issue-18611.rs:1:18
|
-LL | / fn add_state(op: <isize as HasState>::State) {
-LL | |
-LL | | }
- | |_^ the trait `HasState` is not implemented for `isize`
+LL | fn add_state(op: <isize as HasState>::State) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize`
error: aborting due to previous error
+++ /dev/null
-// run-pass
-// Test that we are able to type-check this example. In particular,
-// knowing that `T: 'a` allows us to deduce that `[U]: 'a` (because
-// when `T=[U]` it implies that `U: 'a`).
-//
-// Regr. test for live code we found in the wild when fixing #18937.
-
-pub trait Leak<T : ?Sized> {
- fn leak<'a>(self) -> &'a T where T: 'a;
-}
-
-impl<U> Leak<[U]> for Vec<U> {
- fn leak<'a>(mut self) -> &'a [U] where [U]: 'a {
- let r: *mut [U] = &mut self[..];
- std::mem::forget(self);
- unsafe { &mut *r }
- }
-}
-fn main() {
- println!("Hello, world!");
-}
+++ /dev/null
-// Regression test for #18937.
-
-use std::fmt;
-
-#[derive(Debug)]
-struct MyString<'a>(&'a String);
-
-struct B {
- list: Vec<Box<dyn fmt::Debug>>,
-}
-
-trait A<'a> {
- fn foo<F>(&mut self, f: F)
- where F: fmt::Debug + 'a,
- Self: Sized;
-}
-
-impl<'a> A<'a> for B {
- fn foo<F>(&mut self, f: F)
- where F: fmt::Debug + 'static, //~ ERROR impl has stricter
- {
- self.list.push(Box::new(f));
- }
-}
-
-fn main() {
- let mut b = B { list: Vec::new() };
-
- // Create a borrowed pointer, put it in `b`, then drop what's borrowing it
- let a = "hello".to_string();
- b.foo(MyString(&a));
-
- // Drop the data which `b` has a reference to
- drop(a);
-
- // Use the data, probably segfaulting
- for b in b.list.iter() {
- println!("{:?}", b);
- }
-}
+++ /dev/null
-error[E0276]: impl has stricter requirements than trait
- --> $DIR/issue-18937.rs:20:31
- |
-LL | / fn foo<F>(&mut self, f: F)
-LL | | where F: fmt::Debug + 'a,
-LL | | Self: Sized;
- | |__________________________- definition of `foo` from trait
-...
-LL | where F: fmt::Debug + 'static,
- | ^^^^^^^ impl has extra requirement `F: 'static`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0276`.
| expected `&T`, found type parameter `T`
| help: change the parameter type to match the trait: `(&'a T,)`
|
- = note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))`
- found fn pointer `extern "rust-call" fn(&Foo, (T,))`
+ = note: expected signature `extern "rust-call" fn(&Foo, (&'a T,))`
+ found signature `extern "rust-call" fn(&Foo, (T,))`
error[E0053]: method `call_mut` has an incompatible type for trait
--> $DIR/issue-20225.rs:11:51
| expected `&T`, found type parameter `T`
| help: change the parameter type to match the trait: `(&'a T,)`
|
- = note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))`
- found fn pointer `extern "rust-call" fn(&mut Foo, (T,))`
+ = note: expected signature `extern "rust-call" fn(&mut Foo, (&'a T,))`
+ found signature `extern "rust-call" fn(&mut Foo, (T,))`
error[E0053]: method `call_once` has an incompatible type for trait
--> $DIR/issue-20225.rs:18:47
| expected `&T`, found type parameter `T`
| help: change the parameter type to match the trait: `(&'a T,)`
|
- = note: expected fn pointer `extern "rust-call" fn(Foo, (&'a T,))`
- found fn pointer `extern "rust-call" fn(Foo, (T,))`
+ = note: expected signature `extern "rust-call" fn(Foo, (&'a T,))`
+ found signature `extern "rust-call" fn(Foo, (T,))`
error: aborting due to 3 previous errors
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
- --> $DIR/issue-20831-debruijn.rs:28:5
+ --> $DIR/issue-20831-debruijn.rs:28:33
|
-LL | / fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
-LL | | // Not obvious, but there is an implicit lifetime here -------^
-LL | |
-LL | | //
-... |
-LL | | self.sub = t;
-LL | | }
- | |_____^
+LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> $DIR/issue-20831-debruijn.rs:28:58
LL | impl<'a> Publisher<'a> for MyStruct<'a> {
| ^^
note: ...so that the types are compatible
- --> $DIR/issue-20831-debruijn.rs:28:5
+ --> $DIR/issue-20831-debruijn.rs:28:33
|
-LL | / fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
-LL | | // Not obvious, but there is an implicit lifetime here -------^
-LL | |
-LL | | //
-... |
-LL | | self.sub = t;
-LL | | }
- | |_____^
+LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `<MyStruct<'a> as Publisher<'_>>`
found `<MyStruct<'_> as Publisher<'_>>`
| expected enum `Option`, found enum `Result`
| help: change the output type to match the trait: `Option<i32>`
|
- = note: expected fn pointer `fn(&mut S) -> Option<i32>`
- found fn pointer `fn(&mut S) -> Result<i32, i32>`
+ = note: expected signature `fn(&mut S) -> Option<i32>`
+ found signature `fn(&mut S) -> Result<i32, i32>`
error: aborting due to previous error
= help: within `(Rc<()>, Rc<()>)`, the trait `Send` is not implemented for `Rc<()>`
= note: required because it appears within the type `(Rc<()>, Rc<()>)`
= note: required for `hashbrown::raw::RawTable<(Rc<()>, Rc<()>)>` to implement `Send`
- = note: required because it appears within the type `hashbrown::map::HashMap<Rc<()>, Rc<()>, RandomState>`
+ = note: required because it appears within the type `HashMap<Rc<()>, Rc<()>, RandomState>`
= note: required because it appears within the type `HashMap<Rc<()>, Rc<()>>`
note: required by a bound in `foo`
--> $DIR/issue-21763.rs:6:11
help: add missing generic argument
|
LL | println!("{:?}",(vfnfer[0] as dyn Fn<Args>)(3));
- | ~~~~~~~~
+ | ++++++
error[E0191]: the value of the associated type `Output` (from trait `FnOnce`) must be specified
--> $DIR/issue-23024.rs:8:39
fn main() {
let item = stuff::Item::new();
println!("{}", check_ptr_exist!(item, name));
- //~^ ERROR field `name` of struct `CObj` is private
}
|
= note: this error originates in the macro `check_ptr_exist` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0616]: field `name` of struct `CObj` is private
- --> $DIR/issue-25386.rs:26:43
- |
-LL | println!("{}", check_ptr_exist!(item, name));
- | ^^^^ private field
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0616`.
--> $DIR/issue-25439.rs:8:9
|
LL | fix(|_, x| x);
- | ^^^^^^^^ cyclic type of infinite size
+ | ^^^^^^ cyclic type of infinite size
|
= note: closures cannot capture themselves or take themselves as argument;
this error may be the result of a recent compiler bug-fix,
see issue #46062 <https://github.com/rust-lang/rust/issues/46062>
for more information
+note: required by a bound in `fix`
+ --> $DIR/issue-25439.rs:3:33
+ |
+LL | fn fix<F>(f: F) -> i32 where F: Fn(Helper<F>, i32) -> i32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `fix`
error: aborting due to previous error
+++ /dev/null
-// run-pass
-struct S<T: 'static>(#[allow(unused_tuple_struct_fields)] Option<&'static T>);
-
-trait Tr { type Out; }
-impl<T> Tr for T { type Out = T; }
-
-impl<T: 'static> Copy for S<T> where S<T>: Tr<Out=T> {}
-impl<T: 'static> Clone for S<T> where S<T>: Tr<Out=T> {
- fn clone(&self) -> Self { *self }
-}
-fn main() {
- S::<()>(None);
-}
+++ /dev/null
-// run-pass
-pub trait Parser {
- type Input;
-}
-
-pub struct Iter<P: Parser>(#[allow(unused_tuple_struct_fields)] P, P::Input);
-
-#[allow(unused_tuple_struct_fields)]
-pub struct Map<P, F>(P, F);
-impl<P, F> Parser for Map<P, F> where F: FnMut(P) {
- type Input = u8;
-}
-
-trait AstId { type Untyped; }
-impl AstId for u32 { type Untyped = u32; }
-
-fn record_type<Id: AstId>(i: Id::Untyped) -> u8 {
- Iter(Map(i, |_: Id::Untyped| {}), 42).1
-}
-
-pub fn main() {
- assert_eq!(record_type::<u32>(3), 42);
-}
+++ /dev/null
-struct S<T: 'static>(#[allow(unused_tuple_struct_fields)] Option<&'static T>);
-
-trait Tr { type Out; }
-impl<T> Tr for T { type Out = T; }
-
-impl<T: 'static> Copy for S<T> where S<T>: Tr<Out=T> {}
-impl<T: 'static> Clone for S<T> where S<T>: Tr<Out=T> {
- fn clone(&self) -> Self { *self }
-}
-fn main() {
- let t = S::<()>(None);
- drop(t);
- drop(t); //~ ERROR use of moved value
-}
+++ /dev/null
-error[E0382]: use of moved value: `t`
- --> $DIR/issue-25700.rs:13:10
- |
-LL | let t = S::<()>(None);
- | - move occurs because `t` has type `S<()>`, which does not implement the `Copy` trait
-LL | drop(t);
- | - value moved here
-LL | drop(t);
- | ^ value used here after move
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0382`.
fn main() {
some_macro!(some_function);
- //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+ //~^ ERROR function takes 0 arguments but 1 argument was supplied
//~| NOTE in this expansion of some_macro!
}
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-#![allow(non_camel_case_types)]
-
-// pretty-expanded FIXME #23616
-
-trait hax {
- fn dummy(&self) { }
-}
-impl<A> hax for A { }
-
-fn perform_hax<T: 'static>(x: Box<T>) -> Box<dyn hax+'static> {
- Box::new(x) as Box<dyn hax+'static>
-}
-
-fn deadcode() {
- perform_hax(Box::new("deadcode".to_string()));
-}
-
-pub fn main() {
- let _ = perform_hax(Box::new(42));
-}
// test for https://github.com/rust-lang/rust/issues/29723
+#![feature(if_let_guard)]
+
fn main() {
let s = String::new();
let _s = match 0 {
//~^ ERROR use of moved value: `s`
}
};
+
+ let s = String::new();
+ let _s = match 0 {
+ 0 if let Some(()) = { drop(s); None } => String::from("oops"),
+ _ => s //~ ERROR use of moved value: `s`
+ };
}
error[E0382]: use of moved value: `s`
- --> $DIR/issue-29723.rs:10:13
+ --> $DIR/issue-29723.rs:12:13
|
LL | let s = String::new();
| - move occurs because `s` has type `String`, which does not implement the `Copy` trait
LL | 0 if { drop(s.clone()); false } => String::from("oops"),
| ++++++++
-error: aborting due to previous error
+error[E0382]: use of moved value: `s`
+ --> $DIR/issue-29723.rs:20:14
+ |
+LL | let s = String::new();
+ | - move occurs because `s` has type `String`, which does not implement the `Copy` trait
+LL | let _s = match 0 {
+LL | 0 if let Some(()) = { drop(s); None } => String::from("oops"),
+ | - value moved here
+LL | _ => s
+ | ^ value used here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | 0 if let Some(()) = { drop(s.clone()); None } => String::from("oops"),
+ | ++++++++
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0382`.
+++ /dev/null
-use std::vec::IntoIter;
-
-pub fn get_tok(it: &mut IntoIter<u8>) {
- let mut found_e = false;
-
- let temp: Vec<u8> = it
- .take_while(|&x| {
- found_e = true;
- false
- })
- .cloned() //~ ERROR to be an iterator that yields `&_`, but it yields `u8`
- .collect(); //~ ERROR the method
-}
-
-fn main() {}
+++ /dev/null
-error[E0271]: expected `TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>` to be an iterator that yields `&_`, but it yields `u8`
- --> $DIR/issue-31173.rs:11:10
- |
-LL | .cloned()
- | ^^^^^^ expected reference, found `u8`
- |
- = note: expected reference `&_`
- found type `u8`
-note: the method call chain might not have had the expected associated types
- --> $DIR/issue-31173.rs:3:20
- |
-LL | pub fn get_tok(it: &mut IntoIter<u8>) {
- | ^^^^^^^^^^^^^^^^^ `Iterator::Item` is `u8` here
-...
-LL | .take_while(|&x| {
- | __________-
-LL | | found_e = true;
-LL | | false
-LL | | })
- | |__________- `Iterator::Item` remains `u8` here
-note: required by a bound in `cloned`
- --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
-
-error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>>`, but its trait bounds were not satisfied
- --> $DIR/issue-31173.rs:12:10
- |
-LL | .collect();
- | ^^^^^^^ method cannot be called due to unsatisfied trait bounds
- --> $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL
- |
- = note: doesn't satisfy `<_ as Iterator>::Item = &_`
- --> $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
- |
- = note: doesn't satisfy `_: Iterator`
- |
- = note: the following trait bounds were not satisfied:
- `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]> as Iterator>::Item = &_`
- which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
- `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
- which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0271, E0599.
-For more information about an error, try `rustc --explain E0271`.
+++ /dev/null
-// run-pass
-use std::sync::atomic::{AtomicUsize, Ordering};
-
-static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
-
-struct A(i32);
-
-impl Drop for A {
- fn drop(&mut self) {
- // update global drop count
- DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
- }
-}
-
-static FOO: A = A(123);
-const BAR: A = A(456);
-
-impl A {
- const BAZ: A = A(789);
-}
-
-fn main() {
- assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 0);
- assert_eq!(&FOO.0, &123);
- assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 0);
- assert_eq!(BAR.0, 456);
- assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 1);
- assert_eq!(A::BAZ.0, 789);
- assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2);
-}
+error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied
+ --> $DIR/issue-35570.rs:8:40
+ |
+LL | fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait2<'a>` is not implemented for `()`
+
error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied
--> $DIR/issue-35570.rs:8:1
|
LL | | }
| |_^ the trait `for<'a> Trait2<'a>` is not implemented for `()`
-error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied
- --> $DIR/issue-35570.rs:8:40
- |
-LL | fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) {
- | ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait2<'a>` is not implemented for `()`
-
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable
--> $DIR/issue-36400.rs:5:7
|
-LL | let x = Box::new(3);
- | - help: consider changing this to be mutable: `mut x`
LL | f(&mut *x);
| ^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x = Box::new(3);
+ | +++
error: aborting due to previous error
LL | fn next(&'a mut self) -> Option<Self::Item>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
- = note: expected fn pointer `fn(&mut RepeatMut<'a, T>) -> Option<_>`
- found fn pointer `fn(&'a mut RepeatMut<'a, T>) -> Option<_>`
+ = note: expected signature `fn(&mut RepeatMut<'a, T>) -> Option<_>`
+ found signature `fn(&'a mut RepeatMut<'a, T>) -> Option<_>`
note: the anonymous lifetime as defined here...
--> $DIR/issue-37884.rs:6:5
|
LL | b"".starts_with(stringify!(foo))
| ----------- ^^^^^^^^^^^^^^^ expected slice `[u8]`, found `str`
| |
- | arguments to this function are incorrect
+ | arguments to this method are incorrect
|
= note: expected reference `&[u8]`
found reference `&'static str`
fn foo(a: usize) {}
//~^ defined here
fn main() { foo(5, 6) }
-//~^ ERROR this function takes 1 argument but 2 arguments were supplied
+//~^ ERROR function takes 1 argument but 2 arguments were supplied
error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
--> $DIR/issue-51515.rs:5:5
|
-LL | let foo = &16;
- | --- help: consider changing this to be a mutable reference: `&mut 16`
-...
LL | *foo = 32;
| ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let foo = &mut 16;
+ | ~~~~~~~
error[E0594]: cannot assign to `*bar`, which is behind a `&` reference
--> $DIR/issue-51515.rs:8:5
+++ /dev/null
-fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } }
-//~^ ERROR binding for associated type `Output` references lifetime `'r`
-
-fn main() {
- let f = bug();
-}
+++ /dev/null
-error[E0582]: binding for associated type `Output` references lifetime `'r`, which does not appear in the trait input types
- --> $DIR/issue-54189.rs:1:35
- |
-LL | fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } }
- | ^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0582`.
error[E0596]: cannot borrow `*x.1` as mutable, as it is behind a `&` reference
--> $DIR/issue-61623.rs:6:19
|
-LL | fn f3<'a>(x: &'a ((), &'a mut ())) {
- | -------------------- help: consider changing this to be a mutable reference: `&'a mut ((), &'a mut ())`
LL | f2(|| x.0, f1(x.1))
| ^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn f3<'a>(x: &'a mut ((), &'a mut ())) {
+ | ~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
--- /dev/null
+fn main() {}
+
+impl std::ops::AddAssign for () {
+ //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
+ fn add_assign(&self, other: ()) -> () {
+ ()
+ }
+}
+
+impl std::ops::AddAssign for [(); 1] {
+ //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
+ fn add_assign(&self, other: [(); 1]) -> [(); 1] {
+ [()]
+ }
+}
+
+impl std::ops::AddAssign for &[u8] {
+ //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
+ fn add_assign(&self, other: &[u8]) -> &[u8] {
+ self
+ }
+}
--- /dev/null
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/issue-67535.rs:3:1
+ |
+LL | impl std::ops::AddAssign for () {
+ | ^^^^^-------------------^^^^^--
+ | | | |
+ | | | this is not defined in the current crate because tuples are always foreign
+ | | this is not defined in the current crate because this is a foreign trait
+ | impl doesn't use only types from inside the current crate
+ |
+ = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/issue-67535.rs:10:1
+ |
+LL | impl std::ops::AddAssign for [(); 1] {
+ | ^^^^^-------------------^^^^^-------
+ | | | |
+ | | | this is not defined in the current crate because arrays are always foreign
+ | | this is not defined in the current crate because this is a foreign trait
+ | impl doesn't use only types from inside the current crate
+ |
+ = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/issue-67535.rs:17:1
+ |
+LL | impl std::ops::AddAssign for &[u8] {
+ | ^^^^^-------------------^^^^^-----
+ | | | |
+ | | | this is not defined in the current crate because slices are always foreign
+ | | this is not defined in the current crate because this is a foreign trait
+ | impl doesn't use only types from inside the current crate
+ |
+ = note: define and implement a trait or new type instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0117`.
+++ /dev/null
-use std::collections::BTreeSet;
-
-#[derive(Hash)]
-pub enum ElemDerived {
- //~^ ERROR recursive type `ElemDerived` has infinite size
- A(ElemDerived)
-}
-
-
-pub enum Elem {
- Derived(ElemDerived)
-}
-
-pub struct Set(BTreeSet<Elem>);
-
-impl Set {
- pub fn into_iter(self) -> impl Iterator<Item = Elem> {
- self.0.into_iter()
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0072]: recursive type `ElemDerived` has infinite size
- --> $DIR/issue-72554.rs:4:1
- |
-LL | pub enum ElemDerived {
- | ^^^^^^^^^^^^^^^^^^^^
-LL |
-LL | A(ElemDerived)
- | ----------- recursive without indirection
- |
-help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
- |
-LL | A(Box<ElemDerived>)
- | ++++ +
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0072`.
+++ /dev/null
-// run-pass
-// compile-flags: -Copt-level=0 -Cdebuginfo=2
-
-// Make sure LLVM does not miscompile this.
-
-fn indirect_get_slice() -> &'static [usize] {
- &[]
-}
-
-#[inline(always)]
-fn get_slice() -> &'static [usize] {
- let ret = indirect_get_slice();
- ret
-}
-
-fn main() {
- let output = get_slice().len();
- assert_eq!(output, 0);
-}
help: add missing generic argument
|
LL | eq::<dyn, Foo<T>>
- | ~~~~~~
+ | +++
error: aborting due to 3 previous errors; 1 warning emitted
+++ /dev/null
-struct Argument;
-struct Return;
-
-fn function(_: Argument) -> Return { todo!() }
-
-trait Trait {}
-impl Trait for fn(Argument) -> Return {}
-
-fn takes(_: impl Trait) {}
-
-fn main() {
- takes(function);
- //~^ ERROR the trait bound
- takes(|_: Argument| -> Return { todo!() });
- //~^ ERROR the trait bound
-}
+++ /dev/null
-error[E0277]: the trait bound `fn(Argument) -> Return {function}: Trait` is not satisfied
- --> $DIR/issue-99875.rs:12:11
- |
-LL | takes(function);
- | ----- ^^^^^^^^ the trait `Trait` is not implemented for fn item `fn(Argument) -> Return {function}`
- | |
- | required by a bound introduced by this call
- |
- = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
-note: required by a bound in `takes`
- --> $DIR/issue-99875.rs:9:18
- |
-LL | fn takes(_: impl Trait) {}
- | ^^^^^ required by this bound in `takes`
-
-error[E0277]: the trait bound `[closure@$DIR/issue-99875.rs:14:11: 14:34]: Trait` is not satisfied
- --> $DIR/issue-99875.rs:14:11
- |
-LL | takes(|_: Argument| -> Return { todo!() });
- | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for closure `[closure@$DIR/issue-99875.rs:14:11: 14:34]`
- | |
- | required by a bound introduced by this call
- |
- = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
-note: required by a bound in `takes`
- --> $DIR/issue-99875.rs:9:18
- |
-LL | fn takes(_: impl Trait) {}
- | ^^^^^ required by this bound in `takes`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+
+#![feature(ptr_metadata)]
+
+use std::ptr::Thin;
+
+fn main() {}
+
+fn foo<T: ?Sized + Thin>(t: *const T) -> *const () {
+ unsafe { std::mem::transmute(t) }
+}
|
LL | 999340282366920938463463374607431768211455999;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: value exceeds limit of `340282366920938463463374607431768211455`
error: aborting due to 8 previous errors
//~^ ERROR: character literal may only contain one codepoint
if x == y {}
- //~^ ERROR: can't compare `&str` with `char`
if y == z {} // no error here
if x == z {}
- //~^ ERROR: can't compare `&str` with `char`
let a: usize = "";
//~^ ERROR: mismatched types
LL | let z = "ef";
| ~~~~
-error[E0277]: can't compare `&str` with `char`
- --> $DIR/lex-bad-char-literals-6.rs:9:10
- |
-LL | if x == y {}
- | ^^ no implementation for `&str == char`
- |
- = help: the trait `PartialEq<char>` is not implemented for `&str`
- = help: the following other types implement trait `PartialEq<Rhs>`:
- <&'a str as PartialEq<OsString>>
- <&'a str as PartialEq<String>>
- <&'b str as PartialEq<Cow<'a, str>>>
- <str as PartialEq<Cow<'a, str>>>
- <str as PartialEq<OsStr>>
- <str as PartialEq<OsString>>
- <str as PartialEq<String>>
- <str as PartialEq>
-
error[E0308]: mismatched types
- --> $DIR/lex-bad-char-literals-6.rs:15:20
+ --> $DIR/lex-bad-char-literals-6.rs:13:20
|
LL | let a: usize = "";
| ----- ^^ expected `usize`, found `&str`
| |
| expected due to this
-error[E0277]: can't compare `&str` with `char`
- --> $DIR/lex-bad-char-literals-6.rs:12:10
- |
-LL | if x == z {}
- | ^^ no implementation for `&str == char`
- |
- = help: the trait `PartialEq<char>` is not implemented for `&str`
- = help: the following other types implement trait `PartialEq<Rhs>`:
- <&'a str as PartialEq<OsString>>
- <&'a str as PartialEq<String>>
- <&'b str as PartialEq<Cow<'a, str>>>
- <str as PartialEq<Cow<'a, str>>>
- <str as PartialEq<OsStr>>
- <str as PartialEq<OsString>>
- <str as PartialEq<String>>
- <str as PartialEq>
-
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0308`.
+// ignore-tidy-linelength
+
fn main() {
0o1.0; //~ ERROR: octal float literal is not supported
0o2f32; //~ ERROR: octal float literal is not supported
//~^ ERROR: integer literal is too large
9900000000000000000000000000999999999999999999999999999999;
//~^ ERROR: integer literal is too large
+ 0b111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110;
+ //~^ ERROR: integer literal is too large
+ 0o37777777777777777777777777777777777777777770;
+ //~^ ERROR: integer literal is too large
+ 0xffffffffffffffffffffffffffffffff0;
+ //~^ ERROR: integer literal is too large
0x; //~ ERROR: no valid digits
0xu32; //~ ERROR: no valid digits
0ou32; //~ ERROR: no valid digits
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:2:5
+ --> $DIR/lex-bad-numeric-literals.rs:4:5
|
LL | 0o1.0;
| ^^^^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:4:5
+ --> $DIR/lex-bad-numeric-literals.rs:6:5
|
LL | 0o3.0f32;
| ^^^^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:5:5
+ --> $DIR/lex-bad-numeric-literals.rs:7:5
|
LL | 0o4e4;
| ^^^^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:6:5
+ --> $DIR/lex-bad-numeric-literals.rs:8:5
|
LL | 0o5.0e5;
| ^^^^^^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:7:5
+ --> $DIR/lex-bad-numeric-literals.rs:9:5
|
LL | 0o6e6f32;
| ^^^^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:8:5
+ --> $DIR/lex-bad-numeric-literals.rs:10:5
|
LL | 0o7.0e7f64;
| ^^^^^^^
error: hexadecimal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:9:5
+ --> $DIR/lex-bad-numeric-literals.rs:11:5
|
LL | 0x8.0e+9;
| ^^^^^^^^
error: hexadecimal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:10:5
+ --> $DIR/lex-bad-numeric-literals.rs:12:5
|
LL | 0x9.0e-9;
| ^^^^^^^^
error[E0768]: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:11:5
+ --> $DIR/lex-bad-numeric-literals.rs:13:5
|
LL | 0o;
| ^^
error: expected at least one digit in exponent
- --> $DIR/lex-bad-numeric-literals.rs:12:5
+ --> $DIR/lex-bad-numeric-literals.rs:14:5
|
LL | 1e+;
| ^^^
error: hexadecimal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:13:5
+ --> $DIR/lex-bad-numeric-literals.rs:15:5
|
LL | 0x539.0;
| ^^^^^^^
error[E0768]: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:18:5
+ --> $DIR/lex-bad-numeric-literals.rs:26:5
|
LL | 0x;
| ^^
error[E0768]: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:19:5
+ --> $DIR/lex-bad-numeric-literals.rs:27:5
|
LL | 0xu32;
| ^^
error[E0768]: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:20:5
+ --> $DIR/lex-bad-numeric-literals.rs:28:5
|
LL | 0ou32;
| ^^
error[E0768]: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:21:5
+ --> $DIR/lex-bad-numeric-literals.rs:29:5
|
LL | 0bu32;
| ^^
error[E0768]: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:22:5
+ --> $DIR/lex-bad-numeric-literals.rs:30:5
|
LL | 0b;
| ^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:24:5
+ --> $DIR/lex-bad-numeric-literals.rs:32:5
|
LL | 0o123.456;
| ^^^^^^^^^
error: binary float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:26:5
+ --> $DIR/lex-bad-numeric-literals.rs:34:5
|
LL | 0b111.101;
| ^^^^^^^^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:3:5
+ --> $DIR/lex-bad-numeric-literals.rs:5:5
|
LL | 0o2f32;
| ^^^^^^ not supported
error: integer literal is too large
- --> $DIR/lex-bad-numeric-literals.rs:14:5
+ --> $DIR/lex-bad-numeric-literals.rs:16:5
|
LL | 9900000000000000000000000000999999999999999999999999999999;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: value exceeds limit of `340282366920938463463374607431768211455`
error: integer literal is too large
- --> $DIR/lex-bad-numeric-literals.rs:16:5
+ --> $DIR/lex-bad-numeric-literals.rs:18:5
|
LL | 9900000000000000000000000000999999999999999999999999999999;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: value exceeds limit of `340282366920938463463374607431768211455`
+
+error: integer literal is too large
+ --> $DIR/lex-bad-numeric-literals.rs:20:5
+ |
+LL | 0b111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: value exceeds limit of `0b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111`
+
+error: integer literal is too large
+ --> $DIR/lex-bad-numeric-literals.rs:22:5
+ |
+LL | 0o37777777777777777777777777777777777777777770;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: value exceeds limit of `0o3777777777777777777777777777777777777777777`
+
+error: integer literal is too large
+ --> $DIR/lex-bad-numeric-literals.rs:24:5
+ |
+LL | 0xffffffffffffffffffffffffffffffff0;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: value exceeds limit of `0xffffffffffffffffffffffffffffffff`
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:23:5
+ --> $DIR/lex-bad-numeric-literals.rs:31:5
|
LL | 0o123f64;
| ^^^^^^^^ not supported
error: binary float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:25:5
+ --> $DIR/lex-bad-numeric-literals.rs:33:5
|
LL | 0b101f64;
| ^^^^^^^^ not supported
-error: aborting due to 23 previous errors
+error: aborting due to 26 previous errors
For more information about this error, try `rustc --explain E0768`.
--- /dev/null
+// Regression test for issue #105227.
+
+// run-rustfix
+#![allow(warnings)]
+fn chars0<'a>(v :(&'a str, &'a str)) -> impl Iterator<Item = char> + 'a {
+//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a`
+ v.0.chars().chain(v.1.chars())
+ //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds
+}
+
+fn chars1<'a>(v0 : &'a str, v1 : &'a str) -> impl Iterator<Item = char> + 'a {
+//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a`
+ v0.chars().chain(v1.chars())
+ //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bound
+}
+
+fn chars2<'b>(v0 : &'b str, v1 : &'b str, v2 : &'b str) ->
+//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can use the named lifetime parameter `'b`
+ (impl Iterator<Item = char> + 'b , &'b str)
+{
+ (v0.chars().chain(v1.chars()), v2)
+ //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bound
+}
+
+fn main() {
+}
--- /dev/null
+// Regression test for issue #105227.
+
+// run-rustfix
+#![allow(warnings)]
+fn chars0(v :(& str, &str)) -> impl Iterator<Item = char> {
+//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a`
+ v.0.chars().chain(v.1.chars())
+ //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds
+}
+
+fn chars1(v0 : & str, v1 : &str) -> impl Iterator<Item = char> {
+//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a`
+ v0.chars().chain(v1.chars())
+ //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bound
+}
+
+fn chars2<'b>(v0 : &str, v1 : &'_ str, v2 : &'b str) ->
+//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can use the named lifetime parameter `'b`
+ (impl Iterator<Item = char>, &'b str)
+{
+ (v0.chars().chain(v1.chars()), v2)
+ //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bound
+}
+
+fn main() {
+}
--- /dev/null
+error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds
+ --> $DIR/issue-105227.rs:7:5
+ |
+LL | fn chars0(v :(& str, &str)) -> impl Iterator<Item = char> {
+ | ----- hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here
+LL |
+LL | v.0.chars().chain(v.1.chars())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a`
+ |
+LL | fn chars0<'a>(v :(&'a str, &'a str)) -> impl Iterator<Item = char> + 'a {
+ | ++++ ++ ++ ++++
+
+error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds
+ --> $DIR/issue-105227.rs:13:5
+ |
+LL | fn chars1(v0 : & str, v1 : &str) -> impl Iterator<Item = char> {
+ | ----- hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here
+LL |
+LL | v0.chars().chain(v1.chars())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a`
+ |
+LL | fn chars1<'a>(v0 : &'a str, v1 : &'a str) -> impl Iterator<Item = char> + 'a {
+ | ++++ ++ ++ ++++
+
+error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds
+ --> $DIR/issue-105227.rs:21:5
+ |
+LL | fn chars2<'b>(v0 : &str, v1 : &'_ str, v2 : &'b str) ->
+ | ---- hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here
+...
+LL | (v0.chars().chain(v1.chars()), v2)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: to declare that `impl Iterator<Item = char>` captures `'_`, you can use the named lifetime parameter `'b`
+ |
+LL ~ fn chars2<'b>(v0 : &'b str, v1 : &'b str, v2 : &'b str) ->
+LL |
+LL ~ (impl Iterator<Item = char> + 'b , &'b str)
+ |
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0700`.
fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
//~^ ERROR missing lifetime specifier [E0106]
//~| ERROR mismatched types
-//~| ERROR this function takes 1 argument but 0 arguments were supplied
+//~| ERROR function takes 1 argument but 0 arguments were supplied
fn parse_type_3() -> &str { unimplemented!() }
//~^ ERROR missing lifetime specifier [E0106]
error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
--> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3
|
-LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
- | - help: consider changing this to be mutable: `mut y`
LL | y.push(z);
| ^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn foo(x:fn(&u8, &u8), mut y: Vec<&u8>, z: &u8) {
+ | +++
error: aborting due to 2 previous errors
error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
--> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3
|
-LL | fn foo(x:Box<dyn Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) {
- | - help: consider changing this to be mutable: `mut y`
LL | y.push(z);
| ^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn foo(x:Box<dyn Fn(&u8, &u8)> , mut y: Vec<&u8>, z: &u8) {
+ | +++
error: aborting due to 2 previous errors
LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'1 i32) -> &'1 i32`
|
- = note: expected `fn(&'1 i32, &'a i32) -> &'a i32`
- found `fn(&'1 i32, &'1 i32) -> &'1 i32`
+ = note: expected signature `fn(&'1 i32, &'a i32) -> &'a i32`
+ found signature `fn(&'1 i32, &'1 i32) -> &'1 i32`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
help: add missing lifetime argument
|
LL | type C<'a, 'b> = <A<'a> as Trait>::Bar<'a>;
- | ~~~~~~~
+ | ++++
error: aborting due to 3 previous errors
LL | Box::from_raw(ptr);
| ^^^^^^^^^^^^^^^^^^
|
- = note: call `drop(from_raw(ptr))` if you intend to drop the `Box`
+ = note: call `drop(Box::from_raw(ptr))` if you intend to drop the `Box`
note: the lint level is defined here
--> $DIR/must-use-box-from-raw.rs:5:9
|
--- /dev/null
+// build-pass
+pub fn foo<const BAR: bool> () {}
+
+fn main() {
+ foo::<{cfg!(feature = "foo")}>();
+}
--- /dev/null
+macro_rules! number {
+ (neg false, $self:ident) => { $self };
+ ($signed:tt => $ty:ty;) => {
+ number!(neg $signed, $self);
+ //~^ ERROR no rules expected the token `$`
+ };
+}
+
+number! { false => u8; }
+
+fn main() {}
--- /dev/null
+error: no rules expected the token `$`
+ --> $DIR/best-failure.rs:4:30
+ |
+LL | macro_rules! number {
+ | ------------------- when calling this macro
+...
+LL | number!(neg $signed, $self);
+ | ^^^^^ no rules expected this token in macro call
+...
+LL | number! { false => u8; }
+ | ------------------------ in this macro invocation
+ |
+note: while trying to match meta-variable `$self:ident`
+ --> $DIR/best-failure.rs:2:17
+ |
+LL | (neg false, $self:ident) => { $self };
+ | ^^^^^^^^^^^
+ = note: this error originates in the macro `number` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
| | argument never used
| multiple missing formatting specifiers
|
- = note: printf formatting not supported; see the documentation for `std::fmt`
+ = note: printf formatting is not supported; see the documentation for `std::fmt`
help: format specifiers use curly braces
|
LL | println!("{:.2$} {}!\n", "Hello,", "World", 4);
| |
| help: format specifiers use curly braces: `{0:1$.2$}`
|
- = note: printf formatting not supported; see the documentation for `std::fmt`
+ = note: printf formatting is not supported; see the documentation for `std::fmt`
error: multiple unused formatting arguments
--> $DIR/format-foreign.rs:6:7
| |____| argument never used
| multiple missing formatting specifiers
|
- = note: printf formatting not supported; see the documentation for `std::fmt`
+ = note: printf formatting is not supported; see the documentation for `std::fmt`
help: format specifiers use curly braces
|
LL ~ println!(r###"{:.2$}
| |
| help: format specifiers use curly braces: `{NAME}`
|
- = note: shell formatting not supported; see the documentation for `std::fmt`
+ = note: shell formatting is not supported; see the documentation for `std::fmt`
error: multiple unused formatting arguments
--> $DIR/format-foreign.rs:15:32
| | argument never used
| multiple missing formatting specifiers
|
- = note: shell formatting not supported; see the documentation for `std::fmt`
+ = note: shell formatting is not supported; see the documentation for `std::fmt`
help: format specifiers use curly braces
|
LL | println!("{1} {0} $$ {NAME}", 1, 2, NAME=3);
LL | , UNUSED="args");
| ^^^^^^ named argument never used
|
- = note: shell formatting not supported; see the documentation for `std::fmt`
+ = note: shell formatting is not supported; see the documentation for `std::fmt`
error: aborting due to 4 previous errors
|
LL | concat_bytes!(888888888888888888888888888888888888888);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: value exceeds limit of `340282366920938463463374607431768211455`
error: aborting due to 2 previous errors
--- /dev/null
+// We only want to assert that this doesn't ICE, we don't particularly care
+// about whether it nor it fails to compile.
+
+macro_rules! foo{
+ () => {{
+ macro_rules! bar{() => (())}
+ 1
+ }}
+}
+
+pub fn main() {
+ foo!();
+
+ assert!({one! two()}); //~ ERROR expected one of `(`, `[`, or `{`, found `two`
+
+ // regardless of whether nested macro_rules works, the following should at
+ // least throw a conventional error.
+ assert!({one! two}); //~ ERROR expected one of `(`, `[`, or `{`, found `two`
+}
--- /dev/null
+error: expected one of `(`, `[`, or `{`, found `two`
+ --> $DIR/issue-10536.rs:14:19
+ |
+LL | assert!({one! two()});
+ | ^^^ expected one of `(`, `[`, or `{`
+
+error: expected one of `(`, `[`, or `{`, found `two`
+ --> $DIR/issue-10536.rs:18:19
+ |
+LL | assert!({one! two});
+ | ^^^ expected one of `(`, `[`, or `{`
+
+error: aborting due to 2 previous errors
+
|
LL | pub fn main() { println!("🦀%%%", 0) }
| ^^
- = note: printf formatting not supported; see the documentation for `std::fmt`
+ = note: printf formatting is not supported; see the documentation for `std::fmt`
error: aborting due to previous error
error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable
--> $DIR/span-covering-argument-1.rs:5:14
|
-LL | let $s = 0;
- | -- help: consider changing this to be mutable: `mut foo`
LL | *&mut $s = 0;
| ^^^^^^^ cannot borrow as mutable
...
| ------------------ in this macro invocation
|
= note: this error originates in the macro `bad` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider changing this to be mutable
+ |
+LL | let mut $s = 0;
+ | +++
error: aborting due to previous error
assert_eq!(stringify_ty!(*const T), "*const T");
assert_eq!(stringify_ty!(*mut T), "*mut T");
- // TyKind::Rptr
+ // TyKind::Ref
assert_eq!(stringify_ty!(&T), "&T");
assert_eq!(stringify_ty!(&mut T), "&mut T");
assert_eq!(stringify_ty!(&'a T), "&'a T");
--- /dev/null
+fn main() {
+ let _ = match Some(42) { Some(x) => x, None => "" }; //~ ERROR E0308
+}
--- /dev/null
+error[E0308]: `match` arms have incompatible types
+ --> $DIR/single-line.rs:2:52
+ |
+LL | let _ = match Some(42) { Some(x) => x, None => "" };
+ | -------------- - ^^ expected integer, found `&str`
+ | | |
+ | | this is found to be of type `{integer}`
+ | `match` arms have incompatible types
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
trait Bar {
fn f(&self) {
- self.g(); //~ ERROR the method `g` exists for reference `&Self`, but its trait bounds were not satisfied
+ // issue #105788
+ self.g(); //~ ERROR no method named `g` found for reference `&Self` in the current scope
}
}
LL | fn g(&self);
| ---^-------- help: remove these associated items
-error[E0599]: the method `g` exists for reference `&Self`, but its trait bounds were not satisfied
- --> $DIR/issue-105732.rs:9:14
+error[E0599]: no method named `g` found for reference `&Self` in the current scope
+ --> $DIR/issue-105732.rs:10:14
|
LL | self.g();
- | ^
- |
- = note: the following trait bounds were not satisfied:
- `Self: Foo`
- which is required by `&Self: Foo`
- `&Self: Foo`
- = help: items from traits can only be used if the type parameter is bounded by the trait
-help: the following trait defines an item `g`, perhaps you need to add a supertrait for it:
- |
-LL | trait Bar: Foo {
- | +++++
+ | ^ help: there is a method with a similar name: `f`
error: aborting due to 2 previous errors
LL | 1.query::<dyn ToString>("")
| --------------------- ^^ expected trait object `dyn ToString`, found `&str`
| |
- | arguments to this function are incorrect
+ | arguments to this method are incorrect
|
= note: expected trait object `dyn ToString`
found reference `&'static str`
//~^ ERROR `usize` is not an iterator
let _res: i32 = ..6.take(2).sum();
- //~^ can't call method `take` on ambiguous numeric type
- //~| ERROR mismatched types [E0308]
+ //~^ ERROR can't call method `take` on ambiguous numeric type
//~| HELP you must specify a concrete type for this numeric value
// Won't suggest because `RangeTo` dest not implemented `take`
}
LL | let _res: i32 = ..6_i32.take(2).sum();
| ~~~~~
-error[E0308]: mismatched types
- --> $DIR/issue-90315.rs:71:21
- |
-LL | let _res: i32 = ..6.take(2).sum();
- | --- ^^^^^^^^^^^^^^^^^ expected `i32`, found struct `RangeTo`
- | |
- | expected due to this
- |
- = note: expected type `i32`
- found struct `RangeTo<_>`
-
-error: aborting due to 19 previous errors
+error: aborting due to 18 previous errors
Some errors have detailed explanations: E0308, E0599, E0689.
For more information about an error, try `rustc --explain E0308`.
fn main() {
let x = Foo;
- x.zero(0) //~ ERROR this function takes 0 arguments but 1 argument was supplied
- .one() //~ ERROR this function takes 1 argument but 0 arguments were supplied
- .two(0); //~ ERROR this function takes 2 arguments but 1 argument was supplied
+ x.zero(0) //~ ERROR this method takes 0 arguments but 1 argument was supplied
+ .one() //~ ERROR this method takes 1 argument but 0 arguments were supplied
+ .two(0); //~ ERROR this method takes 2 arguments but 1 argument was supplied
let y = Foo;
y.zero()
.take() //~ ERROR not an iterator
.one(0);
- y.three::<usize>(); //~ ERROR this function takes 3 arguments but 0 arguments were supplied
+ y.three::<usize>(); //~ ERROR this method takes 3 arguments but 0 arguments were supplied
}
-error[E0061]: this function takes 0 arguments but 1 argument was supplied
+error[E0061]: this method takes 0 arguments but 1 argument was supplied
--> $DIR/method-call-err-msg.rs:13:7
|
LL | x.zero(0)
LL | x.zero()
| ~~
-error[E0061]: this function takes 1 argument but 0 arguments were supplied
+error[E0061]: this method takes 1 argument but 0 arguments were supplied
--> $DIR/method-call-err-msg.rs:14:7
|
LL | .one()
LL | .one(/* isize */)
| ~~~~~~~~~~~~~
-error[E0061]: this function takes 2 arguments but 1 argument was supplied
+error[E0061]: this method takes 2 arguments but 1 argument was supplied
--> $DIR/method-call-err-msg.rs:15:7
|
LL | .two(0);
= note: the following trait defines an item `take`, perhaps you need to implement it:
candidate #1: `Iterator`
-error[E0061]: this function takes 3 arguments but 0 arguments were supplied
+error[E0061]: this method takes 3 arguments but 0 arguments were supplied
--> $DIR/method-call-err-msg.rs:21:7
|
LL | y.three::<usize>();
|
LL | fn foo(x: u16);
| ^^^
- = note: expected fn pointer `fn(u16)`
- found fn pointer `fn(i16)`
+ = note: expected signature `fn(u16)`
+ found signature `fn(i16)`
error[E0053]: method `bar` has an incompatible type for trait
--> $DIR/E0053.rs:11:12
|
LL | fn bar(&self);
| ^^^^^
- = note: expected fn pointer `fn(&Bar)`
- found fn pointer `fn(&mut Bar)`
+ = note: expected signature `fn(&Bar)`
+ found signature `fn(&mut Bar)`
error: aborting due to 2 previous errors
--- /dev/null
+// run-rustfix
+
+struct _S(u32, Vec<i32>);
+
+fn _foo(x: &_S) {
+ match x {
+ _S(mut _y, _v) => {
+ //~^ ERROR mismatched types [E0308]
+ }
+ }
+}
+
+fn main() {
+}
--- /dev/null
+// run-rustfix
+
+struct _S(u32, Vec<i32>);
+
+fn _foo(x: &_S) {
+ match x {
+ _S(& (mut _y), _v) => {
+ //~^ ERROR mismatched types [E0308]
+ }
+ }
+}
+
+fn main() {
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-106182.rs:7:12
+ |
+LL | match x {
+ | - this expression has type `&_S`
+LL | _S(& (mut _y), _v) => {
+ | ^^^^^^^^^^ expected `u32`, found reference
+ |
+ = note: expected type `u32`
+ found reference `&_`
+help: consider removing `&` from the pattern
+ |
+LL | _S(mut _y, _v) => {
+ | ~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
|
= note: expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
|
- = note: expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
- found `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'1, T, S>>`
+ = note: expected signature `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
+ found signature `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'1, T, S>>`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
LL | fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType> + '_> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + '1)>`
|
- = note: expected `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + 'static)>`
- found `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + '1)>`
+ = note: expected signature `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + 'static)>`
+ found signature `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + '1)>`
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
--> $DIR/issue-75361-mismatched-impl.rs:12:55
|
let ans = s("what");
//~^ ERROR mismatched types
let ans = s();
- //~^ ERROR this function takes 1 argument but 0 arguments were supplied
+ //~^ ERROR function takes 1 argument but 0 arguments were supplied
let ans = s("burma", "shave");
- //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+ //~^ ERROR function takes 1 argument but 2 arguments were supplied
F("");
//~^ ERROR mismatched types
| ^^^^^^^
help: consider removing `&mut` from the pattern
|
-LL - let S(&mut _b) = S(0);
-LL + let S(_b) = S(0);
- |
+LL | let S(_b) = S(0);
+ | ~~
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:31:14
|
LL | fn foo(x: u16);
| ^^^
- = note: expected fn pointer `fn(u16)`
- found fn pointer `fn(i16)`
+ = note: expected signature `fn(u16)`
+ found signature `fn(i16)`
error[E0053]: method `bar` has an incompatible type for trait
--> $DIR/trait-impl-fn-incompatibility.rs:10:28
|
LL | fn bar(&mut self, bar: &mut Bar);
| ^^^^^^^^
- = note: expected fn pointer `fn(&mut Bar, &mut Bar)`
- found fn pointer `fn(&mut Bar, &Bar)`
+ = note: expected signature `fn(&mut Bar, &mut Bar)`
+ found signature `fn(&mut Bar, &Bar)`
error: aborting due to 2 previous errors
note: `into_iter` takes ownership of the receiver `self`, which moves `val.0`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
= note: move occurs because `val.0` has type `Vec<bool>`, which does not implement the `Copy` trait
+help: you can `clone` the value and consume it, but this might not be your desired behavior
+ |
+LL | val.0.clone().into_iter().next();
+ | ++++++++
error[E0382]: use of moved value: `foo`
--> $DIR/move-fn-self-receiver.rs:34:5
|
LL | fn use_rc_self(self: Rc<Self>) {}
| ^^^^
-help: consider cloning the value if the performance cost is acceptable
+help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | rc_foo.clone().use_rc_self();
- | ++++++++
+ | ++++++++
error[E0382]: use of moved value: `foo_add`
--> $DIR/move-fn-self-receiver.rs:59:5
LL | explicit_into_iter;
| ^^^^^^^^^^^^^^^^^^ value used here after move
|
-help: consider cloning the value if the performance cost is acceptable
+help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | for _val in explicit_into_iter.clone().into_iter() {}
- | ++++++++
+ | ++++++++
error[E0382]: use of moved value: `container`
--> $DIR/move-fn-self-receiver.rs:71:5
|
note: `into_iter` takes ownership of the receiver `self`, which moves `x`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
-help: consider cloning the value if the performance cost is acceptable
+help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | consume(x.clone().into_iter().next().unwrap());
- | ++++++++
+ | ++++++++
error: aborting due to previous error
|
note: `into_iter` takes ownership of the receiver `self`, which moves `x`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
-help: consider cloning the value if the performance cost is acceptable
+help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | let _y = x.clone().into_iter().next().unwrap();
- | ++++++++
+ | ++++++++
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-exprs.rs:83:11
|
note: `into_iter` takes ownership of the receiver `self`, which moves `x`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
-help: consider cloning the value if the performance cost is acceptable
+help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | let _y = [x.clone().into_iter().next().unwrap(); 1];
- | ++++++++
+ | ++++++++
error: aborting due to 11 previous errors
--- /dev/null
+// run-rustfix
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+ fn foo(self: Pin<&mut Self>) {}
+}
+
+fn main() {
+ let mut foo = Foo;
+ let mut foo = Pin::new(&mut foo);
+ foo.as_mut().foo();
+ foo.foo(); //~ ERROR use of moved value
+}
--- /dev/null
+// run-rustfix
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+ fn foo(self: Pin<&mut Self>) {}
+}
+
+fn main() {
+ let mut foo = Foo;
+ let mut foo = Pin::new(&mut foo);
+ foo.foo();
+ foo.foo(); //~ ERROR use of moved value
+}
--- /dev/null
+error[E0382]: use of moved value: `foo`
+ --> $DIR/pin-mut-reborrow.rs:14:5
+ |
+LL | let mut foo = Pin::new(&mut foo);
+ | ------- move occurs because `foo` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
+LL | foo.foo();
+ | ----- `foo` moved due to this method call
+LL | foo.foo();
+ | ^^^ value used here after move
+ |
+note: `Foo::foo` takes ownership of the receiver `self`, which moves `foo`
+ --> $DIR/pin-mut-reborrow.rs:7:12
+ |
+LL | fn foo(self: Pin<&mut Self>) {}
+ | ^^^^
+help: consider reborrowing the `Pin` instead of moving it
+ |
+LL | foo.as_mut().foo();
+ | +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+// run-rustfix
+
+#[derive(Clone)]
+struct Foo;
+impl Foo {
+ fn foo(self) {}
+}
+fn main() {
+ let foo = &Foo;
+ foo.clone().foo(); //~ ERROR cannot move out
+}
--- /dev/null
+// run-rustfix
+
+#[derive(Clone)]
+struct Foo;
+impl Foo {
+ fn foo(self) {}
+}
+fn main() {
+ let foo = &Foo;
+ foo.foo(); //~ ERROR cannot move out
+}
--- /dev/null
+error[E0507]: cannot move out of `*foo` which is behind a shared reference
+ --> $DIR/suggest-clone.rs:10:5
+ |
+LL | foo.foo();
+ | ^^^^-----
+ | | |
+ | | `*foo` moved due to this method call
+ | move occurs because `*foo` has type `Foo`, which does not implement the `Copy` trait
+ |
+note: `Foo::foo` takes ownership of the receiver `self`, which moves `*foo`
+ --> $DIR/suggest-clone.rs:6:12
+ |
+LL | fn foo(self) {}
+ | ^^^^
+help: you can `clone` the value and consume it, but this might not be your desired behavior
+ |
+LL | foo.clone().foo();
+ | ++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
fn func(arg: S) {
//~^ HELP consider changing this to be mutable
- //~| SUGGESTION mut arg
+ //~| SUGGESTION mut
arg.mutate();
//~^ ERROR cannot borrow `arg` as mutable, as it is not declared as mutable
}
fn main() {
let local = S;
//~^ HELP consider changing this to be mutable
- //~| SUGGESTION mut local
+ //~| SUGGESTION mut
local.mutate();
//~^ ERROR cannot borrow `local` as mutable, as it is not declared as mutable
}
error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
--> $DIR/mut-suggestion.rs:12:5
|
-LL | fn func(arg: S) {
- | --- help: consider changing this to be mutable: `mut arg`
-...
LL | arg.mutate();
| ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn func(mut arg: S) {
+ | +++
error[E0596]: cannot borrow `local` as mutable, as it is not declared as mutable
--> $DIR/mut-suggestion.rs:20:5
|
-LL | let local = S;
- | ----- help: consider changing this to be mutable: `mut local`
-...
LL | local.mutate();
| ^^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut local = S;
+ | +++
error: aborting due to 2 previous errors
error[E0594]: cannot assign to `self.how_hungry`, which is behind a `&` reference
--> $DIR/mutable-class-fields-2.rs:9:5
|
-LL | pub fn eat(&self) {
- | ----- help: consider changing this to be a mutable reference: `&mut self`
LL | self.how_hungry -= 5;
| ^^^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | pub fn eat(&mut self) {
+ | ~~~~~~~~~
error: aborting due to previous error
error[E0594]: cannot assign to `nyan.how_hungry`, as `nyan` is not declared as mutable
--> $DIR/mutable-class-fields.rs:15:3
|
-LL | let nyan : Cat = cat(52, 99);
- | ---- help: consider changing this to be mutable: `mut nyan`
LL | nyan.how_hungry = 0;
| ^^^^^^^^^^^^^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut nyan : Cat = cat(52, 99);
+ | +++
error: aborting due to previous error
fn main() {
let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
- //~^ ERROR lifetime may not live long enough
- //~| ERROR higher-ranked subtype error
- //~| ERROR higher-ranked subtype error
- //~| ERROR implementation of `Trait` is not general enough
- //~| ERROR implementation of `Trait` is not general enough
- //~| ERROR implementation of `Trait` is not general enough
- //~| ERROR implementation of `Trait` is not general enough
- //~| ERROR implementation of `Trait` is not general enough
- //~| ERROR implementation of `Trait` is not general enough
- //~| ERROR implementation of `Trait` is not general enough
- //~| ERROR implementation of `Trait` is not general enough
+ //~^ ERROR implementation of `Trait` is not general enough
//~| ERROR implementation of `Trait` is not general enough
}
-error: lifetime may not live long enough
- --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
- |
-LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
- | ^-^
- | ||
- | |has type `<&'1 () as Trait>::Ty`
- | requires that `'1` must outlive `'static`
-
-error: higher-ranked subtype error
- --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
- |
-LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
- | ^^^
-
-error: higher-ranked subtype error
- --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
- |
-LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
- | ^^^
-
-error: implementation of `Trait` is not general enough
- --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
- |
-LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
- | ^^^^^^ implementation of `Trait` is not general enough
- |
- = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
- = note: ...but `Trait` is actually implemented for the type `&'static ()`
-
-error: implementation of `Trait` is not general enough
- --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12
- |
-LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
- |
- = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
- = note: ...but `Trait` is actually implemented for the type `&'static ()`
-
-error: implementation of `Trait` is not general enough
- --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12
- |
-LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
- |
- = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
- = note: ...but `Trait` is actually implemented for the type `&'static ()`
-
error: implementation of `Trait` is not general enough
--> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12
|
= note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
= note: ...but `Trait` is actually implemented for the type `&'static ()`
-error: implementation of `Trait` is not general enough
- --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
- |
-LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
- | ^^^^^^ implementation of `Trait` is not general enough
- |
- = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
- = note: ...but `Trait` is actually implemented for the type `&'static ()`
-
-error: implementation of `Trait` is not general enough
- --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
- |
-LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
- | ^^^^^^ implementation of `Trait` is not general enough
- |
- = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
- = note: ...but `Trait` is actually implemented for the type `&'static ()`
-
-error: implementation of `Trait` is not general enough
- --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
- |
-LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
- | ^^^^^^ implementation of `Trait` is not general enough
- |
- = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
- = note: ...but `Trait` is actually implemented for the type `&'static ()`
-
-error: implementation of `Trait` is not general enough
- --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
- |
-LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
- | ^^^^^^ implementation of `Trait` is not general enough
- |
- = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
- = note: ...but `Trait` is actually implemented for the type `&'static ()`
-
-error: aborting due to 12 previous errors
+error: aborting due to 2 previous errors
// See further discussion on rust-lang/rust#24535,
// rust-lang/rfcs#1006, and rust-lang/rfcs#107
+#![feature(if_let_guard)]
+
fn main() {
rust_issue_24535();
rfcs_issue_1006_1();
3 if compare(&a, &mut 3) => (),
_ => panic!("nope"),
}
+
+ match a {
+ 0 => panic!("nope"),
+ 3 if let true = compare(&a, &mut 3) => (),
+ _ => panic!("nope"),
+ }
}
fn rfcs_issue_1006_1() {
// reaches the panic code when executed, despite the compiler warning
// about that match arm being unreachable.
+#![feature(if_let_guard)]
+
fn main() {
let b = &mut true;
match b {
&mut true => { println!("You might think we should get here"); },
_ => panic!("surely we could never get here, since rustc warns it is unreachable."),
}
+
+ let b = &mut true;
+ match b {
+ //~^ ERROR use of moved value: `b` [E0382]
+ &mut false => {}
+ _ if let Some(()) = {
+ (|| { let bar = b; *bar = false; })();
+ None
+ } => {}
+ &mut true => {}
+ _ => {}
+ }
}
error[E0382]: use of moved value: `b`
- --> $DIR/issue-27282-move-match-input-into-guard.rs:12:5
+ --> $DIR/issue-27282-move-match-input-into-guard.rs:14:5
|
LL | let b = &mut true;
| - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
| |
| value moved into closure here
-error: aborting due to previous error
+error[E0382]: use of moved value: `b`
+ --> $DIR/issue-27282-move-match-input-into-guard.rs:24:5
+ |
+LL | let b = &mut true;
+ | - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
+LL | match b {
+ | ^^^^^^^ value used here after move
+...
+LL | (|| { let bar = b; *bar = false; })();
+ | -- - variable moved due to use in closure
+ | |
+ | value moved into closure here
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0382`.
// mutable borrows in match guards by hiding the mutable borrow in a
// guard behind a move (of the ref mut pattern id) within a closure.
+#![feature(if_let_guard)]
+
fn main() {
match Some(&4) {
None => {},
//~^ ERROR cannot move out of `foo` in pattern guard [E0507]
Some(s) => std::process::exit(*s),
}
+
+ match Some(&4) {
+ None => {},
+ ref mut foo
+ if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+ //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+ Some(s) => std::process::exit(*s),
+ }
}
error[E0507]: cannot move out of `foo` in pattern guard
- --> $DIR/issue-27282-move-ref-mut-into-guard.rs:9:19
+ --> $DIR/issue-27282-move-ref-mut-into-guard.rs:11:19
|
LL | if { (|| { let bar = foo; bar.take() })(); false } => {},
| ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+ --> $DIR/issue-27282-move-ref-mut-into-guard.rs:19:34
+ |
+LL | if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
+ | move out of `foo` occurs here
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0507`.
+#![feature(if_let_guard)]
+
fn main() {
match Some(&4) {
None => {},
Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."),
_ => println!("Here is some supposedly unreachable code."),
}
+
+ match Some(&4) {
+ None => {},
+ ref mut foo
+ if let Some(()) = {
+ (|| { let bar = foo; bar.take() })();
+ //~^ ERROR cannot move out of `foo` in pattern guard
+ None
+ } => {},
+ Some(_) => {},
+ }
}
error[E0507]: cannot move out of `foo` in pattern guard
- --> $DIR/issue-27282-mutation-in-guard.rs:6:18
+ --> $DIR/issue-27282-mutation-in-guard.rs:8:18
|
LL | (|| { let bar = foo; bar.take() })();
| ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+ --> $DIR/issue-27282-mutation-in-guard.rs:20:18
+ |
+LL | (|| { let bar = foo; bar.take() })();
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
+ | move out of `foo` occurs here
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0507`.
// It reborrows instead of moving the `ref mut` pattern borrow. This
// means that our conservative check for mutation in guards will
// reject it. But I want to make sure that we continue to reject it
-// (under NLL) even when that conservaive check goes away.
+// (under NLL) even when that conservative check goes away.
+
+#![feature(if_let_guard)]
fn main() {
let mut b = &mut true;
&mut true => { println!("You might think we should get here"); },
_ => panic!("surely we could never get here, since rustc warns it is unreachable."),
}
+
+ let mut b = &mut true;
+ match b {
+ &mut false => {},
+ ref mut r if let Some(()) = { (|| { let bar = &mut *r; **bar = false; })();
+ //~^ ERROR cannot borrow `r` as mutable, as it is immutable for the pattern guard
+ None } => { &mut *r; },
+ &mut true => {},
+ _ => {},
+ }
}
error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
- --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:12:25
+ --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:14:25
|
LL | ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
| ^^ -- mutable borrow occurs due to use of `r` in closure
|
= note: variables bound in patterns are immutable until the end of the pattern guard
-error: aborting due to previous error
+error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
+ --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:24:40
+ |
+LL | ref mut r if let Some(()) = { (|| { let bar = &mut *r; **bar = false; })();
+ | ^^ -- mutable borrow occurs due to use of `r` in closure
+ | |
+ | cannot borrow as mutable
+ |
+ = note: variables bound in patterns are immutable until the end of the pattern guard
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0596`.
error[E0594]: cannot assign to `fancy_ref.num`, which is behind a `&` reference
--> $DIR/issue-47388.rs:8:5
|
-LL | let fancy_ref = &(&mut fancy);
- | ------------- help: consider changing this to be a mutable reference: `&mut (&mut fancy)`
LL | fancy_ref.num = 6;
| ^^^^^^^^^^^^^^^^^ `fancy_ref` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let fancy_ref = &mut (&mut fancy);
+ | ~~~~~~~~~~~~~~~~~
error: aborting due to previous error
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
--> $DIR/issue-51191.rs:13:9
|
-LL | fn imm(self) {
- | ---- help: consider changing this to be mutable: `mut self`
LL | (&mut self).bar();
| ^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn imm(mut self) {
+ | +++
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
--> $DIR/issue-51191.rs:22:9
error[E0594]: cannot assign to `*my_ref`, which is behind a `&` reference
--> $DIR/issue-51244.rs:3:5
|
-LL | let ref my_ref @ _ = 0;
- | ---------- help: consider changing this to be a mutable reference: `ref mut my_ref`
LL | *my_ref = 0;
| ^^^^^^^^^^^ `my_ref` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let ref mut my_ref @ _ = 0;
+ | ~~~~~~~~~~~~~~
error: aborting due to previous error
--- /dev/null
+fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } }
+//~^ ERROR binding for associated type `Output` references lifetime `'r`
+
+fn main() {
+ let f = bug();
+}
--- /dev/null
+error[E0582]: binding for associated type `Output` references lifetime `'r`, which does not appear in the trait input types
+ --> $DIR/issue-54189.rs:1:35
+ |
+LL | fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } }
+ | ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0582`.
error[E0594]: cannot assign to `*x`, which is behind a `&` reference
--> $DIR/issue-57989.rs:5:5
|
-LL | fn f(x: &i32) {
- | ---- help: consider changing this to be a mutable reference: `&mut i32`
-LL | let g = &x;
LL | *x = 0;
| ^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn f(x: &mut i32) {
+ | ~~~~~~~~
error[E0506]: cannot assign to `*x` because it is borrowed
--> $DIR/issue-57989.rs:5:5
// Test that we have enough false edges to avoid exposing the exact matching
// algorithm in borrow checking.
+#![feature(if_let_guard)]
+
fn guard_always_precedes_arm(y: i32) {
let mut x;
// x should always be initialized, as the only way to reach the arm is
0 | 2 if { x = 2; true } => x,
_ => 2,
};
+
+ let mut x;
+ match y {
+ 0 | 2 if let Some(()) = { x = 2; Some(()) } => x,
+ _ => 2,
+ };
}
fn guard_may_be_skipped(y: i32) {
} => 2,
_ => 3,
};
+
+ let x;
+ match y {
+ _ if let Some(()) = { x = 2; Some(()) } => 1,
+ _ if let Some(()) = {
+ x; //~ ERROR E0381
+ None
+ } => 2,
+ _ => 3,
+ };
}
fn guard_may_be_taken(y: bool) {
}
false => 3,
};
+
+ let x = String::new();
+ match y {
+ false if let Some(()) = { drop(x); Some(()) } => 1,
+ true => {
+ x; //~ ERROR use of moved value: `x`
+ 2
+ }
+ false => 3,
+ };
}
fn main() {}
error[E0381]: used binding `x` isn't initialized
- --> $DIR/match-cfg-fake-edges.rs:21:13
+ --> $DIR/match-cfg-fake-edges.rs:29:13
|
LL | let x;
| - binding declared here but left uninitialized
LL | let x = 0;
| +++
+error[E0381]: used binding `x` isn't initialized
+ --> $DIR/match-cfg-fake-edges.rs:39:13
+ |
+LL | let x;
+ | - binding declared here but left uninitialized
+LL | match y {
+LL | _ if let Some(()) = { x = 2; Some(()) } => 1,
+ | ----- binding initialized here in some conditions
+LL | _ if let Some(()) = {
+LL | x;
+ | ^ `x` used here but it isn't initialized
+ |
+help: consider assigning a value
+ |
+LL | let x = 0;
+ | +++
+
error[E0382]: use of moved value: `x`
- --> $DIR/match-cfg-fake-edges.rs:35:13
+ --> $DIR/match-cfg-fake-edges.rs:53:13
|
LL | let x = String::new();
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
LL | false if { drop(x.clone()); true } => 1,
| ++++++++
-error: aborting due to 2 previous errors
+error[E0382]: use of moved value: `x`
+ --> $DIR/match-cfg-fake-edges.rs:63:13
+ |
+LL | let x = String::new();
+ | - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+LL | match y {
+LL | false if let Some(()) = { drop(x); Some(()) } => 1,
+ | - value moved here
+LL | true => {
+LL | x;
+ | ^ value used here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | false if let Some(()) = { drop(x.clone()); Some(()) } => 1,
+ | ++++++++
+
+error: aborting due to 4 previous errors
Some errors have detailed explanations: E0381, E0382.
For more information about an error, try `rustc --explain E0381`.
+#![feature(if_let_guard)]
+
// Here is arielb1's basic example from rust-lang/rust#27282
// that AST borrowck is flummoxed by:
false } => { },
Some(s) => std::process::exit(*s),
}
+
+ match Some(&4) {
+ None => {},
+ ref mut foo if let Some(()) = {
+ (|| { let bar = foo; bar.take() })();
+ //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+ None } => { },
+ Some(s) => std::process::exit(*s),
+ }
}
// Here below is a case that needs to keep working: we only use the
fn allow_mutate_in_arm_body() {
match Some(&4) {
None => {},
- ref mut foo if foo.is_some() && false => { foo.take(); () }
+ ref mut foo if foo.is_some() => { foo.take(); () }
+ Some(s) => std::process::exit(*s),
+ }
+
+ match Some(&4) {
+ None => {},
+ ref mut foo if let Some(_) = foo => { foo.take(); () }
Some(s) => std::process::exit(*s),
}
}
fn allow_move_into_arm_body() {
match Some(&4) {
None => {},
- mut foo if foo.is_some() && false => { foo.take(); () }
+ mut foo if foo.is_some() => { foo.unwrap(); () }
+ Some(s) => std::process::exit(*s),
+ }
+
+ match Some(&4) {
+ None => {},
+ mut foo if let Some(_) = foo => { foo.unwrap(); () }
Some(s) => std::process::exit(*s),
}
}
error[E0507]: cannot move out of `foo` in pattern guard
- --> $DIR/match-guards-always-borrow.rs:8:14
+ --> $DIR/match-guards-always-borrow.rs:10:14
|
LL | (|| { let bar = foo; bar.take() })();
| ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+ --> $DIR/match-guards-always-borrow.rs:19:14
+ |
+LL | (|| { let bar = foo; bar.take() })();
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
+ | move out of `foo` occurs here
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0507`.
// Test that we don't allow mutating the value being matched on in a way that
// changes which patterns it matches, until we have chosen an arm.
-fn ok_mutation_in_guard(mut q: i32) {
+#![feature(if_let_guard)]
+
+fn ok_mutation_in_if_guard(mut q: i32) {
match q {
// OK, mutation doesn't change which patterns g matches
_ if { q = 1; false } => (),
}
}
-fn ok_mutation_in_guard2(mut u: bool) {
+fn ok_mutation_in_if_let_guard(mut q: i32) {
+ match q {
+ // OK, mutation doesn't change which patterns g matches
+ _ if let Some(()) = { q = 1; None } => (),
+ _ => (),
+ }
+}
+
+fn ok_mutation_in_if_guard2(mut u: bool) {
// OK value of u is unused before modification
match u {
_ => (),
}
}
-fn ok_mutation_in_guard4(mut w: (&mut bool,)) {
+fn ok_mutation_in_if_let_guard2(mut u: bool) {
+ // OK value of u is unused before modification
+ match u {
+ _ => (),
+ _ if let Some(()) = {
+ u = true;
+ None
+ } => (),
+ x => (),
+ }
+}
+
+fn ok_mutation_in_if_guard4(mut w: (&mut bool,)) {
// OK value of u is unused before modification
match w {
_ => (),
}
}
-fn ok_indirect_mutation_in_guard(mut p: &bool) {
+fn ok_mutation_in_if_let_guard4(mut w: (&mut bool,)) {
+ // OK value of u is unused before modification
+ match w {
+ _ => (),
+ _ if let Some(()) = {
+ *w.0 = true;
+ None
+ } => (),
+ x => (),
+ }
+}
+
+fn ok_indirect_mutation_in_if_guard(mut p: &bool) {
match *p {
// OK, mutation doesn't change which patterns s matches
_ if {
}
}
-fn mutation_invalidates_pattern_in_guard(mut q: bool) {
+fn ok_indirect_mutation_in_if_let_guard(mut p: &bool) {
+ match *p {
+ // OK, mutation doesn't change which patterns s matches
+ _ if let Some(()) = {
+ p = &true;
+ None
+ } => (),
+ _ => (),
+ }
+}
+
+fn mutation_invalidates_pattern_in_if_guard(mut q: bool) {
match q {
// q doesn't match the pattern with the guard by the end of the guard.
false if {
}
}
-fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
+fn mutation_invalidates_pattern_in_if_let_guard(mut q: bool) {
+ match q {
+ // q doesn't match the pattern with the guard by the end of the guard.
+ false if let Some(()) = {
+ q = true; //~ ERROR
+ Some(())
+ } => (),
+ _ => (),
+ }
+}
+
+fn mutation_invalidates_previous_pattern_in_if_guard(mut r: bool) {
match r {
// r matches a previous pattern by the end of the guard.
true => (),
}
}
-fn match_on_borrowed_early_end(mut s: bool) {
+fn mutation_invalidates_previous_pattern_in_if_let_guard(mut r: bool) {
+ match r {
+ // r matches a previous pattern by the end of the guard.
+ true => (),
+ _ if let Some(()) = {
+ r = true; //~ ERROR
+ Some(())
+ } => (),
+ _ => (),
+ }
+}
+
+fn match_on_borrowed_early_end_if_guard(mut s: bool) {
let h = &mut s;
// OK value of s is unused before modification.
match s {
}
}
-fn bad_mutation_in_guard(mut t: bool) {
+fn match_on_borrowed_early_end_if_let_guard(mut s: bool) {
+ let h = &mut s;
+ // OK value of s is unused before modification.
+ match s {
+ _ if let Some(()) = {
+ *h = !*h;
+ None
+ } => (),
+ true => (),
+ false => (),
+ }
+}
+
+fn bad_mutation_in_if_guard(mut t: bool) {
match t {
true => (),
false if {
}
}
-fn bad_mutation_in_guard2(mut x: Option<Option<&i32>>) {
+fn bad_mutation_in_if_let_guard(mut t: bool) {
+ match t {
+ true => (),
+ false if let Some(()) = {
+ t = true; //~ ERROR
+ None
+ } => (),
+ false => (),
+ }
+}
+
+fn bad_mutation_in_if_guard2(mut x: Option<Option<&i32>>) {
// Check that nested patterns are checked.
match x {
None => (),
}
}
-fn bad_mutation_in_guard3(mut t: bool) {
+fn bad_mutation_in_if_let_guard2(mut x: Option<Option<&i32>>) {
+ // Check that nested patterns are checked.
+ match x {
+ None => (),
+ Some(None) => (),
+ _ if let Some(()) = {
+ match x {
+ Some(ref mut r) => *r = None, //~ ERROR
+ _ => return,
+ };
+ None
+ } => (),
+ Some(Some(r)) => println!("{}", r),
+ }
+}
+
+fn bad_mutation_in_if_guard3(mut t: bool) {
match t {
s if {
t = !t; //~ ERROR
}
}
-fn bad_indirect_mutation_in_guard(mut y: &bool) {
+fn bad_mutation_in_if_let_guard3(mut t: bool) {
+ match t {
+ s if let Some(()) = {
+ t = !t; //~ ERROR
+ None
+ } => (), // What value should `s` have in the arm?
+ _ => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_guard(mut y: &bool) {
match *y {
true => (),
false if {
}
}
-fn bad_indirect_mutation_in_guard2(mut z: &bool) {
+fn bad_indirect_mutation_in_if_let_guard(mut y: &bool) {
+ match *y {
+ true => (),
+ false if let Some(()) = {
+ y = &true; //~ ERROR
+ None
+ } => (),
+ false => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_guard2(mut z: &bool) {
match z {
&true => (),
&false if {
}
}
-fn bad_indirect_mutation_in_guard3(mut a: &bool) {
- // Same as bad_indirect_mutation_in_guard2, but using match ergonomics
+fn bad_indirect_mutation_in_if_let_guard2(mut z: &bool) {
+ match z {
+ &true => (),
+ &false if let Some(()) = {
+ z = &true; //~ ERROR
+ None
+ } => (),
+ &false => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_guard3(mut a: &bool) {
+ // Same as bad_indirect_mutation_in_if_guard2, but using match ergonomics
match a {
true => (),
false if {
}
}
-fn bad_indirect_mutation_in_guard4(mut b: &bool) {
+fn bad_indirect_mutation_in_if_let_guard3(mut a: &bool) {
+ // Same as bad_indirect_mutation_in_if_guard2, but using match ergonomics
+ match a {
+ true => (),
+ false if let Some(()) = {
+ a = &true; //~ ERROR
+ None
+ } => (),
+ false => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_guard4(mut b: &bool) {
match b {
&_ => (),
&_ if {
}
}
+fn bad_indirect_mutation_in_if_let_guard4(mut b: &bool) {
+ match b {
+ &_ => (),
+ &_ if let Some(()) = {
+ b = &true; //~ ERROR
+ None
+ } => (),
+ &b => (),
+ }
+}
+
fn main() {}
error[E0510]: cannot assign `q` in match guard
- --> $DIR/match-guards-partially-borrow.rs:55:13
+ --> $DIR/match-guards-partially-borrow.rs:100:13
|
LL | match q {
| - value is immutable in match guard
LL | q = true;
| ^^^^^^^^ cannot assign
+error[E0510]: cannot assign `q` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:111:13
+ |
+LL | match q {
+ | - value is immutable in match guard
+...
+LL | q = true;
+ | ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `r` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:123:13
+ |
+LL | match r {
+ | - value is immutable in match guard
+...
+LL | r = true;
+ | ^^^^^^^^ cannot assign
+
error[E0510]: cannot assign `r` in match guard
- --> $DIR/match-guards-partially-borrow.rs:67:13
+ --> $DIR/match-guards-partially-borrow.rs:135:13
|
LL | match r {
| - value is immutable in match guard
| ^^^^^^^^ cannot assign
error[E0510]: cannot assign `t` in match guard
- --> $DIR/match-guards-partially-borrow.rs:91:13
+ --> $DIR/match-guards-partially-borrow.rs:172:13
+ |
+LL | match t {
+ | - value is immutable in match guard
+...
+LL | t = true;
+ | ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `t` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:183:13
|
LL | match t {
| - value is immutable in match guard
| ^^^^^^^^ cannot assign
error[E0510]: cannot mutably borrow `x.0` in match guard
- --> $DIR/match-guards-partially-borrow.rs:105:22
+ --> $DIR/match-guards-partially-borrow.rs:197:22
+ |
+LL | match x {
+ | - value is immutable in match guard
+...
+LL | Some(ref mut r) => *r = None,
+ | ^^^^^^^^^ cannot mutably borrow
+
+error[E0510]: cannot mutably borrow `x.0` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:213:22
|
LL | match x {
| - value is immutable in match guard
| ^^^^^^^^^ cannot mutably borrow
error[E0506]: cannot assign to `t` because it is borrowed
- --> $DIR/match-guards-partially-borrow.rs:117:13
+ --> $DIR/match-guards-partially-borrow.rs:225:13
|
LL | s if {
| - borrow of `t` occurs here
LL | } => (), // What value should `s` have in the arm?
| - borrow later used here
+error[E0506]: cannot assign to `t` because it is borrowed
+ --> $DIR/match-guards-partially-borrow.rs:235:13
+ |
+LL | s if let Some(()) = {
+ | - borrow of `t` occurs here
+LL | t = !t;
+ | ^^^^^^ assignment to borrowed `t` occurs here
+LL | None
+LL | } => (), // What value should `s` have in the arm?
+ | - borrow later used here
+
+error[E0510]: cannot assign `y` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:246:13
+ |
+LL | match *y {
+ | -- value is immutable in match guard
+...
+LL | y = &true;
+ | ^^^^^^^^^ cannot assign
+
error[E0510]: cannot assign `y` in match guard
- --> $DIR/match-guards-partially-borrow.rs:128:13
+ --> $DIR/match-guards-partially-borrow.rs:257:13
|
LL | match *y {
| -- value is immutable in match guard
| ^^^^^^^^^ cannot assign
error[E0510]: cannot assign `z` in match guard
- --> $DIR/match-guards-partially-borrow.rs:139:13
+ --> $DIR/match-guards-partially-borrow.rs:268:13
+ |
+LL | match z {
+ | - value is immutable in match guard
+...
+LL | z = &true;
+ | ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `z` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:279:13
|
LL | match z {
| - value is immutable in match guard
| ^^^^^^^^^ cannot assign
error[E0510]: cannot assign `a` in match guard
- --> $DIR/match-guards-partially-borrow.rs:151:13
+ --> $DIR/match-guards-partially-borrow.rs:291:13
+ |
+LL | match a {
+ | - value is immutable in match guard
+...
+LL | a = &true;
+ | ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `a` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:303:13
|
LL | match a {
| - value is immutable in match guard
| ^^^^^^^^^ cannot assign
error[E0510]: cannot assign `b` in match guard
- --> $DIR/match-guards-partially-borrow.rs:162:13
+ --> $DIR/match-guards-partially-borrow.rs:314:13
+ |
+LL | match b {
+ | - value is immutable in match guard
+...
+LL | b = &true;
+ | ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `b` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:325:13
|
LL | match b {
| - value is immutable in match guard
LL | b = &true;
| ^^^^^^^^^ cannot assign
-error: aborting due to 9 previous errors
+error: aborting due to 18 previous errors
Some errors have detailed explanations: E0506, E0510.
For more information about an error, try `rustc --explain E0506`.
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'d` due to conflicting requirements
- --> $DIR/normalization-bounds-error.rs:12:1
+ --> $DIR/normalization-bounds-error.rs:12:31
|
LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'d` as defined here...
--> $DIR/normalization-bounds-error.rs:12:14
LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
| ^^
note: ...so that the types are compatible
- --> $DIR/normalization-bounds-error.rs:12:1
+ --> $DIR/normalization-bounds-error.rs:12:31
|
LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `Visitor<'d>`
found `Visitor<'_>`
| -- lifetime `'a` defined here
LL | return;
LL | let x: &'static &'a ();
- | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+ | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/wf-unreachable.rs:11:12
| -- lifetime `'a` defined here
LL | return;
LL | let x: &'static &'a () = &&();
- | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+ | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/wf-unreachable.rs:15:12
LL | fn uninit_infer<'a>() {
| -- lifetime `'a` defined here
LL | let x: &'static &'a _;
- | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+ | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/wf-unreachable.rs:21:12
| -- lifetime `'a` defined here
LL | return;
LL | let x: &'static &'a _ = &&();
- | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+ | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/wf-unreachable.rs:26:12
| -- lifetime `'a` defined here
LL | return;
LL | let _: &'static &'a ();
- | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+ | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/wf-unreachable.rs:31:12
| -- lifetime `'a` defined here
LL | return;
LL | let _: &'static &'a () = &&();
- | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+ | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/wf-unreachable.rs:36:12
| -- lifetime `'a` defined here
LL | return;
LL | let _: &'static &'a _ = &&();
- | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+ | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
error: lifetime may not live long enough
--> $DIR/wf-unreachable.rs:49:12
| -- lifetime `'a` defined here
LL | return;
LL | let _: C<'static, 'a, _> = C((), &(), &());
- | ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+ | ^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
error: aborting due to 8 previous errors
-// check-pass
-// known-bug: #101350
+// Regression test for #101350.
+// check-fail
trait Trait {
type Ty;
fn extend<'a>() {
None::<<&'a () as Trait>::Ty>;
+ //~^ ERROR lifetime may not live long enough
}
fn main() {}
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/ascribed-type-wf.rs:13:5
+ |
+LL | fn extend<'a>() {
+ | -- lifetime `'a` defined here
+LL | None::<<&'a () as Trait>::Ty>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
--- /dev/null
+// This test fails if #104478 is fixed before #104477.
+
+// check-pass
+
+struct Printer<'a, 'b>(&'a (), &'b ());
+
+impl Printer<'_, '_> {
+ fn test(self) {
+ let clo = |_: &'_ Self| {};
+ clo(&self);
+ clo(&self);
+ }
+}
+
+fn main() {}
--- /dev/null
+// Make sure we honor region constraints when normalizing type annotations.
+
+// check-fail
+
+#![feature(more_qualified_paths)]
+
+trait Trait {
+ type Assoc;
+}
+
+impl<T> Trait for T
+where
+ T: 'static,
+{
+ type Assoc = MyTy<()>;
+}
+
+enum MyTy<T> {
+ Unit,
+ Tuple(),
+ Struct {},
+ Dumb(T),
+}
+
+impl<T> MyTy<T> {
+ const CONST: () = ();
+ fn method<X>() {}
+ fn method2<X>(&self) {}
+}
+
+trait TraitAssoc {
+ const TRAIT_CONST: ();
+ fn trait_method<X>(&self);
+}
+impl<T> TraitAssoc for T {
+ const TRAIT_CONST: () = ();
+ fn trait_method<X>(&self) {}
+}
+
+type Ty<'a> = <&'a () as Trait>::Assoc;
+
+fn test_local<'a>() {
+ let _: Ty<'a> = MyTy::Unit;
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_closure_sig<'a, 'b>() {
+ |_: Ty<'a>| {};
+ //~^ ERROR lifetime may not live long enough
+ || -> Option<Ty<'b>> { None };
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ <Ty<'a>>::method::<Ty<'static>>;
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'static>>::method::<Ty<'b>>;
+ //~^ ERROR lifetime may not live long enough
+
+ <Ty<'c>>::trait_method::<Ty<'static>>;
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'static>>::trait_method::<Ty<'d>>;
+ //~^ ERROR lifetime may not live long enough
+
+ <Ty<'e>>::CONST;
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'f>>::TRAIT_CONST;
+ //~^ ERROR lifetime may not live long enough
+
+ <Ty<'static>>::method::<Ty<'static>>;
+ <Ty<'static>>::trait_method::<Ty<'static>>;
+ <Ty<'static>>::CONST;
+ <Ty<'static>>::TRAIT_CONST;
+
+ MyTy::Unit::<Ty<'g>>;
+ //~^ ERROR lifetime may not live long enough
+ MyTy::<Ty<'h>>::Unit;
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_call<'a, 'b, 'c>() {
+ <Ty<'a>>::method::<Ty<'static>>();
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'static>>::method::<Ty<'b>>();
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_variants<'a, 'b, 'c>() {
+ <Ty<'a>>::Struct {};
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'b>>::Tuple();
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'c>>::Unit;
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_method_call<'a, 'b>(x: MyTy<()>) {
+ x.method2::<Ty<'a>>();
+ //~^ ERROR lifetime may not live long enough
+ x.trait_method::<Ty<'b>>();
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_struct_path<'a, 'b, 'c, 'd>() {
+ struct Struct<T> { x: Option<T>, }
+
+ trait Project {
+ type Struct;
+ type Enum;
+ }
+ impl<T> Project for T {
+ type Struct = Struct<()>;
+ type Enum = MyTy<()>;
+ }
+
+ // Resolves to enum variant
+ MyTy::<Ty<'a>>::Struct {}; // without SelfTy
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'b> as Project>::Enum::Struct {}; // with SelfTy
+ //~^ ERROR lifetime may not live long enough
+
+ // Resolves to struct and associated type respectively
+ Struct::<Ty<'c>> { x: None, }; // without SelfTy
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'d> as Project>::Struct { x: None, }; // with SelfTy
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+ use MyTy::*;
+ match MyTy::Unit {
+ Struct::<Ty<'a>> {..} => {},
+ //~^ ERROR lifetime may not live long enough
+ Tuple::<Ty<'b>> (..) => {},
+ //~^ ERROR lifetime may not live long enough
+ Unit::<Ty<'c>> => {},
+ //~^ ERROR lifetime may not live long enough
+ Dumb(_) => {},
+ };
+ match MyTy::Unit {
+ <Ty<'d>>::Struct {..} => {},
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'e>>::Tuple (..) => {},
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'f>>::Unit => {},
+ //~^ ERROR lifetime may not live long enough
+ Dumb(_) => {},
+ };
+}
+
+
+fn main() {}
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:43:12
+ |
+LL | fn test_local<'a>() {
+ | -- lifetime `'a` defined here
+LL | let _: Ty<'a> = MyTy::Unit;
+ | ^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:48:6
+ |
+LL | fn test_closure_sig<'a, 'b>() {
+ | -- lifetime `'a` defined here
+LL | |_: Ty<'a>| {};
+ | ^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:50:11
+ |
+LL | fn test_closure_sig<'a, 'b>() {
+ | -- lifetime `'b` defined here
+...
+LL | || -> Option<Ty<'b>> { None };
+ | ^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'a` with `'static`
+ = help: replace `'b` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:55:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'a` defined here
+LL | <Ty<'a>>::method::<Ty<'static>>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:57:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'b` defined here
+...
+LL | <Ty<'static>>::method::<Ty<'b>>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:60:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'c` defined here
+...
+LL | <Ty<'c>>::trait_method::<Ty<'static>>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'c` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:62:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'d` defined here
+...
+LL | <Ty<'static>>::trait_method::<Ty<'d>>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'d` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:65:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'e` defined here
+...
+LL | <Ty<'e>>::CONST;
+ | ^^^^^^^^^^^^^^^ requires that `'e` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:67:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'f` defined here
+...
+LL | <Ty<'f>>::TRAIT_CONST;
+ | ^^^^^^^^^^^^^^^^^^^^^ requires that `'f` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:75:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'g` defined here
+...
+LL | MyTy::Unit::<Ty<'g>>;
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'g` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:77:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'h` defined here
+...
+LL | MyTy::<Ty<'h>>::Unit;
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'h` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'a` with `'static`
+ = help: replace `'b` with `'static`
+ = help: replace `'c` with `'static`
+ = help: replace `'d` with `'static`
+ = help: replace `'e` with `'static`
+ = help: replace `'f` with `'static`
+ = help: replace `'g` with `'static`
+ = help: replace `'h` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:82:5
+ |
+LL | fn test_call<'a, 'b, 'c>() {
+ | -- lifetime `'a` defined here
+LL | <Ty<'a>>::method::<Ty<'static>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:84:5
+ |
+LL | fn test_call<'a, 'b, 'c>() {
+ | -- lifetime `'b` defined here
+...
+LL | <Ty<'static>>::method::<Ty<'b>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'a` with `'static`
+ = help: replace `'b` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:89:5
+ |
+LL | fn test_variants<'a, 'b, 'c>() {
+ | -- lifetime `'a` defined here
+LL | <Ty<'a>>::Struct {};
+ | ^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:91:5
+ |
+LL | fn test_variants<'a, 'b, 'c>() {
+ | -- lifetime `'b` defined here
+...
+LL | <Ty<'b>>::Tuple();
+ | ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:93:5
+ |
+LL | fn test_variants<'a, 'b, 'c>() {
+ | -- lifetime `'c` defined here
+...
+LL | <Ty<'c>>::Unit;
+ | ^^^^^^^^^^^^^^ requires that `'c` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'a` with `'static`
+ = help: replace `'b` with `'static`
+ = help: replace `'c` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:98:7
+ |
+LL | fn test_method_call<'a, 'b>(x: MyTy<()>) {
+ | -- lifetime `'a` defined here
+LL | x.method2::<Ty<'a>>();
+ | ^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:100:7
+ |
+LL | fn test_method_call<'a, 'b>(x: MyTy<()>) {
+ | -- lifetime `'b` defined here
+...
+LL | x.trait_method::<Ty<'b>>();
+ | ^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'a` with `'static`
+ = help: replace `'b` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:117:5
+ |
+LL | fn test_struct_path<'a, 'b, 'c, 'd>() {
+ | -- lifetime `'a` defined here
+...
+LL | MyTy::<Ty<'a>>::Struct {}; // without SelfTy
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:119:5
+ |
+LL | fn test_struct_path<'a, 'b, 'c, 'd>() {
+ | -- lifetime `'b` defined here
+...
+LL | <Ty<'b> as Project>::Enum::Struct {}; // with SelfTy
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:123:5
+ |
+LL | fn test_struct_path<'a, 'b, 'c, 'd>() {
+ | -- lifetime `'c` defined here
+...
+LL | Struct::<Ty<'c>> { x: None, }; // without SelfTy
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'c` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:125:5
+ |
+LL | fn test_struct_path<'a, 'b, 'c, 'd>() {
+ | -- lifetime `'d` defined here
+...
+LL | <Ty<'d> as Project>::Struct { x: None, }; // with SelfTy
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'d` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'a` with `'static`
+ = help: replace `'b` with `'static`
+ = help: replace `'c` with `'static`
+ = help: replace `'d` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:132:9
+ |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+ | -- lifetime `'a` defined here
+...
+LL | Struct::<Ty<'a>> {..} => {},
+ | ^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:134:9
+ |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+ | -- lifetime `'b` defined here
+...
+LL | Tuple::<Ty<'b>> (..) => {},
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:136:9
+ |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+ | -- lifetime `'c` defined here
+...
+LL | Unit::<Ty<'c>> => {},
+ | ^^^^^^^^^^^^^^ requires that `'c` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:141:9
+ |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+ | -- lifetime `'d` defined here
+...
+LL | <Ty<'d>>::Struct {..} => {},
+ | ^^^^^^^^^^^^^^^^^^^^^ requires that `'d` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:143:9
+ |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+ | -- lifetime `'e` defined here
+...
+LL | <Ty<'e>>::Tuple (..) => {},
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'e` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:145:9
+ |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+ | -- lifetime `'f` defined here
+...
+LL | <Ty<'f>>::Unit => {},
+ | ^^^^^^^^^^^^^^ requires that `'f` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'a` with `'static`
+ = help: replace `'b` with `'static`
+ = help: replace `'c` with `'static`
+ = help: replace `'d` with `'static`
+ = help: replace `'e` with `'static`
+ = help: replace `'f` with `'static`
+
+error: aborting due to 28 previous errors
+
--- /dev/null
+// check-fail
+
+trait Trait { type Assoc; }
+impl<'a> Trait for &'a () { type Assoc = &'a (); }
+
+struct MyTuple<T, U = <&'static () as Trait>::Assoc>(T, U);
+fn test_tuple(x: &(), y: &()) {
+ MyTuple::<_>((), x);
+ //~^ ERROR
+ let _: MyTuple::<_> = MyTuple((), y);
+ //~^ ERROR
+}
+
+struct MyStruct<T, U = <&'static () as Trait>::Assoc> { val: (T, U), }
+fn test_struct(x: &(), y: &()) {
+ MyStruct::<_> { val: ((), x) };
+ //~^ ERROR
+ let _: MyStruct::<_> = MyStruct { val: ((), y) };
+ //~^ ERROR
+}
+
+fn main() {}
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/normalization-default.rs:8:22
+ |
+LL | fn test_tuple(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'1`
+LL | MyTuple::<_>((), x);
+ | ^ this usage requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-default.rs:10:12
+ |
+LL | fn test_tuple(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'2`
+...
+LL | let _: MyTuple::<_> = MyTuple((), y);
+ | ^^^^^^^^^^^^ type annotation requires that `'2` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-default.rs:16:26
+ |
+LL | fn test_struct(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'1`
+LL | MyStruct::<_> { val: ((), x) };
+ | ^^^^^^^ this usage requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-default.rs:18:12
+ |
+LL | fn test_struct(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'2`
+...
+LL | let _: MyStruct::<_> = MyStruct { val: ((), y) };
+ | ^^^^^^^^^^^^^ type annotation requires that `'2` must outlive `'static`
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// Annnotations may contain projection types with inference variables as input.
+// Make sure we don't get ambiguities when normalizing them.
+
+// check-fail
+
+// Single impl.
+fn test1<A, B, C, D>(a: A, b: B, c: C) {
+ trait Tr { type Ty; }
+ impl<T: 'static> Tr for (T,) { type Ty = T; }
+
+ let _: <(_,) as Tr>::Ty = a; //~ ERROR type `A`
+ Some::<<(_,) as Tr>::Ty>(b); //~ ERROR type `B`
+ || -> <(_,) as Tr>::Ty { c }; //~ ERROR type `C`
+ |d: <(_,) as Tr>::Ty| -> D { d }; //~ ERROR type `D`
+}
+
+
+// Two impls. The selected impl depends on the actual type.
+fn test2<A, B, C>(a: A, b: B, c: C) {
+ trait Tr { type Ty; }
+ impl<T: 'static> Tr for (u8, T) { type Ty = T; }
+ impl<T> Tr for (i8, T) { type Ty = T; }
+ type Alias<X, Y> = (<(X, Y) as Tr>::Ty, X);
+
+ fn temp() -> String { todo!() }
+
+ // `u8` impl, requires static.
+ let _: Alias<_, _> = (a, 0u8); //~ ERROR type `A`
+ Some::<Alias<_, _>>((b, 0u8)); //~ ERROR type `B`
+ || -> Alias<_, _> { (c, 0u8) }; //~ ERROR type `C`
+
+ let _: Alias<_, _> = (&temp(), 0u8); //~ ERROR temporary value
+ Some::<Alias<_, _>>((&temp(), 0u8)); //~ ERROR temporary value
+
+ // `i8` impl, no region constraints.
+ let _: Alias<_, _> = (&temp(), 0i8);
+ Some::<Alias<_, _>>((&temp(), 0i8));
+}
+
+fn main() {}
--- /dev/null
+error[E0310]: the parameter type `A` may not live long enough
+ --> $DIR/normalization-infer.rs:11:12
+ |
+LL | let _: <(_,) as Tr>::Ty = a;
+ | ^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test1<A: 'static, B, C, D>(a: A, b: B, c: C) {
+ | +++++++++
+
+error[E0310]: the parameter type `B` may not live long enough
+ --> $DIR/normalization-infer.rs:12:5
+ |
+LL | Some::<<(_,) as Tr>::Ty>(b);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `B` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test1<A, B: 'static, C, D>(a: A, b: B, c: C) {
+ | +++++++++
+
+error[E0310]: the parameter type `C` may not live long enough
+ --> $DIR/normalization-infer.rs:13:11
+ |
+LL | || -> <(_,) as Tr>::Ty { c };
+ | ^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test1<A, B, C: 'static, D>(a: A, b: B, c: C) {
+ | +++++++++
+
+error[E0310]: the parameter type `D` may not live long enough
+ --> $DIR/normalization-infer.rs:14:6
+ |
+LL | |d: <(_,) as Tr>::Ty| -> D { d };
+ | ^ ...so that the type `D` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test1<A, B, C, D: 'static>(a: A, b: B, c: C) {
+ | +++++++++
+
+error[E0310]: the parameter type `A` may not live long enough
+ --> $DIR/normalization-infer.rs:28:12
+ |
+LL | let _: Alias<_, _> = (a, 0u8);
+ | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test2<A: 'static, B, C>(a: A, b: B, c: C) {
+ | +++++++++
+
+error[E0310]: the parameter type `B` may not live long enough
+ --> $DIR/normalization-infer.rs:29:5
+ |
+LL | Some::<Alias<_, _>>((b, 0u8));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `B` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test2<A, B: 'static, C>(a: A, b: B, c: C) {
+ | +++++++++
+
+error[E0310]: the parameter type `C` may not live long enough
+ --> $DIR/normalization-infer.rs:30:11
+ |
+LL | || -> Alias<_, _> { (c, 0u8) };
+ | ^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test2<A, B, C: 'static>(a: A, b: B, c: C) {
+ | +++++++++
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/normalization-infer.rs:32:28
+ |
+LL | let _: Alias<_, _> = (&temp(), 0u8);
+ | ----------- ^^^^^^ creates a temporary value which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/normalization-infer.rs:33:27
+ |
+LL | Some::<Alias<_, _>>((&temp(), 0u8));
+ | --^^^^^^------ - temporary value is freed at the end of this statement
+ | | |
+ | | creates a temporary value which is freed while still in use
+ | this usage requires that borrow lasts for `'static`
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0310, E0716.
+For more information about an error, try `rustc --explain E0310`.
--- /dev/null
+// check-fail
+
+trait Trait { type Assoc; }
+impl<'a> Trait for &'a () { type Assoc = &'a (); }
+
+struct MyTuple<T>(T);
+impl MyTuple<<&'static () as Trait>::Assoc> {
+ fn test(x: &(), y: &()) {
+ Self(x);
+ //~^ ERROR
+ let _: Self = MyTuple(y);
+ //~^ ERROR
+ }
+}
+
+struct MyStruct<T> { val: T, }
+impl MyStruct<<&'static () as Trait>::Assoc> {
+ fn test(x: &(), y: &()) {
+ Self { val: x };
+ //~^ ERROR
+ let _: Self = MyStruct { val: y };
+ //~^ ERROR
+ }
+}
+
+fn main() {}
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/normalization-self.rs:9:14
+ |
+LL | fn test(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'1`
+LL | Self(x);
+ | ^ this usage requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-self.rs:11:16
+ |
+LL | fn test(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'2`
+...
+LL | let _: Self = MyTuple(y);
+ | ^^^^ type annotation requires that `'2` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-self.rs:19:21
+ |
+LL | fn test(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'1`
+LL | Self { val: x };
+ | ^ this usage requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-self.rs:21:16
+ |
+LL | fn test(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'2`
+...
+LL | let _: Self = MyStruct { val: y };
+ | ^^^^ type annotation requires that `'2` must outlive `'static`
+
+error: aborting due to 4 previous errors
+
trait Foo { type Out; }
impl Foo for () { type Out = &'static u32; }
+impl<'a> Foo for &'a () { type Out = &'a u32; }
fn main() {
let a = 22;
- let b: <() as Foo>::Out = &a; //~ ERROR
+ let _: <() as Foo>::Out = &a; //~ ERROR
+
+ let a = 22;
+ let _: <&'static () as Foo>::Out = &a; //~ ERROR
+
+ let a = 22;
+ let _: <&'_ () as Foo>::Out = &a;
}
error[E0597]: `a` does not live long enough
- --> $DIR/normalization.rs:9:31
+ --> $DIR/normalization.rs:10:31
|
-LL | let b: <() as Foo>::Out = &a;
+LL | let _: <() as Foo>::Out = &a;
| ---------------- ^^ borrowed value does not live long enough
| |
| type annotation requires that `a` is borrowed for `'static`
+...
LL | }
| - `a` dropped here while still borrowed
-error: aborting due to previous error
+error[E0597]: `a` does not live long enough
+ --> $DIR/normalization.rs:13:40
+ |
+LL | let _: <&'static () as Foo>::Out = &a;
+ | ------------------------- ^^ borrowed value does not live long enough
+ | |
+ | type annotation requires that `a` is borrowed for `'static`
+...
+LL | }
+ | - `a` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0597`.
fn main() {
foo(1, 2, 3);
- //~^ ERROR this function takes 4 arguments but 3
+ //~^ ERROR function takes 4 arguments but 3
bar(1, 2, 3);
- //~^ ERROR this function takes 6 arguments but 3
+ //~^ ERROR function takes 6 arguments but 3
}
--- /dev/null
+// check-pass
+
+#![deny(where_clauses_object_safety)]
+
+pub trait Trait {
+ fn method(&self) where Self: Sync;
+}
+
+fn main() {}
--- /dev/null
+enum E {
+ Foo {
+<<<<<<< HEAD //~ ERROR encountered diff marker
+ x: u8,
+|||||||
+ z: (),
+=======
+ y: i8,
+>>>>>>> branch
+ }
+}
--- /dev/null
+error: encountered diff marker
+ --> $DIR/enum-2.rs:3:1
+ |
+LL | <<<<<<< HEAD
+ | ^^^^^^^ after this is the code before the merge
+LL | x: u8,
+LL | |||||||
+ | -------
+LL | z: (),
+LL | =======
+ | -------
+LL | y: i8,
+LL | >>>>>>> branch
+ | ^^^^^^^ above this are the incoming code changes
+ |
+ = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+ = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+ = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
--- /dev/null
+enum E {
+<<<<<<< HEAD //~ ERROR encountered diff marker
+ Foo(u8),
+=======
+ Bar(i8),
+>>>>>>> branch
+}
--- /dev/null
+error: encountered diff marker
+ --> $DIR/enum.rs:2:1
+ |
+LL | <<<<<<< HEAD
+ | ^^^^^^^ after this is the code before the merge
+LL | Foo(u8),
+LL | =======
+ | -------
+LL | Bar(i8),
+LL | >>>>>>> branch
+ | ^^^^^^^ above this are the incoming code changes
+ |
+ = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+ = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+ = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
--- /dev/null
+trait T {
+ fn foo(
+<<<<<<< HEAD //~ ERROR encountered diff marker
+ x: u8,
+=======
+ x: i8,
+>>>>>>> branch
+ ) {}
+}
+
+struct S;
+impl T for S {}
+
+fn main() {
+ S::foo(42);
+}
--- /dev/null
+error: encountered diff marker
+ --> $DIR/fn-arg.rs:3:1
+ |
+LL | <<<<<<< HEAD
+ | ^^^^^^^ after this is the code before the merge
+LL | x: u8,
+LL | =======
+ | -------
+LL | x: i8,
+LL | >>>>>>> branch
+ | ^^^^^^^ above this are the incoming code changes
+ |
+ = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+ = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+ = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
--- /dev/null
+#[attribute]
+<<<<<<< HEAD //~ ERROR encountered diff marker
+fn foo() {}
+=======
+fn bar() {}
+>>>>>>> branch
+
+fn main() {
+ foo();
+}
--- /dev/null
+error: encountered diff marker
+ --> $DIR/item-with-attr.rs:2:1
+ |
+LL | <<<<<<< HEAD
+ | ^^^^^^^ after this is the code before the merge
+LL | fn foo() {}
+LL | =======
+ | -------
+LL | fn bar() {}
+LL | >>>>>>> branch
+ | ^^^^^^^ above this are the incoming code changes
+ |
+ = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+ = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+ = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
--- /dev/null
+<<<<<<< HEAD //~ ERROR encountered diff marker
+fn foo() {}
+=======
+fn bar() {}
+>>>>>>> branch
+
+fn main() {
+ foo();
+}
--- /dev/null
+error: encountered diff marker
+ --> $DIR/item.rs:1:1
+ |
+LL | <<<<<<< HEAD
+ | ^^^^^^^ after this is the code before the merge
+LL | fn foo() {}
+LL | =======
+ | -------
+LL | fn bar() {}
+LL | >>>>>>> branch
+ | ^^^^^^^ above this are the incoming code changes
+ |
+ = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+ = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+ = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
--- /dev/null
+trait T {
+ fn foo() {}
+ fn bar() {}
+}
+
+struct S;
+impl T for S {}
+
+fn main() {
+<<<<<<< HEAD //~ ERROR encountered diff marker
+ S::foo();
+=======
+ S::bar();
+>>>>>>> branch
+}
--- /dev/null
+error: encountered diff marker
+ --> $DIR/statement.rs:10:1
+ |
+LL | <<<<<<< HEAD
+ | ^^^^^^^ after this is the code before the merge
+LL | S::foo();
+LL | =======
+ | -------
+LL | S::bar();
+LL | >>>>>>> branch
+ | ^^^^^^^ above this are the incoming code changes
+ |
+ = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+ = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+ = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
--- /dev/null
+struct S {
+ x: u8,
+}
+fn main() {
+ let _ = S {
+<<<<<<< HEAD //~ ERROR encountered diff marker
+ x: 42,
+=======
+ x: 0,
+>>>>>>> branch
+ }
+}
--- /dev/null
+error: encountered diff marker
+ --> $DIR/struct-expr.rs:6:1
+ |
+LL | <<<<<<< HEAD
+ | ^^^^^^^ after this is the code before the merge
+LL | x: 42,
+LL | =======
+ | -------
+LL | x: 0,
+LL | >>>>>>> branch
+ | ^^^^^^^ above this are the incoming code changes
+ |
+ = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+ = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+ = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
--- /dev/null
+struct S {
+<<<<<<< HEAD //~ ERROR encountered diff marker
+ x: u8,
+=======
+ x: i8,
+>>>>>>> branch
+}
--- /dev/null
+error: encountered diff marker
+ --> $DIR/struct.rs:2:1
+ |
+LL | <<<<<<< HEAD
+ | ^^^^^^^ after this is the code before the merge
+LL | x: u8,
+LL | =======
+ | -------
+LL | x: i8,
+LL | >>>>>>> branch
+ | ^^^^^^^ above this are the incoming code changes
+ |
+ = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+ = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+ = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
--- /dev/null
+trait T {
+<<<<<<< HEAD //~ ERROR encountered diff marker
+ fn foo() {}
+=======
+ fn bar() {}
+>>>>>>> branch
+}
+
+struct S;
+impl T for S {}
+
+fn main() {
+ S::foo();
+}
--- /dev/null
+error: encountered diff marker
+ --> $DIR/trait-item.rs:2:1
+ |
+LL | <<<<<<< HEAD
+ | ^^^^^^^ after this is the code before the merge
+LL | fn foo() {}
+LL | =======
+ | -------
+LL | fn bar() {}
+LL | >>>>>>> branch
+ | ^^^^^^^ above this are the incoming code changes
+ |
+ = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+ = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+ = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
--- /dev/null
+struct S(
+<<<<<<< HEAD //~ ERROR encountered diff marker
+ u8,
+=======
+ i8,
+>>>>>>> branch
+);
--- /dev/null
+error: encountered diff marker
+ --> $DIR/tuple-struct.rs:2:1
+ |
+LL | <<<<<<< HEAD
+ | ^^^^^^^ after this is the code before the merge
+LL | u8,
+LL | =======
+ | -------
+LL | i8,
+LL | >>>>>>> branch
+ | ^^^^^^^ above this are the incoming code changes
+ |
+ = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+ = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+ = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
--- /dev/null
+use foo::{
+<<<<<<< HEAD //~ ERROR encountered diff marker
+ bar,
+=======
+ baz,
+>>>>>>> branch
+};
+
+fn main() {}
--- /dev/null
+error: encountered diff marker
+ --> $DIR/use-statement.rs:2:1
+ |
+LL | <<<<<<< HEAD
+ | ^^^^^^^ after this is the code before the merge
+LL | bar,
+LL | =======
+ | -------
+LL | baz,
+LL | >>>>>>> branch
+ | ^^^^^^^ above this are the incoming code changes
+ |
+ = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+ = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+ = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
|
LL | 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: value exceeds limit of `340282366920938463463374607431768211455`
error: aborting due to previous error
--- /dev/null
+// This tests the parser recovery in `recover_intersection_pat`
+// and serves as a regression test for the diagnostics issue #65400.
+//
+// The general idea is that for `$pat_lhs @ $pat_rhs` where
+// `$pat_lhs` is not generated by `ref? mut? $ident` we want
+// to suggest either switching the order or note that intersection
+// patterns are not allowed.
+
+// run-rustfix
+
+#![allow(unused_variables)]
+
+fn main() {
+ let s: Option<u8> = None;
+
+ match s {
+ y @ Some(x) => {}
+ //~^ ERROR pattern on wrong side of `@`
+ //~| pattern on the left, should be on the right
+ //~| binding on the right, should be on the left
+ //~| HELP switch the order
+ //~| SUGGESTION y @ Some(x)
+ _ => {}
+ }
+
+ match 2 {
+ e @ 1..=5 => {}
+ //~^ ERROR pattern on wrong side of `@`
+ //~| pattern on the left, should be on the right
+ //~| binding on the right, should be on the left
+ //~| HELP switch the order
+ //~| SUGGESTION e @ 1..=5
+ _ => {}
+ }
+}
--- /dev/null
+// This tests the parser recovery in `recover_intersection_pat`
+// and serves as a regression test for the diagnostics issue #65400.
+//
+// The general idea is that for `$pat_lhs @ $pat_rhs` where
+// `$pat_lhs` is not generated by `ref? mut? $ident` we want
+// to suggest either switching the order or note that intersection
+// patterns are not allowed.
+
+// run-rustfix
+
+#![allow(unused_variables)]
+
+fn main() {
+ let s: Option<u8> = None;
+
+ match s {
+ Some(x) @ y => {}
+ //~^ ERROR pattern on wrong side of `@`
+ //~| pattern on the left, should be on the right
+ //~| binding on the right, should be on the left
+ //~| HELP switch the order
+ //~| SUGGESTION y @ Some(x)
+ _ => {}
+ }
+
+ match 2 {
+ 1 ..= 5 @ e => {}
+ //~^ ERROR pattern on wrong side of `@`
+ //~| pattern on the left, should be on the right
+ //~| binding on the right, should be on the left
+ //~| HELP switch the order
+ //~| SUGGESTION e @ 1..=5
+ _ => {}
+ }
+}
--- /dev/null
+error: pattern on wrong side of `@`
+ --> $DIR/intersection-patterns-1.rs:17:9
+ |
+LL | Some(x) @ y => {}
+ | -------^^^-
+ | | |
+ | | binding on the right, should be on the left
+ | pattern on the left, should be on the right
+ | help: switch the order: `y @ Some(x)`
+
+error: pattern on wrong side of `@`
+ --> $DIR/intersection-patterns-1.rs:27:9
+ |
+LL | 1 ..= 5 @ e => {}
+ | -------^^^-
+ | | |
+ | | binding on the right, should be on the left
+ | pattern on the left, should be on the right
+ | help: switch the order: `e @ 1..=5`
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// This tests the parser recovery in `recover_intersection_pat`
+// and serves as a regression test for the diagnostics issue #65400.
+//
+// The general idea is that for `$pat_lhs @ $pat_rhs` where
+// `$pat_lhs` is not generated by `ref? mut? $ident` we want
+// to suggest either switching the order or note that intersection
+// patterns are not allowed.
+
+fn main() {
+ let s: Option<u8> = None;
+
+ match s {
+ Some(x) @ Some(y) => {}
+ //~^ ERROR left-hand side of `@` must be a binding
+ //~| interpreted as a pattern, not a binding
+ //~| also a pattern
+ //~| NOTE bindings are `x`, `mut x`, `ref x`, and `ref mut x`
+ _ => {}
+ }
+}
--- /dev/null
+error: left-hand side of `@` must be a binding
+ --> $DIR/intersection-patterns-2.rs:13:9
+ |
+LL | Some(x) @ Some(y) => {}
+ | -------^^^-------
+ | | |
+ | | also a pattern
+ | interpreted as a pattern, not a binding
+ |
+ = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x`
+
+error: aborting due to previous error
+
+++ /dev/null
-// This tests the parser recovery in `recover_intersection_pat`
-// and serves as a regression test for the diagnostics issue #65400.
-//
-// The general idea is that for `$pat_lhs @ $pat_rhs` where
-// `$pat_lhs` is not generated by `ref? mut? $ident` we want
-// to suggest either switching the order or note that intersection
-// patterns are not allowed.
-
-fn main() {
- let s: Option<u8> = None;
-
- match s {
- Some(x) @ y => {}
- //~^ ERROR pattern on wrong side of `@`
- //~| pattern on the left, should be on the right
- //~| binding on the right, should be on the left
- //~| HELP switch the order
- //~| SUGGESTION y @ Some(x)
- _ => {}
- }
-
- match s {
- Some(x) @ Some(y) => {}
- //~^ ERROR left-hand side of `@` must be a binding
- //~| interpreted as a pattern, not a binding
- //~| also a pattern
- //~| NOTE bindings are `x`, `mut x`, `ref x`, and `ref mut x`
- _ => {}
- }
-
- match 2 {
- 1 ..= 5 @ e => {}
- //~^ ERROR pattern on wrong side of `@`
- //~| pattern on the left, should be on the right
- //~| binding on the right, should be on the left
- //~| HELP switch the order
- //~| SUGGESTION e @ 1..=5
- _ => {}
- }
-}
+++ /dev/null
-error: pattern on wrong side of `@`
- --> $DIR/intersection-patterns.rs:13:9
- |
-LL | Some(x) @ y => {}
- | -------^^^-
- | | |
- | | binding on the right, should be on the left
- | pattern on the left, should be on the right
- | help: switch the order: `y @ Some(x)`
-
-error: left-hand side of `@` must be a binding
- --> $DIR/intersection-patterns.rs:23:9
- |
-LL | Some(x) @ Some(y) => {}
- | -------^^^-------
- | | |
- | | also a pattern
- | interpreted as a pattern, not a binding
- |
- = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x`
-
-error: pattern on wrong side of `@`
- --> $DIR/intersection-patterns.rs:32:9
- |
-LL | 1 ..= 5 @ e => {}
- | -------^^^-
- | | |
- | | binding on the right, should be on the left
- | pattern on the left, should be on the right
- | help: switch the order: `e @ 1..=5`
-
-error: aborting due to 3 previous errors
-
|
LL | let __isize = 340282366920938463463374607431768211456; // 2^128
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: value exceeds limit of `340282366920938463463374607431768211455`
error: aborting due to previous error
|
LL | let __isize = 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ff;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: value exceeds limit of `0xffffffffffffffffffffffffffffffff`
error: aborting due to previous error
//~^ ERROR expected identifier, found keyword `fn`
//~| ERROR expected identifier, found keyword `fn`
//~| ERROR expected identifier, found keyword `fn`
-//~| ERROR cannot find trait `r#fn` in this scope
-//~| ERROR cannot find trait `r#fn` in this scope
-//~| ERROR cannot find trait `r#fn` in this scope
-//~| HELP a trait with a similar name exists
-//~| HELP a trait with a similar name exists
-//~| HELP a trait with a similar name exists
-//~| HELP escape `fn` to use it as an identifier
-//~| HELP escape `fn` to use it as an identifier
-//~| HELP escape `fn` to use it as an identifier
+//~| HELP use `Fn` to refer to the trait
+//~| HELP use `Fn` to refer to the trait
+//~| HELP use `Fn` to refer to the trait
where
G: fn(),
//~^ ERROR expected identifier, found keyword `fn`
- //~| ERROR cannot find trait `r#fn` in this scope
- //~| HELP a trait with a similar name exists
- //~| HELP escape `fn` to use it as an identifier
+ //~| HELP use `Fn` to refer to the trait
{}
fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
--> $DIR/kw-in-trait-bounds.rs:3:10
|
LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
- | ^^ expected identifier, found keyword
+ | ^^
|
-help: escape `fn` to use it as an identifier
+help: use `Fn` to refer to the trait
|
-LL | fn _f<F: r#fn(), G>(_: impl fn(), _: &dyn fn())
- | ++
+LL | fn _f<F: Fn(), G>(_: impl fn(), _: &dyn fn())
+ | ~~
error: expected identifier, found keyword `fn`
--> $DIR/kw-in-trait-bounds.rs:3:27
|
LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
- | ^^ expected identifier, found keyword
+ | ^^
|
-help: escape `fn` to use it as an identifier
+help: use `Fn` to refer to the trait
|
-LL | fn _f<F: fn(), G>(_: impl r#fn(), _: &dyn fn())
- | ++
+LL | fn _f<F: fn(), G>(_: impl Fn(), _: &dyn fn())
+ | ~~
error: expected identifier, found keyword `fn`
--> $DIR/kw-in-trait-bounds.rs:3:41
|
LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
- | ^^ expected identifier, found keyword
+ | ^^
|
-help: escape `fn` to use it as an identifier
+help: use `Fn` to refer to the trait
|
-LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn r#fn())
- | ++
+LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn Fn())
+ | ~~
error: expected identifier, found keyword `fn`
- --> $DIR/kw-in-trait-bounds.rs:17:4
+ --> $DIR/kw-in-trait-bounds.rs:11:4
|
LL | G: fn(),
- | ^^ expected identifier, found keyword
+ | ^^
|
-help: escape `fn` to use it as an identifier
+help: use `Fn` to refer to the trait
|
-LL | G: r#fn(),
- | ++
+LL | G: Fn(),
+ | ~~
error: expected identifier, found keyword `struct`
- --> $DIR/kw-in-trait-bounds.rs:24:10
+ --> $DIR/kw-in-trait-bounds.rs:16:10
|
LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
| ^^^^^^ expected identifier, found keyword
| ++
error: expected identifier, found keyword `struct`
- --> $DIR/kw-in-trait-bounds.rs:24:29
+ --> $DIR/kw-in-trait-bounds.rs:16:29
|
LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
| ^^^^^^ expected identifier, found keyword
| ++
error: expected identifier, found keyword `struct`
- --> $DIR/kw-in-trait-bounds.rs:24:45
+ --> $DIR/kw-in-trait-bounds.rs:16:45
|
LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
| ^^^^^^ expected identifier, found keyword
| ++
error: expected identifier, found keyword `struct`
- --> $DIR/kw-in-trait-bounds.rs:38:8
+ --> $DIR/kw-in-trait-bounds.rs:30:8
|
LL | B: struct,
| ^^^^^^ expected identifier, found keyword
LL | B: r#struct,
| ++
-error[E0405]: cannot find trait `r#fn` in this scope
- --> $DIR/kw-in-trait-bounds.rs:3:10
- |
-LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
- | ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
- --> $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
- = note: similarly named trait `Fn` defined here
-
-error[E0405]: cannot find trait `r#fn` in this scope
- --> $DIR/kw-in-trait-bounds.rs:17:4
- |
-LL | G: fn(),
- | ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
- --> $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
- = note: similarly named trait `Fn` defined here
-
-error[E0405]: cannot find trait `r#fn` in this scope
- --> $DIR/kw-in-trait-bounds.rs:3:27
- |
-LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
- | ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
- --> $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
- = note: similarly named trait `Fn` defined here
-
-error[E0405]: cannot find trait `r#fn` in this scope
- --> $DIR/kw-in-trait-bounds.rs:3:41
- |
-LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
- | ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
- --> $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
- = note: similarly named trait `Fn` defined here
-
error[E0405]: cannot find trait `r#struct` in this scope
- --> $DIR/kw-in-trait-bounds.rs:24:10
+ --> $DIR/kw-in-trait-bounds.rs:16:10
|
LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
| ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
| ------------ similarly named trait `Struct` defined here
error[E0405]: cannot find trait `r#struct` in this scope
- --> $DIR/kw-in-trait-bounds.rs:38:8
+ --> $DIR/kw-in-trait-bounds.rs:30:8
|
LL | B: struct,
| ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
| ------------ similarly named trait `Struct` defined here
error[E0405]: cannot find trait `r#struct` in this scope
- --> $DIR/kw-in-trait-bounds.rs:24:29
+ --> $DIR/kw-in-trait-bounds.rs:16:29
|
LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
| ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
| ------------ similarly named trait `Struct` defined here
error[E0405]: cannot find trait `r#struct` in this scope
- --> $DIR/kw-in-trait-bounds.rs:24:45
+ --> $DIR/kw-in-trait-bounds.rs:16:45
|
LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
| ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
LL | trait Struct {}
| ------------ similarly named trait `Struct` defined here
-error: aborting due to 16 previous errors
+error: aborting due to 12 previous errors
For more information about this error, try `rustc --explain E0405`.
--- /dev/null
+fn main() {
+ foo<<S as T>::V>(); //~ ERROR
+}
--- /dev/null
+error: comparison operators cannot be chained
+ --> $DIR/nested-bad-turbofish.rs:2:16
+ |
+LL | foo<<S as T>::V>();
+ | ^ ^
+ |
+ = help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+ = help: or use `(...)` if you meant to specify fn arguments
+
+error: aborting due to previous error
+
--- /dev/null
+fn foo(_: impl fn() -> i32) {}
+//~^ ERROR expected identifier, found keyword `fn`
+
+fn foo2<T: fn(i32)>(_: T) {}
+//~^ ERROR expected identifier, found keyword `fn`
+
+fn main() {
+ foo(|| ());
+ //~^ mismatched types
+ foo2(|_: ()| {});
+ //~^ type mismatch in closure arguments
+}
--- /dev/null
+error: expected identifier, found keyword `fn`
+ --> $DIR/recover-fn-trait-from-fn-kw.rs:1:16
+ |
+LL | fn foo(_: impl fn() -> i32) {}
+ | ^^
+ |
+help: use `Fn` to refer to the trait
+ |
+LL | fn foo(_: impl Fn() -> i32) {}
+ | ~~
+
+error: expected identifier, found keyword `fn`
+ --> $DIR/recover-fn-trait-from-fn-kw.rs:4:12
+ |
+LL | fn foo2<T: fn(i32)>(_: T) {}
+ | ^^
+ |
+help: use `Fn` to refer to the trait
+ |
+LL | fn foo2<T: Fn(i32)>(_: T) {}
+ | ~~
+
+error[E0308]: mismatched types
+ --> $DIR/recover-fn-trait-from-fn-kw.rs:8:12
+ |
+LL | foo(|| ());
+ | ^^ expected `i32`, found `()`
+
+error[E0631]: type mismatch in closure arguments
+ --> $DIR/recover-fn-trait-from-fn-kw.rs:10:5
+ |
+LL | foo2(|_: ()| {});
+ | ^^^^ ------- found signature defined here
+ | |
+ | expected due to this
+ |
+ = note: expected closure signature `fn(i32) -> _`
+ found closure signature `fn(()) -> _`
+note: required by a bound in `foo2`
+ --> $DIR/recover-fn-trait-from-fn-kw.rs:4:12
+ |
+LL | fn foo2<T: fn(i32)>(_: T) {}
+ | ^^^^^^^ required by this bound in `foo2`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0308, E0631.
+For more information about an error, try `rustc --explain E0308`.
error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable
--> $DIR/nested-binding-modes-mut.rs:4:5
|
-LL | let mut is_mut @ not_mut = 42;
- | ------- help: consider changing this to be mutable: `mut not_mut`
-LL | &mut is_mut;
LL | &mut not_mut;
| ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut is_mut @ mut not_mut = 42;
+ | +++
error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable
--> $DIR/nested-binding-modes-mut.rs:9:5
|
-LL | let not_mut @ mut is_mut = 42;
- | ------- help: consider changing this to be mutable: `mut not_mut`
-LL | &mut is_mut;
LL | &mut not_mut;
| ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut not_mut @ mut is_mut = 42;
+ | +++
error: aborting due to 2 previous errors
error[E0594]: cannot assign to `*_x0`, which is behind a `&` reference
--> $DIR/borrowck-move-ref-pattern.rs:26:5
|
-LL | let (ref _x0, _x1, ref _x2, ..) = tup;
- | ------- help: consider changing this to be a mutable reference: `ref mut _x0`
-...
LL | *_x0 = U;
| ^^^^^^^^ `_x0` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let (ref mut _x0, _x1, ref _x2, ..) = tup;
+ | ~~~~~~~~~~~
error[E0594]: cannot assign to `*_x2`, which is behind a `&` reference
--> $DIR/borrowck-move-ref-pattern.rs:27:5
|
-LL | let (ref _x0, _x1, ref _x2, ..) = tup;
- | ------- help: consider changing this to be a mutable reference: `ref mut _x2`
-...
LL | *_x2 = U;
| ^^^^^^^^ `_x2` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let (ref _x0, _x1, ref mut _x2, ..) = tup;
+ | ~~~~~~~~~~~
error[E0382]: use of moved value: `tup.1`
--> $DIR/borrowck-move-ref-pattern.rs:28:10
--- /dev/null
+fn main() {
+ let x = foo::Foo::default();
+ if x.len {
+ //~^ ERROR field `len` of struct `Foo` is private
+ println!("foo");
+ }
+}
+
+mod foo {
+ #[derive(Default)]
+ pub struct Foo {
+ len: String,
+ }
+
+ impl Foo {
+ pub fn len(&self) -> usize {
+ 42
+ }
+ }
+}
--- /dev/null
+error[E0616]: field `len` of struct `Foo` is private
+ --> $DIR/private-field-ty-err.rs:3:10
+ |
+LL | if x.len {
+ | ^^^ private field
+ |
+help: a method `len` also exists, call it with parentheses
+ |
+LL | if x.len() {
+ | ++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0616`.
#[cfg(target_os = "android")]
{
- // Android signals an abort() call with SIGSEGV at address 0xdeadbaad
- // See e.g. https://groups.google.com/g/android-ndk/c/laW1CJc7Icc
- assert!(signal == libc::SIGSEGV);
-
- // Additional checks performed:
- // 1. Find last tombstone (similar to coredump but in text format) from the
- // same executable (path) as we are (must be because of usage of fork):
- // This ensures that we look into the correct tombstone.
- // 2. Cause of crash is a SIGSEGV with address 0xdeadbaad.
- // 3. libc::abort call is in one of top two functions on callstack.
- // The last two steps distinguish between a normal SIGSEGV and one caused
- // by libc::abort.
-
- let this_exe = std::env::current_exe().unwrap().into_os_string().into_string().unwrap();
- let exe_string = format!(">>> {this_exe} <<<");
- let tombstone = (0..100)
- .map(|n| format!("/data/tombstones/tombstone_{n:02}"))
- .filter(|f| std::path::Path::new(&f).exists())
- .map(|f| std::fs::read_to_string(&f).expect("Cannot read tombstone file"))
- .filter(|f| f.contains(&exe_string))
- .last()
- .expect("no tombstone found");
-
- println!("Content of tombstone:\n{tombstone}");
-
- assert!(
- tombstone.contains("signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad")
- );
- let abort_on_top = tombstone
- .lines()
- .skip_while(|l| !l.contains("backtrace:"))
- .skip(1)
- .take_while(|l| l.starts_with(" #"))
- .take(2)
- .any(|f| f.contains("/system/lib/libc.so (abort"));
- assert!(abort_on_top);
+ assert!(signal == libc::SIGABRT || signal == libc::SIGSEGV);
+
+ if signal == libc::SIGSEGV {
+ // Pre-KitKat versions of Android signal an abort() with SIGSEGV at address 0xdeadbaad
+ // See e.g. https://groups.google.com/g/android-ndk/c/laW1CJc7Icc
+ //
+ // This behavior was changed in KitKat to send a standard SIGABRT signal.
+ // See: https://r.android.com/60341
+ //
+ // Additional checks performed:
+ // 1. Find last tombstone (similar to coredump but in text format) from the
+ // same executable (path) as we are (must be because of usage of fork):
+ // This ensures that we look into the correct tombstone.
+ // 2. Cause of crash is a SIGSEGV with address 0xdeadbaad.
+ // 3. libc::abort call is in one of top two functions on callstack.
+ // The last two steps distinguish between a normal SIGSEGV and one caused
+ // by libc::abort.
+
+ let this_exe = std::env::current_exe().unwrap().into_os_string().into_string().unwrap();
+ let exe_string = format!(">>> {this_exe} <<<");
+ let tombstone = (0..100)
+ .map(|n| format!("/data/tombstones/tombstone_{n:02}"))
+ .filter(|f| std::path::Path::new(&f).exists())
+ .map(|f| std::fs::read_to_string(&f).expect("Cannot read tombstone file"))
+ .filter(|f| f.contains(&exe_string))
+ .last()
+ .expect("no tombstone found");
+
+ println!("Content of tombstone:\n{tombstone}");
+
+ assert!(tombstone
+ .contains("signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad"));
+ let abort_on_top = tombstone
+ .lines()
+ .skip_while(|l| !l.contains("backtrace:"))
+ .skip(1)
+ .take_while(|l| l.starts_with(" #"))
+ .take(2)
+ .any(|f| f.contains("/system/lib/libc.so (abort"));
+ assert!(abort_on_top);
+ }
}
}
| lifetime `'a` defined here
...
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
| |
| lifetime `'a` defined here
LL | let z: Option<&'b &'a usize> = None;
- | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
+ | ^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
| lifetime `'a` defined here
LL | let y: Paramd<'a> = Paramd { x: a };
LL | let z: Option<&'b Paramd<'a>> = None;
- | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
+ | ^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
| |
| lifetime `'a` defined here
LL | let z: Option<&'a &'b usize> = None;
- | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+ | ^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
error[E0277]: the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied
- --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:1
+ --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:49
|
-LL | / fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
-LL | |
-LL | |
-LL | | {
-LL | | }
- | |_^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T`
+LL | fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T`
|
help: consider restricting type parameter `T`
|
| ++++++++++++++++++++++++
error[E0277]: the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied
- --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:49
+ --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:1
|
-LL | fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T`
+LL | / fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
+LL | |
+LL | |
+LL | | {
+LL | | }
+ | |_^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T`
|
help: consider restricting type parameter `T`
|
| lifetime `'a` defined here
...
LL | let _: &'a WithHrAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
| lifetime `'a` defined here
...
LL | let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
| lifetime `'a` defined here
...
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
| lifetime `'a` defined here
...
LL | let _x: &'a WithAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
| lifetime `'a` defined here
...
LL | let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
--- /dev/null
+use std::mem::size_of;
+
+#[repr(transparent)]
+enum Foo { //~ ERROR E0731
+ A(u8), B(u8),
+}
+
+fn main() {
+ println!("Foo: {}", size_of::<Foo>());
+}
--- /dev/null
+error[E0731]: transparent enum needs exactly one variant, but has 2
+ --> $DIR/transparent-enum-too-many-variants.rs:4:1
+ |
+LL | enum Foo {
+ | ^^^^^^^^ needs exactly one variant, but has 2
+LL | A(u8), B(u8),
+ | - - too many variants in `Foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0731`.
// Make sure primitive type fallback doesn't work in value namespace
std::mem::size_of(u16);
//~^ ERROR expected value, found builtin type `u16`
- //~| ERROR this function takes 0 arguments but 1 argument was supplied
+ //~| ERROR function takes 0 arguments but 1 argument was supplied
// Make sure primitive type fallback doesn't work with global paths
let _: ::u8;
+#![feature(if_let_guard)]
+
enum VecWrapper { A(Vec<i32>) }
-fn foo(x: VecWrapper) -> usize {
+fn if_guard(x: VecWrapper) -> usize {
match x {
VecWrapper::A(v) if { drop(v); false } => 1,
//~^ ERROR cannot move out of `v` in pattern guard
}
}
+fn if_let_guard(x: VecWrapper) -> usize {
+ match x {
+ VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1,
+ //~^ ERROR cannot move out of `v` in pattern guard
+ VecWrapper::A(v) => v.len()
+ }
+}
+
fn main() {
- foo(VecWrapper::A(vec![107]));
+ if_guard(VecWrapper::A(vec![107]));
+ if_let_guard(VecWrapper::A(vec![107]));
}
error[E0507]: cannot move out of `v` in pattern guard
- --> $DIR/rfc-reject-double-move-across-arms.rs:5:36
+ --> $DIR/rfc-reject-double-move-across-arms.rs:7:36
|
LL | VecWrapper::A(v) if { drop(v); false } => 1,
| ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
-error: aborting due to previous error
+error[E0507]: cannot move out of `v` in pattern guard
+ --> $DIR/rfc-reject-double-move-across-arms.rs:15:51
+ |
+LL | VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1,
+ | ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0507`.
+#![feature(if_let_guard)]
+
struct A { a: Box<i32> }
-fn foo(n: i32) {
+fn if_guard(n: i32) {
let x = A { a: Box::new(n) };
let _y = match x {
A { a: v } if { drop(v); true } => v,
};
}
+fn if_let_guard(n: i32) {
+ let x = A { a: Box::new(n) };
+ let _y = match x {
+ A { a: v } if let Some(()) = { drop(v); Some(()) } => v,
+ //~^ ERROR cannot move out of `v` in pattern guard
+ _ => Box::new(0),
+ };
+}
+
fn main() {
- foo(107);
+ if_guard(107);
+ if_let_guard(107);
}
error[E0507]: cannot move out of `v` in pattern guard
- --> $DIR/rfc-reject-double-move-in-first-arm.rs:6:30
+ --> $DIR/rfc-reject-double-move-in-first-arm.rs:8:30
|
LL | A { a: v } if { drop(v); true } => v,
| ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
-error: aborting due to previous error
+error[E0507]: cannot move out of `v` in pattern guard
+ --> $DIR/rfc-reject-double-move-in-first-arm.rs:17:45
+ |
+LL | A { a: v } if let Some(()) = { drop(v); Some(()) } => v,
+ | ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0507`.
// run-pass
+// revisions: default mir-opt
+//[default] compile-flags: -Zinline-mir=no
+//[mir-opt] compile-flags: -Zmir-opt-level=4
use std::panic::Location;
struct Foo;
impl Foo {
+ #[inline(always)]
#[track_caller]
fn check_loc(&self, line: u32, col: u32) -> &Self {
let loc = Location::caller();
--- /dev/null
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Tr {
+ fn a(self) -> i32;
+}
+
+impl Tr for () {
+ fn a(self) -> i32 { 42 }
+}
+
+const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+ x(())
+}
+
+const _: () = assert!(need_const_closure(Tr::a) == 42);
+//~^ ERROR: the trait bound
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `(): ~const Tr` is not satisfied in `fn(()) -> i32 {<() as Tr>::a}`
+ --> $DIR/const-closure-trait-method-fail.rs:16:42
+ |
+LL | const _: () = assert!(need_const_closure(Tr::a) == 42);
+ | ------------------ ^^^^^ within `fn(()) -> i32 {<() as Tr>::a}`, the trait `~const Tr` is not implemented for `()`
+ | |
+ | required by a bound introduced by this call
+ |
+note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
+ --> $DIR/const-closure-trait-method-fail.rs:16:42
+ |
+LL | const _: () = assert!(need_const_closure(Tr::a) == 42);
+ | ^^^^^
+ = note: required because it appears within the type `fn(()) -> i32 {<() as Tr>::a}`
+note: required by a bound in `need_const_closure`
+ --> $DIR/const-closure-trait-method-fail.rs:12:32
+ |
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `need_const_closure`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Tr {
+ fn a(self) -> i32;
+}
+
+impl const Tr for () {
+ fn a(self) -> i32 { 42 }
+}
+
+const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+ x(())
+}
+
+const _: () = assert!(need_const_closure(Tr::a) == 42);
+
+fn main() {}
--- /dev/null
+// edition:2018
+// aux-build:edition-lint-infer-outlives-macro.rs
+// run-rustfix
+
+#![deny(explicit_outlives_requirements)]
+#![allow(dead_code)]
+
+#[macro_use]
+extern crate edition_lint_infer_outlives_macro;
+
+// Test that the lint does not fire if the predicate is from the local crate,
+// but all the bounds are from an external macro.
+macro_rules! make_foo {
+ ($a:tt) => {
+ struct Foo<$a, 'b: $a> {
+ foo: &$a &'b (),
+ }
+
+ struct FooWhere<$a, 'b> where 'b: $a {
+ foo: &$a &'b (),
+ }
+ }
+}
+
+gimme_a! {make_foo!}
+
+struct Bar<'a, 'b> {
+ //~^ ERROR: outlives requirements can be inferred
+ bar: &'a &'b (),
+}
+
+struct BarWhere<'a, 'b> {
+ //~^ ERROR: outlives requirements can be inferred
+ bar: &'a &'b (),
+}
+
+// Test that the lint *does* fire if the predicate is contained in a local macro.
+mod everything_inside {
+ macro_rules! m {
+ ('b: 'a) => {
+ struct Foo<'a, 'b>(&'a &'b ());
+ //~^ ERROR: outlives requirements can be inferred
+ struct Bar<'a, 'b>(&'a &'b ()) ;
+ //~^ ERROR: outlives requirements can be inferred
+ struct Baz<'a, 'b>(&'a &'b ()) where (): Sized, ;
+ //~^ ERROR: outlives requirements can be inferred
+ };
+ }
+ m!('b: 'a);
+}
+
+mod inner_lifetime_outside_colon_inside {
+ macro_rules! m {
+ ($b:lifetime: 'a) => {
+ struct Foo<'a, $b>(&'a &$b ());
+ //~^ ERROR: outlives requirements can be inferred
+ struct Bar<'a, $b>(&'a &$b ()) ;
+ //~^ ERROR: outlives requirements can be inferred
+ struct Baz<'a, $b>(&'a &$b ()) where (): Sized, ;
+ //~^ ERROR: outlives requirements can be inferred
+ }
+ }
+ m!('b: 'a);
+}
+
+mod outer_lifetime_outside_colon_inside {
+ macro_rules! m {
+ ('b: $a:lifetime) => {
+ struct Foo<$a, 'b: $a>(&$a &'b ());
+ struct Bar<$a, 'b>(&$a &'b ()) where 'b: $a;
+ struct Baz<$a, 'b>(&$a &'b ()) where (): Sized, 'b: $a;
+ }
+ }
+ m!('b: 'a);
+}
+
+mod both_lifetimes_outside_colon_inside {
+ macro_rules! m {
+ ($b:lifetime: $a:lifetime) => {
+ struct Foo<$a, $b: $a>(&$a &$b ());
+ struct Bar<$a, $b>(&$a &$b ()) where $b: $a;
+ struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b: $a;
+ }
+ }
+ m!('b: 'a);
+}
+
+mod everything_outside {
+ macro_rules! m {
+ ($b:lifetime $colon:tt $a:lifetime) => {
+ struct Foo<$a, $b $colon $a>(&$a &$b ());
+ struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+ struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+ }
+ }
+ m!('b: 'a);
+}
+
+mod everything_outside_with_tt_inner {
+ macro_rules! m {
+ ($b:tt $colon:tt $a:lifetime) => {
+ struct Foo<$a, $b $colon $a>(&$a &$b ());
+ struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+ struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+ }
+ }
+ m!('b: 'a);
+}
+
+// FIXME: These should be consistent.
+mod everything_outside_with_tt_outer {
+ macro_rules! m {
+ ($b:lifetime $colon:tt $a:tt) => {
+ struct Foo<$a, $b >(&$a &$b ());
+ //~^ ERROR: outlives requirements can be inferred
+ struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+ struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+ }
+ }
+ m!('b: 'a);
+}
+
+mod everything_outside_with_tt_both {
+ macro_rules! m {
+ ($b:tt $colon:tt $a:tt) => {
+ struct Foo<$a, $b >(&$a &$b ());
+ //~^ ERROR: outlives requirements can be inferred
+ struct Bar<$a, $b>(&$a &$b ()) where ;
+ //~^ ERROR: outlives requirements can be inferred
+ struct Baz<$a, $b>(&$a &$b ()) where (): Sized, ;
+ //~^ ERROR: outlives requirements can be inferred
+ }
+ }
+ m!('b: 'a);
+}
+
+fn main() {}
// edition:2018
// aux-build:edition-lint-infer-outlives-macro.rs
-
-// Test that the lint does not fire if the where predicate
-// is from the local crate, but all the bounds are from an
-// external macro.
+// run-rustfix
#![deny(explicit_outlives_requirements)]
+#![allow(dead_code)]
#[macro_use]
extern crate edition_lint_infer_outlives_macro;
+// Test that the lint does not fire if the predicate is from the local crate,
+// but all the bounds are from an external macro.
macro_rules! make_foo {
($a:tt) => {
- struct Foo<$a, 'b> where 'b: $a {
+ struct Foo<$a, 'b: $a> {
+ foo: &$a &'b (),
+ }
+
+ struct FooWhere<$a, 'b> where 'b: $a {
foo: &$a &'b (),
}
}
bar: &'a &'b (),
}
+struct BarWhere<'a, 'b> where 'b: 'a {
+ //~^ ERROR: outlives requirements can be inferred
+ bar: &'a &'b (),
+}
+
+// Test that the lint *does* fire if the predicate is contained in a local macro.
+mod everything_inside {
+ macro_rules! m {
+ ('b: 'a) => {
+ struct Foo<'a, 'b: 'a>(&'a &'b ());
+ //~^ ERROR: outlives requirements can be inferred
+ struct Bar<'a, 'b>(&'a &'b ()) where 'b: 'a;
+ //~^ ERROR: outlives requirements can be inferred
+ struct Baz<'a, 'b>(&'a &'b ()) where (): Sized, 'b: 'a;
+ //~^ ERROR: outlives requirements can be inferred
+ };
+ }
+ m!('b: 'a);
+}
+
+mod inner_lifetime_outside_colon_inside {
+ macro_rules! m {
+ ($b:lifetime: 'a) => {
+ struct Foo<'a, $b: 'a>(&'a &$b ());
+ //~^ ERROR: outlives requirements can be inferred
+ struct Bar<'a, $b>(&'a &$b ()) where $b: 'a;
+ //~^ ERROR: outlives requirements can be inferred
+ struct Baz<'a, $b>(&'a &$b ()) where (): Sized, $b: 'a;
+ //~^ ERROR: outlives requirements can be inferred
+ }
+ }
+ m!('b: 'a);
+}
+
+mod outer_lifetime_outside_colon_inside {
+ macro_rules! m {
+ ('b: $a:lifetime) => {
+ struct Foo<$a, 'b: $a>(&$a &'b ());
+ struct Bar<$a, 'b>(&$a &'b ()) where 'b: $a;
+ struct Baz<$a, 'b>(&$a &'b ()) where (): Sized, 'b: $a;
+ }
+ }
+ m!('b: 'a);
+}
+
+mod both_lifetimes_outside_colon_inside {
+ macro_rules! m {
+ ($b:lifetime: $a:lifetime) => {
+ struct Foo<$a, $b: $a>(&$a &$b ());
+ struct Bar<$a, $b>(&$a &$b ()) where $b: $a;
+ struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b: $a;
+ }
+ }
+ m!('b: 'a);
+}
+
+mod everything_outside {
+ macro_rules! m {
+ ($b:lifetime $colon:tt $a:lifetime) => {
+ struct Foo<$a, $b $colon $a>(&$a &$b ());
+ struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+ struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+ }
+ }
+ m!('b: 'a);
+}
+
+mod everything_outside_with_tt_inner {
+ macro_rules! m {
+ ($b:tt $colon:tt $a:lifetime) => {
+ struct Foo<$a, $b $colon $a>(&$a &$b ());
+ struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+ struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+ }
+ }
+ m!('b: 'a);
+}
+
+// FIXME: These should be consistent.
+mod everything_outside_with_tt_outer {
+ macro_rules! m {
+ ($b:lifetime $colon:tt $a:tt) => {
+ struct Foo<$a, $b $colon $a>(&$a &$b ());
+ //~^ ERROR: outlives requirements can be inferred
+ struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+ struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+ }
+ }
+ m!('b: 'a);
+}
+
+mod everything_outside_with_tt_both {
+ macro_rules! m {
+ ($b:tt $colon:tt $a:tt) => {
+ struct Foo<$a, $b $colon $a>(&$a &$b ());
+ //~^ ERROR: outlives requirements can be inferred
+ struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+ //~^ ERROR: outlives requirements can be inferred
+ struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+ //~^ ERROR: outlives requirements can be inferred
+ }
+ }
+ m!('b: 'a);
+}
+
fn main() {}
error: outlives requirements can be inferred
- --> $DIR/edition-lint-infer-outlives-macro.rs:23:18
+ --> $DIR/edition-lint-infer-outlives-macro.rs:27:18
|
LL | struct Bar<'a, 'b: 'a> {
| ^^^^ help: remove this bound
|
note: the lint level is defined here
- --> $DIR/edition-lint-infer-outlives-macro.rs:8:9
+ --> $DIR/edition-lint-infer-outlives-macro.rs:5:9
|
LL | #![deny(explicit_outlives_requirements)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error: outlives requirements can be inferred
+ --> $DIR/edition-lint-infer-outlives-macro.rs:32:24
+ |
+LL | struct BarWhere<'a, 'b> where 'b: 'a {
+ | ^^^^^^^^^^^^^ help: remove this bound
+
+error: outlives requirements can be inferred
+ --> $DIR/edition-lint-infer-outlives-macro.rs:41:30
+ |
+LL | struct Foo<'a, 'b: 'a>(&'a &'b ());
+ | ^^^^ help: remove this bound
+...
+LL | m!('b: 'a);
+ | ---------- in this macro invocation
+ |
+ = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+ --> $DIR/edition-lint-infer-outlives-macro.rs:43:44
+ |
+LL | struct Bar<'a, 'b>(&'a &'b ()) where 'b: 'a;
+ | ^^^^^^^^^^^^ help: remove this bound
+...
+LL | m!('b: 'a);
+ | ---------- in this macro invocation
+ |
+ = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+ --> $DIR/edition-lint-infer-outlives-macro.rs:45:61
+ |
+LL | struct Baz<'a, 'b>(&'a &'b ()) where (): Sized, 'b: 'a;
+ | ^^^^^^ help: remove this bound
+...
+LL | m!('b: 'a);
+ | ---------- in this macro invocation
+ |
+ = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+ --> $DIR/edition-lint-infer-outlives-macro.rs:55:30
+ |
+LL | struct Foo<'a, $b: 'a>(&'a &$b ());
+ | ^^^^ help: remove this bound
+...
+LL | m!('b: 'a);
+ | ---------- in this macro invocation
+ |
+ = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+ --> $DIR/edition-lint-infer-outlives-macro.rs:57:44
+ |
+LL | struct Bar<'a, $b>(&'a &$b ()) where $b: 'a;
+ | ^^^^^^^^^^^^ help: remove this bound
+...
+LL | m!('b: 'a);
+ | ---------- in this macro invocation
+ |
+ = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+ --> $DIR/edition-lint-infer-outlives-macro.rs:59:61
+ |
+LL | struct Baz<'a, $b>(&'a &$b ()) where (): Sized, $b: 'a;
+ | ^^^^^^ help: remove this bound
+...
+LL | m!('b: 'a);
+ | ---------- in this macro invocation
+ |
+ = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+ --> $DIR/edition-lint-infer-outlives-macro.rs:114:31
+ |
+LL | struct Foo<$a, $b $colon $a>(&$a &$b ());
+ | ^^^^^^^^^ help: remove this bound
+
+error: outlives requirements can be inferred
+ --> $DIR/edition-lint-infer-outlives-macro.rs:126:31
+ |
+LL | struct Foo<$a, $b $colon $a>(&$a &$b ());
+ | ^^^^^^^^^ help: remove this bound
+
+error: outlives requirements can be inferred
+ --> $DIR/edition-lint-infer-outlives-macro.rs:128:50
+ |
+LL | struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+ | ^^^^^^^^^^^^ help: remove this bound
+
+error: outlives requirements can be inferred
+ --> $DIR/edition-lint-infer-outlives-macro.rs:130:61
+ |
+LL | struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+ | ^^^^^^^^^^^^ help: remove this bound
+
+error: aborting due to 12 previous errors
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:53:24
|
-LL | fn deref_mut_field1(x: Own<Point>) {
- | - help: consider changing this to be mutable: `mut x`
LL | let __isize = &mut x.y;
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn deref_mut_field1(mut x: Own<Point>) {
+ | +++
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:65:10
|
-LL | fn deref_extend_mut_field1(x: &Own<Point>) -> &mut isize {
- | ----------- help: consider changing this to be a mutable reference: `&mut Own<Point>`
LL | &mut x.y
| ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn deref_extend_mut_field1(x: &mut Own<Point>) -> &mut isize {
+ | ~~~~~~~~~~~~~~~
error[E0499]: cannot borrow `*x` as mutable more than once at a time
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:78:19
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:88:5
|
-LL | fn assign_field1<'a>(x: Own<Point>) {
- | - help: consider changing this to be mutable: `mut x`
LL | x.y = 3;
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn assign_field1<'a>(mut x: Own<Point>) {
+ | +++
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:92:5
|
-LL | fn assign_field2<'a>(x: &'a Own<Point>) {
- | -------------- help: consider changing this to be a mutable reference: `&'a mut Own<Point>`
LL | x.y = 3;
| ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn assign_field2<'a>(x: &'a mut Own<Point>) {
+ | ~~~~~~~~~~~~~~~~~~
error[E0499]: cannot borrow `*x` as mutable more than once at a time
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:101:5
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:109:5
|
-LL | fn deref_mut_method1(x: Own<Point>) {
- | - help: consider changing this to be mutable: `mut x`
LL | x.set(0, 0);
| ^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn deref_mut_method1(mut x: Own<Point>) {
+ | +++
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:121:5
|
-LL | fn deref_extend_mut_method1(x: &Own<Point>) -> &mut isize {
- | ----------- help: consider changing this to be a mutable reference: `&mut Own<Point>`
LL | x.y_mut()
| ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn deref_extend_mut_method1(x: &mut Own<Point>) -> &mut isize {
+ | ~~~~~~~~~~~~~~~
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:129:6
|
-LL | fn assign_method1<'a>(x: Own<Point>) {
- | - help: consider changing this to be mutable: `mut x`
LL | *x.y_mut() = 3;
| ^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn assign_method1<'a>(mut x: Own<Point>) {
+ | +++
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:133:6
|
-LL | fn assign_method2<'a>(x: &'a Own<Point>) {
- | -------------- help: consider changing this to be a mutable reference: `&'a mut Own<Point>`
LL | *x.y_mut() = 3;
| ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn assign_method2<'a>(x: &'a mut Own<Point>) {
+ | ~~~~~~~~~~~~~~~~~~
error: aborting due to 10 previous errors
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:29:25
|
-LL | fn deref_mut1(x: Own<isize>) {
- | - help: consider changing this to be mutable: `mut x`
LL | let __isize = &mut *x;
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn deref_mut1(mut x: Own<isize>) {
+ | +++
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:41:11
|
-LL | fn deref_extend_mut1<'a>(x: &'a Own<isize>) -> &'a mut isize {
- | -------------- help: consider changing this to be a mutable reference: `&'a mut Own<isize>`
LL | &mut **x
| ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn deref_extend_mut1<'a>(x: &'a mut Own<isize>) -> &'a mut isize {
+ | ~~~~~~~~~~~~~~~~~~
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:49:6
|
-LL | fn assign1<'a>(x: Own<isize>) {
- | - help: consider changing this to be mutable: `mut x`
LL | *x = 3;
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn assign1<'a>(mut x: Own<isize>) {
+ | +++
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:53:6
|
-LL | fn assign2<'a>(x: &'a Own<isize>) {
- | -------------- help: consider changing this to be a mutable reference: `&'a mut Own<isize>`
LL | **x = 3;
| ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn assign2<'a>(x: &'a mut Own<isize>) {
+ | ~~~~~~~~~~~~~~~~~~
error: aborting due to 4 previous errors
error[E0596]: cannot borrow `*f` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:25:5
|
-LL | fn test2<F>(f: &F) where F: FnMut() {
- | -- help: consider changing this to be a mutable reference: `&mut F`
LL | (*f)();
| ^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn test2<F>(f: &mut F) where F: FnMut() {
+ | ~~~~~~
error[E0596]: cannot borrow `f.f` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:34:5
|
-LL | fn test4(f: &Test) {
- | ----- help: consider changing this to be a mutable reference: `&mut Test<'_>`
LL | f.f.call_mut(())
| ^^^^^^^^^^^^^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn test4(f: &mut Test<'_>) {
+ | ~~~~~~~~~~~~~
error[E0507]: cannot move out of `f`, a captured variable in an `FnMut` closure
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:57:13
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-call-method-from-mut-aliasable.rs:17:5
|
-LL | fn b(x: &Foo) {
- | ---- help: consider changing this to be a mutable reference: `&mut Foo`
-LL | x.f();
LL | x.h();
| ^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn b(x: &mut Foo) {
+ | ~~~~~~~~
error: aborting due to previous error
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-fn-in-const-b.rs:7:9
|
-LL | fn broken(x: &Vec<String>) {
- | ------------ help: consider changing this to be a mutable reference: `&mut Vec<String>`
LL | x.push(format!("this is broken"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn broken(x: &mut Vec<String>) {
+ | ~~~~~~~~~~~~~~~~
error: aborting due to previous error
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-object-mutability.rs:8:5
|
-LL | fn borrowed_receiver(x: &dyn Foo) {
- | -------- help: consider changing this to be a mutable reference: `&mut dyn Foo`
-LL | x.borrowed();
LL | x.borrowed_mut();
| ^^^^^^^^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn borrowed_receiver(x: &mut dyn Foo) {
+ | ~~~~~~~~~~~~
error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable
--> $DIR/borrowck-object-mutability.rs:18:5
|
-LL | fn owned_receiver(x: Box<dyn Foo>) {
- | - help: consider changing this to be mutable: `mut x`
-LL | x.borrowed();
LL | x.borrowed_mut();
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn owned_receiver(mut x: Box<dyn Foo>) {
+ | +++
error: aborting due to 2 previous errors
fn main() {
foo(Some(42), 2);
- foo(Some(42), 2, ""); //~ ERROR this function takes
+ foo(Some(42), 2, ""); //~ ERROR function takes
bar("", ""); //~ ERROR mismatched types
bar(1, 2);
- bar(1, 2, 3); //~ ERROR this function takes
+ bar(1, 2, 3); //~ ERROR function takes
}
fn main() {
let _: Result<(), String> = Ok(); //~ ERROR this enum variant takes
- foo(); //~ ERROR this function takes
- foo(()); //~ ERROR this function takes
- bar(); //~ ERROR this function takes
- S.baz(); //~ ERROR this function takes
- S.generic::<()>(); //~ ERROR this function takes
+ foo(); //~ ERROR function takes
+ foo(()); //~ ERROR function takes
+ bar(); //~ ERROR function takes
+ S.baz(); //~ ERROR this method takes
+ S.generic::<()>(); //~ ERROR this method takes
}
LL | bar(());
| ~~~~
-error[E0061]: this function takes 1 argument but 0 arguments were supplied
+error[E0061]: this method takes 1 argument but 0 arguments were supplied
--> $DIR/missing-unit-argument.rs:15:7
|
LL | S.baz();
LL | S.baz(());
| ~~~~
-error[E0061]: this function takes 1 argument but 0 arguments were supplied
+error[E0061]: this method takes 1 argument but 0 arguments were supplied
--> $DIR/missing-unit-argument.rs:16:7
|
LL | S.generic::<()>();
error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference
--> $DIR/mut-arg-hint.rs:3:9
|
-LL | fn foo(mut a: &String) {
- | ------- help: consider changing this to be a mutable reference: `&mut String`
LL | a.push_str("bar");
| ^^^^^^^^^^^^^^^^^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn foo(mut a: &mut String) {
+ | ~~~~~~~~~~~
error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference
--> $DIR/mut-arg-hint.rs:8:5
|
-LL | pub fn foo<'a>(mut a: &'a String) {
- | ---------- help: consider changing this to be a mutable reference: `&'a mut String`
LL | a.push_str("foo");
| ^^^^^^^^^^^^^^^^^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | pub fn foo<'a>(mut a: &'a mut String) {
+ | ~~~~~~~~~~~~~~
error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference
--> $DIR/mut-arg-hint.rs:15:9
|
-LL | pub fn foo(mut a: &String) {
- | ------- help: consider changing this to be a mutable reference: `&mut String`
LL | a.push_str("foo");
| ^^^^^^^^^^^^^^^^^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | pub fn foo(mut a: &mut String) {
+ | ~~~~~~~~~~~
error: aborting due to 3 previous errors
}
}
-impl<B: ?Sized> Display for Cow<'_, B> { //~ ERROR: the trait bound `B: Clone` is not satisfied [E0277]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { //~ ERROR: the trait bound `B: Clone` is not satisfied [E0277]
+impl<B: ?Sized> Display for Cow<'_, B> {
+ //~^ ERROR: the trait bound `B: Clone` is not satisfied [E0277]
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ //~^ ERROR: the trait bound `B: Clone` is not satisfied [E0277]
write!(f, "foo")
}
}
error[E0277]: the trait bound `B: Clone` is not satisfied
- --> $DIR/issue-79224.rs:18:1
+ --> $DIR/issue-79224.rs:18:17
|
-LL | / impl<B: ?Sized> Display for Cow<'_, B> {
-LL | | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-LL | | write!(f, "foo")
-LL | | }
-LL | | }
- | |_^ the trait `Clone` is not implemented for `B`
+LL | impl<B: ?Sized> Display for Cow<'_, B> {
+ | ^^^^^^^ the trait `Clone` is not implemented for `B`
|
= note: required for `B` to implement `ToOwned`
help: consider further restricting this bound
| +++++++++++++++++++
error[E0277]: the trait bound `B: Clone` is not satisfied
- --> $DIR/issue-79224.rs:19:5
+ --> $DIR/issue-79224.rs:20:12
|
-LL | / fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-LL | | write!(f, "foo")
-LL | | }
- | |_____^ the trait `Clone` is not implemented for `B`
+LL | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ | ^^^^^ the trait `Clone` is not implemented for `B`
|
= note: required for `B` to implement `ToOwned`
help: consider further restricting this bound
error: aborting due to 20 previous errors
-Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0544, E0546, E0547, E0549.
+Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0544, E0546, E0547, E0549, E0711.
For more information about an error, try `rustc --explain E0539`.
ast-stats-1 - Ident 440 ( 5.9%) 5
ast-stats-1 PathSegment 720 ( 9.7%) 30 24
ast-stats-1 Ty 896 (12.1%) 14 64
-ast-stats-1 - Rptr 64 ( 0.9%) 1
ast-stats-1 - Ptr 64 ( 0.9%) 1
+ast-stats-1 - Ref 64 ( 0.9%) 1
ast-stats-1 - ImplicitSelf 128 ( 1.7%) 2
ast-stats-1 - Path 640 ( 8.6%) 10
ast-stats-1 Item 1_656 (22.3%) 9 184
ast-stats-2 - Block 216 ( 2.7%) 3
ast-stats-2 PathSegment 792 ( 9.8%) 33 24
ast-stats-2 Ty 896 (11.0%) 14 64
-ast-stats-2 - Rptr 64 ( 0.8%) 1
ast-stats-2 - Ptr 64 ( 0.8%) 1
+ast-stats-2 - Ref 64 ( 0.8%) 1
ast-stats-2 - ImplicitSelf 128 ( 1.6%) 2
ast-stats-2 - Path 640 ( 7.9%) 10
ast-stats-2 Item 2_024 (25.0%) 11 184
hir-stats Generics 560 ( 6.2%) 10 56
hir-stats Ty 720 ( 8.0%) 15 48
hir-stats - Ptr 48 ( 0.5%) 1
-hir-stats - Rptr 48 ( 0.5%) 1
+hir-stats - Ref 48 ( 0.5%) 1
hir-stats - Path 624 ( 6.9%) 13
hir-stats Expr 768 ( 8.5%) 12 64
hir-stats - Path 64 ( 0.7%) 1
let _: Option<(i32, bool)> = Some(1, 2);
//~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied
int_bool(1, 2);
- //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+ //~^ ERROR function takes 1 argument but 2 arguments were supplied
let _: Option<(i8,)> = Some();
//~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
fn main() {
let _: Result<(i32, i8), ()> = Ok((1, 2));
- //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied
+ //~^ ERROR enum variant takes 1 argument but 2 arguments were supplied
let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi"));
- //~^ ERROR this enum variant takes 1 argument but 3 arguments were supplied
+ //~^ ERROR enum variant takes 1 argument but 3 arguments were supplied
let _: Option<()> = Some(());
- //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
+ //~^ ERROR enum variant takes 1 argument but 0 arguments were supplied
let _: Option<(i32,)> = Some((3,));
//~^ ERROR mismatched types
let _: Option<(i32,)> = Some((3,));
//~^ ERROR mismatched types
- two_ints((1, 2)); //~ ERROR this function takes 1 argument
+ two_ints((1, 2)); //~ ERROR function takes 1 argument
- with_generic((3, 4)); //~ ERROR this function takes 1 argument
+ with_generic((3, 4)); //~ ERROR function takes 1 argument
}
fn two_ints(_: (i32, i32)) {
fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
if false {
// test generics/bound handling
- with_generic((a, b)); //~ ERROR this function takes 1 argument
+ with_generic((a, b)); //~ ERROR function takes 1 argument
}
}
fn main() {
let _: Result<(i32, i8), ()> = Ok(1, 2);
- //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied
+ //~^ ERROR enum variant takes 1 argument but 2 arguments were supplied
let _: Option<(i32, i8, &'static str)> = Some(1, 2, "hi");
- //~^ ERROR this enum variant takes 1 argument but 3 arguments were supplied
+ //~^ ERROR enum variant takes 1 argument but 3 arguments were supplied
let _: Option<()> = Some();
- //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
+ //~^ ERROR enum variant takes 1 argument but 0 arguments were supplied
let _: Option<(i32,)> = Some(3);
//~^ ERROR mismatched types
let _: Option<(i32,)> = Some((3));
//~^ ERROR mismatched types
- two_ints(1, 2); //~ ERROR this function takes 1 argument
+ two_ints(1, 2); //~ ERROR function takes 1 argument
- with_generic(3, 4); //~ ERROR this function takes 1 argument
+ with_generic(3, 4); //~ ERROR function takes 1 argument
}
fn two_ints(_: (i32, i32)) {
fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
if false {
// test generics/bound handling
- with_generic(a, b); //~ ERROR this function takes 1 argument
+ with_generic(a, b); //~ ERROR function takes 1 argument
}
}
-error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied
+error[E0061]: enum variant takes 1 argument but 2 arguments were supplied
--> $DIR/args-instead-of-tuple.rs:7:36
|
LL | let _: Result<(i32, i8), ()> = Ok(1, 2);
LL | let _: Result<(i32, i8), ()> = Ok((1, 2));
| + +
-error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied
+error[E0061]: enum variant takes 1 argument but 3 arguments were supplied
--> $DIR/args-instead-of-tuple.rs:9:46
|
LL | let _: Option<(i32, i8, &'static str)> = Some(1, 2, "hi");
LL | let _: Option<(i32,)> = Some((3,));
| +
-error[E0061]: this function takes 1 argument but 2 arguments were supplied
+error[E0061]: function takes 1 argument but 2 arguments were supplied
--> $DIR/args-instead-of-tuple.rs:20:5
|
LL | two_ints(1, 2);
LL | two_ints((1, 2));
| + +
-error[E0061]: this function takes 1 argument but 2 arguments were supplied
+error[E0061]: function takes 1 argument but 2 arguments were supplied
--> $DIR/args-instead-of-tuple.rs:22:5
|
LL | with_generic(3, 4);
LL | with_generic((3, 4));
| + +
-error[E0061]: this function takes 1 argument but 2 arguments were supplied
+error[E0061]: function takes 1 argument but 2 arguments were supplied
--> $DIR/args-instead-of-tuple.rs:31:9
|
LL | with_generic(a, b);
--- /dev/null
+fn main() {
+ let _f: f32 = 0xAAf32;
+ //~^ ERROR mismatched types
+ //~| HELP rewrite this
+
+ let _f: f32 = 0xAB_f32;
+ //~^ ERROR mismatched types
+ //~| HELP rewrite this
+
+ let _f: f64 = 0xFF_f64;
+ //~^ ERROR mismatched types
+ //~| HELP rewrite this
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/bad-hex-float-lit.rs:2:19
+ |
+LL | let _f: f32 = 0xAAf32;
+ | --- ^^^^^^^ expected `f32`, found integer
+ | |
+ | expected due to this
+ |
+help: rewrite this as a decimal floating point literal, or use `as` to turn a hex literal into a float
+ |
+LL | let _f: f32 = 0xAA as f32;
+ | ~~~~~~~~~~~
+LL | let _f: f32 = 170_f32;
+ | ~~~~~~~
+
+error[E0308]: mismatched types
+ --> $DIR/bad-hex-float-lit.rs:6:19
+ |
+LL | let _f: f32 = 0xAB_f32;
+ | --- ^^^^^^^^ expected `f32`, found integer
+ | |
+ | expected due to this
+ |
+help: rewrite this as a decimal floating point literal, or use `as` to turn a hex literal into a float
+ |
+LL | let _f: f32 = 0xAB as f32;
+ | ~~~~~~~~~~~
+LL | let _f: f32 = 171_f32;
+ | ~~~~~~~
+
+error[E0308]: mismatched types
+ --> $DIR/bad-hex-float-lit.rs:10:19
+ |
+LL | let _f: f64 = 0xFF_f64;
+ | --- ^^^^^^^^ expected `f64`, found integer
+ | |
+ | expected due to this
+ |
+help: rewrite this as a decimal floating point literal, or use `as` to turn a hex literal into a float
+ |
+LL | let _f: f64 = 0xFF as f64;
+ | ~~~~~~~~~~~
+LL | let _f: f64 = 255_f64;
+ | ~~~~~~~
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
fn test(t: &dyn Iterator<Item=&u64>) -> u64 {
- t.min().unwrap() //~ ERROR the `min` method cannot be invoked on a trait object
+ t.min().unwrap() //~ ERROR the `min` method cannot be invoked on `&dyn Iterator<Item = &u64>`
}
fn main() {
-error: the `min` method cannot be invoked on a trait object
+error: the `min` method cannot be invoked on `&dyn Iterator<Item = &u64>`
--> $DIR/imm-ref-trait-object.rs:2:8
|
LL | t.min().unwrap()
| ^^^
- --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
- = note: this has a `Sized` requirement
+help: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
|
- = note: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
+LL | fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
+ | +++
error: aborting due to previous error
//~| ERROR missing lifetime specifier
}
+// This must not err, as the `&` actually resolves to `'a`.
+fn resolved_anonymous<'a, T>(f: impl Fn(&'a str) -> &T) {
+ f("f")
+}
+
fn main() {}
// The purpose of this test is not to validate the output of the compiler.
// Instead, it ensures the suggestion is generated without performing an arithmetic overflow.
+struct S;
+impl S {
+ fn foo(&self) {}
+}
fn main() {
- let x = not_found; //~ ERROR cannot find value `not_found` in this scope
- simd_gt::<()>(x);
+ let x = S;
+ foo::<()>(x);
//~^ ERROR this associated function takes 0 generic arguments but 1 generic argument was supplied
- //~| ERROR cannot find function `simd_gt` in this scope
+ //~| ERROR cannot find function `foo` in this scope
}
-error[E0425]: cannot find value `not_found` in this scope
- --> $DIR/issue-104287.rs:5:13
- |
-LL | let x = not_found;
- | ^^^^^^^^^ not found in this scope
-
error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
- --> $DIR/issue-104287.rs:6:5
+ --> $DIR/issue-104287.rs:10:5
|
-LL | simd_gt::<()>(x);
- | ^^^^^^^------ help: remove these generics
+LL | foo::<()>(x);
+ | ^^^------ help: remove these generics
| |
| expected 0 generic arguments
+ |
+note: associated function defined here, with 0 generic parameters
+ --> $DIR/issue-104287.rs:6:8
+ |
+LL | fn foo(&self) {}
+ | ^^^
-error[E0425]: cannot find function `simd_gt` in this scope
- --> $DIR/issue-104287.rs:6:5
+error[E0425]: cannot find function `foo` in this scope
+ --> $DIR/issue-104287.rs:10:5
|
-LL | simd_gt::<()>(x);
- | ^^^^^^^ not found in this scope
+LL | foo::<()>(x);
+ | ^^^ not found in this scope
|
-help: use the `.` operator to call the method `SimdPartialOrd::simd_gt` on `[type error]`
+help: use the `.` operator to call the method `foo` on `&S`
|
-LL - simd_gt::<()>(x);
-LL + x.simd_gt();
+LL - foo::<()>(x);
+LL + x.foo();
|
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
Some errors have detailed explanations: E0107, E0425.
For more information about an error, try `rustc --explain E0107`.
--- /dev/null
+fn main() {
+ let mut buf = [0u8; 50];
+ let mut bref = buf.as_slice();
+ foo(&mut bref);
+ //~^ ERROR 4:9: 4:18: the trait bound `&[u8]: std::io::Write` is not satisfied [E0277]
+}
+
+fn foo(_: &mut impl std::io::Write) {}
--- /dev/null
+error[E0277]: the trait bound `&[u8]: std::io::Write` is not satisfied
+ --> $DIR/issue-105645.rs:4:9
+ |
+LL | foo(&mut bref);
+ | --- ^^^^^^^^^ the trait `std::io::Write` is not implemented for `&[u8]`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `std::io::Write` is implemented for `&mut [u8]`
+note: required by a bound in `foo`
+ --> $DIR/issue-105645.rs:8:21
+ |
+LL | fn foo(_: &mut impl std::io::Write) {}
+ | ^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#[derive(Clone)]
+struct S;
+
+// without Clone
+struct T;
+
+fn foo(_: S) {}
+
+fn test1() {
+ let s = &S;
+ foo(s); //~ ERROR mismatched types
+}
+
+fn bar(_: T) {}
+fn test2() {
+ let t = &T;
+ bar(t); //~ ERROR mismatched types
+}
+
+fn main() {
+ test1();
+ test2();
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-106443-sugg-clone-for-arg.rs:11:9
+ |
+LL | foo(s);
+ | --- ^ expected struct `S`, found `&S`
+ | |
+ | arguments to this function are incorrect
+ |
+note: function defined here
+ --> $DIR/issue-106443-sugg-clone-for-arg.rs:7:4
+ |
+LL | fn foo(_: S) {}
+ | ^^^ ----
+help: consider using clone here
+ |
+LL | foo(s.clone());
+ | ++++++++
+
+error[E0308]: mismatched types
+ --> $DIR/issue-106443-sugg-clone-for-arg.rs:17:9
+ |
+LL | bar(t);
+ | --- ^ expected struct `T`, found `&T`
+ | |
+ | arguments to this function are incorrect
+ |
+note: function defined here
+ --> $DIR/issue-106443-sugg-clone-for-arg.rs:14:4
+ |
+LL | fn bar(_: T) {}
+ | ^^^ ----
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#[derive(Clone)]
+struct S;
+
+trait X {}
+
+impl X for S {}
+
+fn foo<T: X>(_: T) {}
+fn bar<T: X>(s: &T) {
+ foo(s); //~ ERROR the trait bound `&T: X` is not satisfied
+}
+
+fn bar_with_clone<T: X + Clone>(s: &T) {
+ foo(s); //~ ERROR the trait bound `&T: X` is not satisfied
+}
+
+fn main() {
+ let s = &S;
+ bar(s);
+}
--- /dev/null
+error[E0277]: the trait bound `&T: X` is not satisfied
+ --> $DIR/issue-106443-sugg-clone-for-bound.rs:10:9
+ |
+LL | foo(s);
+ | ^ the trait `X` is not implemented for `&T`
+ |
+help: consider further restricting this bound
+ |
+LL | fn bar<T: X + Clone>(s: &T) {
+ | +++++++
+help: consider using clone here
+ |
+LL | foo(s.clone());
+ | ++++++++
+
+error[E0277]: the trait bound `&T: X` is not satisfied
+ --> $DIR/issue-106443-sugg-clone-for-bound.rs:14:9
+ |
+LL | foo(s);
+ | ^ the trait `X` is not implemented for `&T`
+ |
+help: consider using clone here
+ |
+LL | foo(s.clone());
+ | ++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
error[E0594]: cannot assign to `*input`, which is behind a `&` reference
--> $DIR/issue-68049-2.rs:9:7
|
-LL | fn example(&self, input: &i32); // should suggest here
- | ---- help: consider changing that to be a mutable reference: `&mut i32`
-...
LL | *input = self.0;
| ^^^^^^^^^^^^^^^ `input` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing that to be a mutable reference
+ |
+LL | fn example(&self, input: &mut i32); // should suggest here
+ | ~~~~~~~~
error[E0594]: cannot assign to `self.0`, which is behind a `&` reference
--> $DIR/issue-68049-2.rs:17:5
|
-LL | fn example(&self, input: &i32); // should suggest here
- | ----- help: consider changing that to be a mutable reference: `&mut self`
-...
LL | self.0 += *input;
| ^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing that to be a mutable reference
+ |
+LL | fn example(&mut self, input: &i32); // should suggest here
+ | ~~~~~~~~~
error: aborting due to 2 previous errors
LL | Unit,
| ---- enum variant `Alias::Unit` defined here
...
-LL | Alias::
- | ______^
- | | _____|
- | ||
+LL | // Alias::
LL | || Unit();
| ||________^_- call expression requires function
| |________|
--- /dev/null
+fn as_ref() -> Option<Vec<u8>> {
+ None
+}
+struct Type {
+ option: Option<Vec<u8>>
+}
+trait Trait {
+ fn foo(&self) -> Vec<u8>;
+}
+impl Trait for Option<Vec<u8>> {
+ fn foo(&self) -> Vec<u8> {
+ vec![1, 2, 3]
+ }
+}
+
+impl Type {
+ fn method(&self) -> Option<Vec<u8>> {
+ self.option..as_ref().map(|x| x)
+ //~^ ERROR E0308
+ }
+ fn method2(&self) -> &u8 {
+ self.option..foo().get(0)
+ //~^ ERROR E0425
+ //~| ERROR E0308
+ }
+}
+
+fn main() {
+ let _ = Type { option: None }.method();
+}
--- /dev/null
+error[E0425]: cannot find function `foo` in this scope
+ --> $DIR/method-access-to-range-literal-typo.rs:22:22
+ |
+LL | self.option..foo().get(0)
+ | ^^^ not found in this scope
+ |
+help: you might have meant to write `.` instead of `..`
+ |
+LL - self.option..foo().get(0)
+LL + self.option.foo().get(0)
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/method-access-to-range-literal-typo.rs:18:9
+ |
+LL | fn method(&self) -> Option<Vec<u8>> {
+ | --------------- expected `Option<Vec<u8>>` because of return type
+LL | self.option..as_ref().map(|x| x)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found struct `Range`
+ |
+ = note: expected enum `Option<_>`
+ found struct `std::ops::Range<Option<_>>`
+help: you likely meant to write a method call instead of a range
+ |
+LL - self.option..as_ref().map(|x| x)
+LL + self.option.as_ref().map(|x| x)
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/method-access-to-range-literal-typo.rs:22:9
+ |
+LL | fn method2(&self) -> &u8 {
+ | --- expected `&u8` because of return type
+LL | self.option..foo().get(0)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&u8`, found struct `Range`
+ |
+ = note: expected reference `&u8`
+ found struct `std::ops::Range<Option<Vec<u8>>>`
+help: you likely meant to write a method call instead of a range
+ |
+LL - self.option..foo().get(0)
+LL + self.option.foo().get(0)
+ |
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0425.
+For more information about an error, try `rustc --explain E0308`.
fn two_type_params<A, B>(_: B) {}
fn main() {
- two_type_params::<String, _>(100); //~ ERROR this function takes 2 generic arguments
+ two_type_params::<String, _>(100); //~ ERROR function takes 2 generic arguments
two_type_params::<String, _>(100);
}
fn two_type_params<A, B>(_: B) {}
fn main() {
- two_type_params::<String>(100); //~ ERROR this function takes 2 generic arguments
+ two_type_params::<String>(100); //~ ERROR function takes 2 generic arguments
two_type_params::<String, _>(100);
}
|
note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `selection.1`
--> $SRC_DIR/core/src/option.rs:LL:COL
+help: you can `clone` the value and consume it, but this might not be your desired behavior
+ |
+LL | if selection.1.clone().unwrap().contains(selection.0) {
+ | ++++++++
error[E0507]: cannot move out of `selection.1` which is behind a shared reference
--> $DIR/option-content-move.rs:27:20
|
note: `Result::<T, E>::unwrap` takes ownership of the receiver `self`, which moves `selection.1`
--> $SRC_DIR/core/src/result.rs:LL:COL
+help: you can `clone` the value and consume it, but this might not be your desired behavior
+ |
+LL | if selection.1.clone().unwrap().contains(selection.0) {
+ | ++++++++
error: aborting due to 2 previous errors
--- /dev/null
+#![allow(unused)]
+
+struct X {
+ x: (),
+}
+pub trait A {
+ fn foo(&mut self, _: usize) -> &mut ();
+}
+impl A for X {
+ fn foo(&mut self, _: usize) -> &mut () {
+ &mut self.x
+ }
+}
+impl X {
+ fn foo(&mut self, _: usize) -> &mut Self {
+ self
+ }
+}
+
+fn main() {
+ let mut x = X { x: () };
+ *x.foo(0) = (); //~ ERROR E0308
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/shadowed-lplace-method-2.rs:22:17
+ |
+LL | *x.foo(0) = ();
+ | --------- ^^ expected struct `X`, found `()`
+ | |
+ | expected due to the type of this binding
+ |
+note: the `foo` call is resolved to the method in `X`, shadowing the method of the same name on trait `A`
+ --> $DIR/shadowed-lplace-method-2.rs:22:8
+ |
+LL | *x.foo(0) = ();
+ | ^^^ refers to `X::foo`
+help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly
+ |
+LL | *<_ as A>::foo(&mut x, 0) = ();
+ | ++++++++++++++++++ ~
+help: try wrapping the expression in `X`
+ |
+LL | *x.foo(0) = X { x: () };
+ | ++++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// run-rustfix
+#![allow(unused_imports)]
+use std::borrow::BorrowMut;
+use std::cell::RefCell;
+use std::rc::Rc;
+
+fn main() {
+ let rc = Rc::new(RefCell::new(true));
+ *std::cell::RefCell::<_>::borrow_mut(&rc) = false; //~ ERROR E0308
+}
--- /dev/null
+// run-rustfix
+#![allow(unused_imports)]
+use std::borrow::BorrowMut;
+use std::cell::RefCell;
+use std::rc::Rc;
+
+fn main() {
+ let rc = Rc::new(RefCell::new(true));
+ *rc.borrow_mut() = false; //~ ERROR E0308
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/shadowed-lplace-method.rs:9:24
+ |
+LL | *rc.borrow_mut() = false;
+ | ---------------- ^^^^^ expected struct `Rc`, found `bool`
+ | |
+ | expected due to the type of this binding
+ |
+ = note: expected struct `Rc<RefCell<bool>>`
+ found type `bool`
+note: the `borrow_mut` call is resolved to the method in `std::borrow::BorrowMut`, shadowing the method of the same name on the inherent impl for `std::cell::RefCell<T>`
+ --> $DIR/shadowed-lplace-method.rs:9:9
+ |
+LL | use std::borrow::BorrowMut;
+ | ---------------------- `std::borrow::BorrowMut` imported here
+...
+LL | *rc.borrow_mut() = false;
+ | ^^^^^^^^^^ refers to `std::borrow::BorrowMut::borrow_mut`
+help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly
+ |
+LL | *std::cell::RefCell::<_>::borrow_mut(&rc) = false;
+ | +++++++++++++++++++++++++++++++++++++ ~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
LL | let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
| --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&str`, found closure
| |
- | arguments to this function are incorrect
+ | arguments to this method are incorrect
|
= note: expected reference `&str`
found closure `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]`
error[E0594]: cannot assign to `self.0`, which is behind a `&` reference
--> $DIR/suggest-ref-mut.rs:7:9
|
-LL | fn zap(&self) {
- | ----- help: consider changing this to be a mutable reference: `&mut self`
-...
LL | self.0 = 32;
| ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn zap(&mut self) {
+ | ~~~~~~~~~
error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
--> $DIR/suggest-ref-mut.rs:16:5
|
-LL | let ref foo = 16;
- | ------- help: consider changing this to be a mutable reference: `ref mut foo`
-...
LL | *foo = 32;
| ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let ref mut foo = 16;
+ | ~~~~~~~~~~~
error[E0594]: cannot assign to `*bar`, which is behind a `&` reference
--> $DIR/suggest-ref-mut.rs:21:9
|
-LL | if let Some(ref bar) = Some(16) {
- | ------- help: consider changing this to be a mutable reference: `ref mut bar`
-...
LL | *bar = 32;
| ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | if let Some(ref mut bar) = Some(16) {
+ | ~~~~~~~~~~~
error[E0594]: cannot assign to `*quo`, which is behind a `&` reference
--> $DIR/suggest-ref-mut.rs:25:22
|
LL | ref quo => { *quo = 32; },
- | ------- ^^^^^^^^^ `quo` is a `&` reference, so the data it refers to cannot be written
- | |
- | help: consider changing this to be a mutable reference: `ref mut quo`
+ | ^^^^^^^^^ `quo` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | ref mut quo => { *quo = 32; },
+ | ~~~~~~~~~~~
error: aborting due to 4 previous errors
LL | x.funk(3);
| ---- ^ expected associated type, found integer
| |
- | arguments to this function are incorrect
+ | arguments to this method are incorrect
|
= note: expected associated type `<T as Trait<i32>>::A`
found type `{integer}`
LL | const C: _ = || 42;
| ^ not allowed in type signatures
|
-note: however, the inferred type `[closure@$DIR/unnamable-types.rs:17:14: 17:16]` cannot be named
+note: however, the inferred type `[closure@unnamable-types.rs:17:14]` cannot be named
--> $DIR/unnamable-types.rs:17:14
|
LL | const C: _ = || 42;
LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
| ^
|
-note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:45]>` cannot be named
+note: however, the inferred type `S<[closure@unnamable-types.rs:23:31]>` cannot be named
--> $DIR/unnamable-types.rs:23:11
|
LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
help: add missing generic argument
|
LL | fn foo(c: Quux<T>) { assert!((false)); }
- | ~~~~~~~
+ | +++
error: aborting due to previous error
kind: Scope {
region_scope: Node(2),
lint_level: Explicit(
- HirId {
- owner: OwnerId {
- def_id: DefId(0:3 ~ thir_tree[8f1d]::main),
- },
- local_id: 2,
- },
+ HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2),
),
value: e0,
},
// Cannot have a larger effect than the trait:
unsafe fn jumbo(&self, x: &usize) { *self + *x; }
//~^ ERROR method `jumbo` has an incompatible type for trait
- //~| expected fn pointer `fn
- //~| found fn pointer `unsafe fn
+ //~| expected signature `fn
+ //~| found signature `unsafe fn
}
fn main() {}
|
LL | fn jumbo(&self, x: &usize) -> usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: expected fn pointer `fn(&usize, &usize) -> usize`
- found fn pointer `unsafe fn(&usize, &usize)`
+ = note: expected signature `fn(&usize, &usize) -> usize`
+ found signature `unsafe fn(&usize, &usize)`
error: aborting due to previous error
|
LL | fn foo(_: fn(u8) -> ());
| ^^^^^^^^^^^^
- = note: expected fn pointer `fn(fn(u8))`
- found fn pointer `fn(fn(u16))`
+ = note: expected signature `fn(fn(u8))`
+ found signature `fn(fn(u16))`
error[E0053]: method `bar` has an incompatible type for trait
--> $DIR/issue-35869.rs:13:15
|
LL | fn bar(_: Option<u8>);
| ^^^^^^^^^^
- = note: expected fn pointer `fn(Option<u8>)`
- found fn pointer `fn(Option<u16>)`
+ = note: expected signature `fn(Option<u8>)`
+ found signature `fn(Option<u16>)`
error[E0053]: method `baz` has an incompatible type for trait
--> $DIR/issue-35869.rs:15:15
|
LL | fn baz(_: (u8, u16));
| ^^^^^^^^^
- = note: expected fn pointer `fn((u8, _))`
- found fn pointer `fn((u16, _))`
+ = note: expected signature `fn((u8, _))`
+ found signature `fn((u16, _))`
error[E0053]: method `qux` has an incompatible type for trait
--> $DIR/issue-35869.rs:17:17
|
LL | fn qux() -> u8;
| ^^
- = note: expected fn pointer `fn() -> u8`
- found fn pointer `fn() -> u16`
+ = note: expected signature `fn() -> u8`
+ found signature `fn() -> u16`
error: aborting due to 4 previous errors
LL | builder.push(output);
| ---- ^^^^^^ expected type parameter `F`, found struct `Class`
| |
- | arguments to this function are incorrect
+ | arguments to this method are incorrect
|
= note: expected type parameter `F`
found struct `Class<P>`
error[E0277]: the trait bound `Foo: HasComponent<()>` is not satisfied
- --> $DIR/issue-91594.rs:10:1
+ --> $DIR/issue-91594.rs:10:6
|
LL | impl HasComponent<<Foo as Component<Foo>>::Interface> for Foo {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo`
|
= help: the trait `HasComponent<<Foo as Component<Foo>>::Interface>` is implemented for `Foo`
note: required for `Foo` to implement `Component<Foo>`
--- /dev/null
+struct Argument;
+struct Return;
+
+fn function(_: Argument) -> Return { todo!() }
+
+trait Trait {}
+impl Trait for fn(Argument) -> Return {}
+
+fn takes(_: impl Trait) {}
+
+fn main() {
+ takes(function);
+ //~^ ERROR the trait bound
+ takes(|_: Argument| -> Return { todo!() });
+ //~^ ERROR the trait bound
+}
--- /dev/null
+error[E0277]: the trait bound `fn(Argument) -> Return {function}: Trait` is not satisfied
+ --> $DIR/issue-99875.rs:12:11
+ |
+LL | takes(function);
+ | ----- ^^^^^^^^ the trait `Trait` is not implemented for fn item `fn(Argument) -> Return {function}`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
+note: required by a bound in `takes`
+ --> $DIR/issue-99875.rs:9:18
+ |
+LL | fn takes(_: impl Trait) {}
+ | ^^^^^ required by this bound in `takes`
+
+error[E0277]: the trait bound `[closure@$DIR/issue-99875.rs:14:11: 14:34]: Trait` is not satisfied
+ --> $DIR/issue-99875.rs:14:11
+ |
+LL | takes(|_: Argument| -> Return { todo!() });
+ | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for closure `[closure@$DIR/issue-99875.rs:14:11: 14:34]`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
+note: required by a bound in `takes`
+ --> $DIR/issue-99875.rs:9:18
+ |
+LL | fn takes(_: impl Trait) {}
+ | ^^^^^ required by this bound in `takes`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
LL | fn foo(x: Foo<'b,'a>) {
| ^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
- = note: expected fn pointer `fn(Foo<'a, 'b>)`
- found fn pointer `fn(Foo<'b, 'a>)`
+ = note: expected signature `fn(Foo<'a, 'b>)`
+ found signature `fn(Foo<'b, 'a>)`
note: the lifetime `'b` as defined here...
--> $DIR/matching-lifetimes.rs:13:9
|
LL | fn foo(x: Foo<'b,'a>) {
| ^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
- = note: expected fn pointer `fn(Foo<'a, 'b>)`
- found fn pointer `fn(Foo<'b, 'a>)`
+ = note: expected signature `fn(Foo<'a, 'b>)`
+ found signature `fn(Foo<'b, 'a>)`
note: the lifetime `'a` as defined here...
--> $DIR/matching-lifetimes.rs:13:6
|
| required by a bound introduced by this call
|
= help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType`
- = note: required because it appears within the type `({integer}, dummy1c::TestType)`
+ = note: required because it appears within the type `({integer}, TestType)`
note: required by a bound in `is_send`
--> $DIR/negated-auto-traits-error.rs:16:15
|
|
= note: the trait bound `Unique<dummy2::TestType>: Send` is not satisfied
= note: required for `Unique<dummy2::TestType>` to implement `Send`
- = note: required because it appears within the type `Box<dummy2::TestType>`
+ = note: required because it appears within the type `Box<TestType>`
note: required by a bound in `is_send`
--> $DIR/negated-auto-traits-error.rs:16:15
|
| required by a bound introduced by this call
|
= help: within `Outer2<dummy3::TestType>`, the trait `Send` is not implemented for `dummy3::TestType`
-note: required because it appears within the type `Outer2<dummy3::TestType>`
+note: required because it appears within the type `Outer2<TestType>`
--> $DIR/negated-auto-traits-error.rs:12:8
|
LL | struct Outer2<T>(T);
| ^^^^^^
= note: required for `Unique<Outer2<dummy3::TestType>>` to implement `Send`
- = note: required because it appears within the type `Box<Outer2<dummy3::TestType>>`
+ = note: required because it appears within the type `Box<Outer2<TestType>>`
note: required by a bound in `is_send`
--> $DIR/negated-auto-traits-error.rs:16:15
|
LL | fn get_relation(&self) -> &ProofReader {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Article) -> &'1 ProofReader`
|
- = note: expected `fn(&'1 Article) -> &'2 ProofReader`
- found `fn(&'1 Article) -> &'1 ProofReader`
+ = note: expected signature `fn(&'1 Article) -> &'2 ProofReader`
+ found signature `fn(&'1 Article) -> &'1 ProofReader`
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
--> $DIR/param-without-lifetime-constraint.rs:10:31
|
error[E0200]: the trait `Foo` requires an `unsafe impl` declaration
--> $DIR/safety-trait-impl-cc.rs:9:1
|
-LL | / impl lib::Foo for Bar {
-LL | | fn foo(&self) -> isize {
-LL | | panic!();
-LL | | }
-LL | | }
- | |_^
+LL | impl lib::Foo for Bar {
+ | ^^^^^^^^^^^^^^^^^^^^^
|
= note: the trait `Foo` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
help: add `unsafe` to this trait implementation
--> $DIR/safety-trait-impl.rs:14:1
|
LL | impl UnsafeTrait for u16 { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the trait `UnsafeTrait` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
help: add `unsafe` to this trait implementation
--> $DIR/safety-trait-impl.rs:16:1
|
LL | unsafe impl SafeTrait for u32 { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: remove `unsafe` from this trait implementation
|
LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'1>) -> Result<(&'1 str, &'1 &'1 str), FromSqlError>`
|
- = note: expected `fn(ValueRef<'1>) -> Result<(&'2 str, &'1 &'2 str), FromSqlError>`
- found `fn(ValueRef<'1>) -> Result<(&'1 str, &'1 &'1 str), FromSqlError>`
+ = note: expected signature `fn(ValueRef<'1>) -> Result<(&'2 str, &'1 &'2 str), FromSqlError>`
+ found signature `fn(ValueRef<'1>) -> Result<(&'1 str, &'1 &'1 str), FromSqlError>`
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
--> $DIR/self-without-lifetime-constraint.rs:41:60
|
error[E0596]: cannot borrow `**t` as mutable, as it is behind a `&` reference
--> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:6:5
|
-LL | fn reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
- | --------------- help: consider changing this to be a mutable reference: `&'a mut &'a mut i32`
LL | *t
| ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn reborrow_mut<'a>(t: &'a mut &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
+ | ~~~~~~~~~~~~~~~~~~~
error[E0596]: cannot borrow `**t` as mutable, as it is behind a `&` reference
--> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:10:6
|
-LL | fn copy_reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
- | --------------- help: consider changing this to be a mutable reference: `&'a mut &'a mut i32`
LL | {*t}
| ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn copy_reborrow_mut<'a>(t: &'a mut &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
+ | ~~~~~~~~~~~~~~~~~~~
error: aborting due to 2 previous errors
fn main() {
foo("hi", 1, 2, "hi");
- //~^ ERROR this function takes 3 arguments but 4 arguments were supplied
+ //~^ ERROR function takes 3 arguments but 4 arguments were supplied
bar("hi", "hi", "hi");
//~^ ERROR mismatched types
}
-error[E0061]: this function takes 3 arguments but 4 arguments were supplied
+error[E0061]: function takes 3 arguments but 4 arguments were supplied
--> $DIR/add-tuple-within-arguments.rs:6:5
|
LL | foo("hi", 1, 2, "hi");
fn bar() {
let x = Foo;
test(x.qux(), x.qux());
- //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+ //~^ ERROR function takes 1 argument but 2 arguments were supplied
}
fn main() {}
-error[E0061]: this function takes 1 argument but 2 arguments were supplied
+error[E0061]: function takes 1 argument but 2 arguments were supplied
--> $DIR/wrong_argument_ice-2.rs:13:5
|
LL | test(x.qux(), x.qux());
if groups.capacity() == 0 {
groups.push(new_group, vec![process]);
- //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+ //~^ ERROR this method takes 1 argument but 2 arguments were supplied
return groups;
}
-error[E0061]: this function takes 1 argument but 2 arguments were supplied
+error[E0061]: this method takes 1 argument but 2 arguments were supplied
--> $DIR/wrong_argument_ice-3.rs:9:16
|
LL | groups.push(new_group, vec![process]);
fn main() {
(|| {})(|| {
- //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+ //~^ ERROR function takes 0 arguments but 1 argument was supplied
let b = 1;
});
}
impl BuildPlanBuilder {
pub fn or(&mut self) -> &mut Self {
self.acc.push_back(self.current_provides, self.current_requires);
- //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+ //~^ ERROR method takes 1 argument but 2 arguments were supplied
self
}
}
-error[E0061]: this function takes 1 argument but 2 arguments were supplied
+error[E0061]: method takes 1 argument but 2 arguments were supplied
--> $DIR/wrong_argument_ice.rs:11:18
|
LL | self.acc.push_back(self.current_provides, self.current_requires);
--- /dev/null
+//check-pass
+
+#![feature(type_alias_impl_trait)]
+
+trait Trait {
+ type Opaque1;
+ type Opaque2;
+ fn constrain(self);
+}
+
+impl<'a> Trait for &'a () {
+ type Opaque1 = impl Sized;
+ type Opaque2 = impl Sized + 'a;
+ fn constrain(self) {
+ let _: Self::Opaque1 = ();
+ let _: Self::Opaque2 = self;
+ }
+}
+
+fn main() {}
help: add missing generic argument
|
LL | input_cells: Vec<T>::new()
- | ~~~~~~
+ | +++
error: aborting due to 3 previous errors
--- /dev/null
+struct S;
+fn main() {
+ let x = {
+ println!("foo");
+ 42;
+ };
+ let y = {};
+ let z = {
+ "hi";
+ };
+ let s = {
+ S;
+ };
+ println!("{}", x); //~ ERROR E0277
+ println!("{}", y); //~ ERROR E0277
+ println!("{}", z); //~ ERROR E0277
+ println!("{}", s); //~ ERROR E0277
+ let _: i32 = x; //~ ERROR E0308
+ let _: i32 = y; //~ ERROR E0308
+ let _: i32 = z; //~ ERROR E0308
+ let _: i32 = s; //~ ERROR E0308
+}
--- /dev/null
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:14:20
+ |
+LL | 42;
+ | - help: remove this semicolon
+...
+LL | println!("{}", x);
+ | ^ `()` cannot be formatted with the default formatter
+ |
+ = help: the trait `std::fmt::Display` is not implemented for `()`
+ = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:15:20
+ |
+LL | let y = {};
+ | -- this empty block is missing a tail expression
+...
+LL | println!("{}", y);
+ | ^ `()` cannot be formatted with the default formatter
+ |
+ = help: the trait `std::fmt::Display` is not implemented for `()`
+ = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:16:20
+ |
+LL | "hi";
+ | - help: remove this semicolon
+...
+LL | println!("{}", z);
+ | ^ `()` cannot be formatted with the default formatter
+ |
+ = help: the trait `std::fmt::Display` is not implemented for `()`
+ = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:17:20
+ |
+LL | let s = {
+ | _____________-
+LL | | S;
+LL | | };
+ | |_____- this block is missing a tail expression
+...
+LL | println!("{}", s);
+ | ^ `()` cannot be formatted with the default formatter
+ |
+ = help: the trait `std::fmt::Display` is not implemented for `()`
+ = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:18:18
+ |
+LL | 42;
+ | - help: remove this semicolon
+...
+LL | let _: i32 = x;
+ | --- ^ expected `i32`, found `()`
+ | |
+ | expected due to this
+
+error[E0308]: mismatched types
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:19:18
+ |
+LL | let y = {};
+ | -- this empty block is missing a tail expression
+...
+LL | let _: i32 = y;
+ | --- ^ expected `i32`, found `()`
+ | |
+ | expected due to this
+
+error[E0308]: mismatched types
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:20:18
+ |
+LL | let z = {
+ | _____________-
+LL | | "hi";
+LL | | };
+ | |_____- this block is missing a tail expression
+...
+LL | let _: i32 = z;
+ | --- ^ expected `i32`, found `()`
+ | |
+ | expected due to this
+
+error[E0308]: mismatched types
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:21:18
+ |
+LL | let s = {
+ | _____________-
+LL | | S;
+LL | | };
+ | |_____- this block is missing a tail expression
+...
+LL | let _: i32 = s;
+ | --- ^ expected `i32`, found `()`
+ | |
+ | expected due to this
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
--- /dev/null
+struct S<'a>(&'a str);
+
+fn f(inner: fn(&str, &S)) {
+}
+
+#[allow(unreachable_code)]
+fn main() {
+ let inner: fn(_, _) = unimplemented!();
+ f(inner); //~ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/closure-with-wrong-borrows.rs:9:7
+ |
+LL | f(inner);
+ | - ^^^^^ one type is more general than the other
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected fn pointer `for<'a, 'b, 'c> fn(&'a str, &'b S<'c>)`
+ found fn pointer `fn(_, _)`
+note: function defined here
+ --> $DIR/closure-with-wrong-borrows.rs:3:4
+ |
+LL | fn f(inner: fn(&str, &S)) {
+ | ^ -------------------
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+fn foo<'a>(_: impl 'a Sized) {}
+//~^ ERROR: expected `+` between lifetime and Sized
+//~| ERROR: expected one of `:`, `@`, or `|`, found `)`
+//~| ERROR: expected one of `)`, `+`, or `,`, found `Sized`
+//~| ERROR: at least one trait must be specified
+
+fn main(){
+}
--- /dev/null
+error: expected `+` between lifetime and Sized
+ --> $DIR/issue-102598.rs:1:20
+ |
+LL | fn foo<'a>(_: impl 'a Sized) {}
+ | ^^
+ |
+help: add `+`
+ |
+LL | fn foo<'a>(_: impl 'a + Sized) {}
+ | +
+
+error: expected one of `:`, `@`, or `|`, found `)`
+ --> $DIR/issue-102598.rs:1:28
+ |
+LL | fn foo<'a>(_: impl 'a Sized) {}
+ | ^ expected one of `:`, `@`, or `|`
+ |
+ = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this is a parameter name, give it a type
+ |
+LL | fn foo<'a>(_: impl 'a Sized: TypeName) {}
+ | ++++++++++
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn foo<'a>(_: impl 'a _: Sized) {}
+ | ++
+
+error: expected one of `)`, `+`, or `,`, found `Sized`
+ --> $DIR/issue-102598.rs:1:23
+ |
+LL | fn foo<'a>(_: impl 'a Sized) {}
+ | -^^^^^ expected one of `)`, `+`, or `,`
+ | |
+ | help: missing `,`
+
+error: at least one trait must be specified
+ --> $DIR/issue-102598.rs:1:15
+ |
+LL | fn foo<'a>(_: impl 'a Sized) {}
+ | ^^^^^^^
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+#![crate_type = "lib"]
+
+pub fn foo(callback: fn() -> dyn ToString) {
+ let mut x: Option<Box<dyn Fn() -> dyn ToString>> = None;
+ x = Some(Box::new(callback));
+ //~^ ERROR: the size for values of type `dyn ToString` cannot be known at compilation time
+}
--- /dev/null
+error[E0277]: the size for values of type `dyn ToString` cannot be known at compilation time
+ --> $DIR/issue-58355.rs:5:14
+ |
+LL | x = Some(Box::new(callback));
+ | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: within `fn() -> dyn ToString`, the trait `Sized` is not implemented for `dyn ToString`
+ = note: required because it appears within the type `fn() -> dyn ToString`
+ = note: required for the cast from `fn() -> dyn ToString` to the object type `dyn Fn() -> (dyn ToString + 'static)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
fn main() {
let x: Vec::with_capacity(10, 20); //~ ERROR expected type, found `10`
- //~^ ERROR this function takes 1 argument
+ //~^ ERROR function takes 1 argument
}
error[E0308]: mismatched types
--> $DIR/assignment-in-if.rs:44:18
|
+LL | if y = (Foo { foo: x }) {
+ | - here the type of `x` is inferred to be `usize`
+...
LL | if x == x && x = x && x == x {
| ------ ^ expected `bool`, found `usize`
| |
error[E0308]: mismatched types
--> $DIR/assignment-in-if.rs:44:22
|
+LL | if y = (Foo { foo: x }) {
+ | - here the type of `x` is inferred to be `usize`
+...
LL | if x == x && x = x && x == x {
| ^ expected `bool`, found `usize`
error[E0308]: mismatched types
--> $DIR/assignment-in-if.rs:51:28
|
+LL | if y = (Foo { foo: x }) {
+ | - here the type of `x` is inferred to be `usize`
+...
LL | if x == x && x == x && x = x {
| ---------------- ^ expected `bool`, found `usize`
| |
--- /dev/null
+fn bar(_: Vec<i32>) {}
+fn baz(_: &Vec<&i32>) {}
+fn main() {
+ let v = vec![&1];
+ bar(v); //~ ERROR E0308
+ let v = vec![];
+ baz(&v);
+ baz(&v);
+ bar(v); //~ ERROR E0308
+ let v = vec![];
+ baz(&v);
+ bar(v); //~ ERROR E0308
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/point-at-inference-2.rs:5:9
+ |
+LL | bar(v);
+ | --- ^ expected `i32`, found `&{integer}`
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected struct `Vec<i32>`
+ found struct `Vec<&{integer}>`
+note: function defined here
+ --> $DIR/point-at-inference-2.rs:1:4
+ |
+LL | fn bar(_: Vec<i32>) {}
+ | ^^^ -----------
+
+error[E0308]: mismatched types
+ --> $DIR/point-at-inference-2.rs:9:9
+ |
+LL | baz(&v);
+ | - here the type of `v` is inferred to be `Vec<&i32>`
+LL | baz(&v);
+LL | bar(v);
+ | --- ^ expected `i32`, found `&i32`
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected struct `Vec<i32>`
+ found struct `Vec<&i32>`
+note: function defined here
+ --> $DIR/point-at-inference-2.rs:1:4
+ |
+LL | fn bar(_: Vec<i32>) {}
+ | ^^^ -----------
+
+error[E0308]: mismatched types
+ --> $DIR/point-at-inference-2.rs:12:9
+ |
+LL | baz(&v);
+ | - here the type of `v` is inferred to be `Vec<&i32>`
+LL | bar(v);
+ | --- ^ expected `i32`, found `&i32`
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected struct `Vec<i32>`
+ found struct `Vec<&i32>`
+note: function defined here
+ --> $DIR/point-at-inference-2.rs:1:4
+ |
+LL | fn bar(_: Vec<i32>) {}
+ | ^^^ -----------
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// run-rustfix
+fn main() {
+ let mut v = Vec::new();
+ v.push(0i32);
+ //~^ NOTE this is of type `i32`, which causes `v` to be inferred as `Vec<i32>`
+ v.push(0);
+ v.push(1i32); //~ ERROR mismatched types
+ //~^ NOTE expected `i32`, found `u32`
+ //~| NOTE arguments to this method are incorrect
+ //~| NOTE associated function defined here
+ //~| HELP change the type of the numeric literal from `u32` to `i32`
+}
--- /dev/null
+// run-rustfix
+fn main() {
+ let mut v = Vec::new();
+ v.push(0i32);
+ //~^ NOTE this is of type `i32`, which causes `v` to be inferred as `Vec<i32>`
+ v.push(0);
+ v.push(1u32); //~ ERROR mismatched types
+ //~^ NOTE expected `i32`, found `u32`
+ //~| NOTE arguments to this method are incorrect
+ //~| NOTE associated function defined here
+ //~| HELP change the type of the numeric literal from `u32` to `i32`
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/point-at-inference-3.rs:7:12
+ |
+LL | v.push(0i32);
+ | ---- this is of type `i32`, which causes `v` to be inferred as `Vec<i32>`
+...
+LL | v.push(1u32);
+ | ---- ^^^^ expected `i32`, found `u32`
+ | |
+ | arguments to this method are incorrect
+ |
+note: associated function defined here
+ --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | v.push(1i32);
+ | ~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// run-rustfix
+fn bar(_: Vec<i32>) {}
+fn baz(_: &impl std::any::Any) {}
+fn main() {
+ let v = vec![1, 2, 3, 4, 5];
+ let mut foo = vec![];
+ baz(&foo);
+ for i in &v {
+ foo.push(*i);
+ }
+ baz(&foo);
+ bar(foo); //~ ERROR E0308
+}
--- /dev/null
+// run-rustfix
+fn bar(_: Vec<i32>) {}
+fn baz(_: &impl std::any::Any) {}
+fn main() {
+ let v = vec![1, 2, 3, 4, 5];
+ let mut foo = vec![];
+ baz(&foo);
+ for i in &v {
+ foo.push(i);
+ }
+ baz(&foo);
+ bar(foo); //~ ERROR E0308
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/point-at-inference.rs:12:9
+ |
+LL | foo.push(i);
+ | - this is of type `&{integer}`, which causes `foo` to be inferred as `Vec<&{integer}>`
+...
+LL | bar(foo);
+ | --- ^^^ expected `i32`, found `&{integer}`
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected struct `Vec<i32>`
+ found struct `Vec<&{integer}>`
+note: function defined here
+ --> $DIR/point-at-inference.rs:2:4
+ |
+LL | fn bar(_: Vec<i32>) {}
+ | ^^^ -----------
+help: consider dereferencing the borrow
+ |
+LL | foo.push(*i);
+ | +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+fn digit() -> str {
+ return {};
+ //~^ ERROR: mismatched types [E0308]
+}
+fn main() {
+ let [_y..] = [box 1, box 2];
+ //~^ ERROR: cannot find value `_y` in this scope [E0425]
+ //~| ERROR: `X..` patterns in slices are experimental [E0658]
+ //~| ERROR: box expression syntax is experimental; you can call `Box::new` instead [E0658]
+ //~| ERROR: box expression syntax is experimental; you can call `Box::new` instead [E0658]
+ //~| ERROR: pattern requires 1 element but array has 2 [E0527]
+}
--- /dev/null
+error[E0425]: cannot find value `_y` in this scope
+ --> $DIR/issue-105946.rs:6:10
+ |
+LL | let [_y..] = [box 1, box 2];
+ | ^^ not found in this scope
+
+error[E0658]: `X..` patterns in slices are experimental
+ --> $DIR/issue-105946.rs:6:10
+ |
+LL | let [_y..] = [box 1, box 2];
+ | ^^^^
+ |
+ = note: see issue #67264 <https://github.com/rust-lang/rust/issues/67264> for more information
+ = help: add `#![feature(half_open_range_patterns_in_slices)]` to the crate attributes to enable
+
+error[E0658]: box expression syntax is experimental; you can call `Box::new` instead
+ --> $DIR/issue-105946.rs:6:19
+ |
+LL | let [_y..] = [box 1, box 2];
+ | ^^^^^
+ |
+ = note: see issue #49733 <https://github.com/rust-lang/rust/issues/49733> for more information
+ = help: add `#![feature(box_syntax)]` to the crate attributes to enable
+
+error[E0658]: box expression syntax is experimental; you can call `Box::new` instead
+ --> $DIR/issue-105946.rs:6:26
+ |
+LL | let [_y..] = [box 1, box 2];
+ | ^^^^^
+ |
+ = note: see issue #49733 <https://github.com/rust-lang/rust/issues/49733> for more information
+ = help: add `#![feature(box_syntax)]` to the crate attributes to enable
+
+error[E0308]: mismatched types
+ --> $DIR/issue-105946.rs:2:10
+ |
+LL | return {};
+ | ^^ expected `str`, found `()`
+
+error[E0527]: pattern requires 1 element but array has 2
+ --> $DIR/issue-105946.rs:6:9
+ |
+LL | let [_y..] = [box 1, box 2];
+ | ^^^^^^ expected 2 elements
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0308, E0425, E0527, E0658.
+For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+// run-pass
+// Test that we are able to type-check this example. In particular,
+// knowing that `T: 'a` allows us to deduce that `[U]: 'a` (because
+// when `T=[U]` it implies that `U: 'a`).
+//
+// Regr. test for live code we found in the wild when fixing #18937.
+
+pub trait Leak<T : ?Sized> {
+ fn leak<'a>(self) -> &'a T where T: 'a;
+}
+
+impl<U> Leak<[U]> for Vec<U> {
+ fn leak<'a>(mut self) -> &'a [U] where [U]: 'a {
+ let r: *mut [U] = &mut self[..];
+ std::mem::forget(self);
+ unsafe { &mut *r }
+ }
+}
+fn main() {
+ println!("Hello, world!");
+}
--- /dev/null
+// Regression test for #18937.
+
+use std::fmt;
+
+#[derive(Debug)]
+struct MyString<'a>(&'a String);
+
+struct B {
+ list: Vec<Box<dyn fmt::Debug>>,
+}
+
+trait A<'a> {
+ fn foo<F>(&mut self, f: F)
+ where F: fmt::Debug + 'a,
+ Self: Sized;
+}
+
+impl<'a> A<'a> for B {
+ fn foo<F>(&mut self, f: F)
+ where F: fmt::Debug + 'static, //~ ERROR impl has stricter
+ {
+ self.list.push(Box::new(f));
+ }
+}
+
+fn main() {
+ let mut b = B { list: Vec::new() };
+
+ // Create a borrowed pointer, put it in `b`, then drop what's borrowing it
+ let a = "hello".to_string();
+ b.foo(MyString(&a));
+
+ // Drop the data which `b` has a reference to
+ drop(a);
+
+ // Use the data, probably segfaulting
+ for b in b.list.iter() {
+ println!("{:?}", b);
+ }
+}
--- /dev/null
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/issue-18937.rs:20:31
+ |
+LL | / fn foo<F>(&mut self, f: F)
+LL | | where F: fmt::Debug + 'a,
+LL | | Self: Sized;
+ | |__________________________- definition of `foo` from trait
+...
+LL | where F: fmt::Debug + 'static,
+ | ^^^^^^^ impl has extra requirement `F: 'static`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0276`.
--- /dev/null
+use std::vec::IntoIter;
+
+pub fn get_tok(it: &mut IntoIter<u8>) {
+ let mut found_e = false;
+
+ let temp: Vec<u8> = it
+ .take_while(|&x| {
+ found_e = true;
+ false
+ })
+ .cloned() //~ ERROR to be an iterator that yields `&_`, but it yields `u8`
+ .collect(); //~ ERROR the method
+}
+
+fn main() {}
--- /dev/null
+error[E0271]: expected `TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>` to be an iterator that yields `&_`, but it yields `u8`
+ --> $DIR/issue-31173.rs:11:10
+ |
+LL | .cloned()
+ | ^^^^^^ expected reference, found `u8`
+ |
+ = note: expected reference `&_`
+ found type `u8`
+note: the method call chain might not have had the expected associated types
+ --> $DIR/issue-31173.rs:3:20
+ |
+LL | pub fn get_tok(it: &mut IntoIter<u8>) {
+ | ^^^^^^^^^^^^^^^^^ `Iterator::Item` is `u8` here
+...
+LL | .take_while(|&x| {
+ | __________-
+LL | | found_e = true;
+LL | | false
+LL | | })
+ | |__________- `Iterator::Item` remains `u8` here
+note: required by a bound in `cloned`
+ --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>>`, but its trait bounds were not satisfied
+ --> $DIR/issue-31173.rs:12:10
+ |
+LL | .collect();
+ | ^^^^^^^ method cannot be called due to unsatisfied trait bounds
+ --> $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL
+ |
+ = note: doesn't satisfy `<_ as Iterator>::Item = &_`
+ --> $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
+ |
+ = note: doesn't satisfy `_: Iterator`
+ |
+ = note: the following trait bounds were not satisfied:
+ `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]> as Iterator>::Item = &_`
+ which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
+ `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
+ which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0271, E0599.
+For more information about an error, try `rustc --explain E0271`.
--- /dev/null
+struct Foo {
+ val: MissingType,
+ //~^ ERROR cannot find type `MissingType` in this scope
+}
+
+fn main() {
+ Foo { val: Default::default() };
+}
--- /dev/null
+error[E0412]: cannot find type `MissingType` in this scope
+ --> $DIR/nonexistent-field-not-ambiguous.rs:2:10
+ |
+LL | val: MissingType,
+ | ^^^^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
--- /dev/null
+// fn foo() -> String {
+// String::new()
+// }
+
+fn test(s: &str) {
+ println!("{}", s);
+}
+
+fn test2(s: String) {
+ println!("{}", s);
+}
+
+fn main() {
+ let x = foo(); //~ERROR cannot find function `foo` in this scope
+ test(&x);
+ test2(x); // Does not complain about `x` being a `&str`.
+}
--- /dev/null
+error[E0425]: cannot find function `foo` in this scope
+ --> $DIR/quiet-type-err-let-binding.rs:14:13
+ |
+LL | let x = foo();
+ | ^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
fn main() {
l(vec![])
- //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+ //~^ ERROR function takes 1 argument but 2 arguments were supplied
//~| HELP remove the extra argument
}
fn main() {
l(vec![], vec![])
- //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+ //~^ ERROR function takes 1 argument but 2 arguments were supplied
//~| HELP remove the extra argument
}
const _: Option<_> = map(value);
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+
+fn evens_squared(n: usize) -> _ {
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+ (1..n).filter(|x| x % 2 == 0).map(|x| x * x)
+}
+
+const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
| not allowed in type signatures
| help: replace with the correct type: `Option<u8>`
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+ --> $DIR/typeck_type_placeholder_item.rs:224:31
+ |
+LL | fn evens_squared(n: usize) -> _ {
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace with an appropriate return type: `impl Iterator<Item = usize>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+ --> $DIR/typeck_type_placeholder_item.rs:229:10
+ |
+LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
+ | ^ not allowed in type signatures
+ |
+note: however, the inferred type `Map<Filter<Range<i32>, [closure@typeck_type_placeholder_item.rs:229:29]>, [closure@typeck_type_placeholder_item.rs:229:49]>` cannot be named
+ --> $DIR/typeck_type_placeholder_item.rs:229:14
+ |
+LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/typeck_type_placeholder_item.rs:140:31
|
| not allowed in type signatures
| help: replace with the correct type: `i32`
-error: aborting due to 69 previous errors
+error: aborting due to 71 previous errors
Some errors have detailed explanations: E0121, E0282, E0403.
For more information about an error, try `rustc --explain E0121`.
--> $DIR/ufcs-partially-resolved.rs:36:12
|
LL | let _: <u8 as Tr>::Y::NN;
- | ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u16 as Trait>::NN`
+ | ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<u8 as Tr>::Y as Trait>::NN`
error[E0599]: no associated item named `NN` found for type `u16` in the current scope
--> $DIR/ufcs-partially-resolved.rs:38:20
help: add missing generic argument
|
LL | <String as IntoCow<B>>::into_cow("foo".to_string());
- | ~~~~~~~~~~
+ | +++
error[E0107]: missing generics for trait `IntoCow`
--> $DIR/ufcs-qpath-missing-params.rs:17:16
help: add missing generic argument
|
LL | <String as IntoCow<B>>::into_cow::<str>("foo".to_string());
- | ~~~~~~~~~~
+ | +++
error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
--> $DIR/ufcs-qpath-missing-params.rs:17:26
--> $DIR/unboxed-closure-no-cyclic-sig.rs:8:7
|
LL | g(|_| { });
- | ^^^^^^^^ cyclic type of infinite size
+ | ^^^ cyclic type of infinite size
|
= note: closures cannot capture themselves or take themselves as argument;
this error may be the result of a recent compiler bug-fix,
see issue #46062 <https://github.com/rust-lang/rust/issues/46062>
for more information
+note: required by a bound in `g`
+ --> $DIR/unboxed-closure-no-cyclic-sig.rs:5:24
+ |
+LL | fn g<F>(_: F) where F: FnOnce(Option<F>) {}
+ | ^^^^^^^^^^^^^^^^^ required by this bound in `g`
error: aborting due to previous error
fn main() {
let _f = {
let x = 0;
- || x //~ ERROR `x` does not live long enough
+ || x //~ ERROR closure may outlive the current block, but it borrows `x`
};
_f;
}
-error[E0597]: `x` does not live long enough
- --> $DIR/unboxed-closure-region.rs:8:12
+error[E0373]: closure may outlive the current block, but it borrows `x`, which is owned by the current block
+ --> $DIR/unboxed-closure-region.rs:8:9
|
-LL | let _f = {
- | -- borrow later stored here
-LL | let x = 0;
LL | || x
- | -- ^ borrowed value does not live long enough
+ | ^^ - `x` is borrowed here
| |
- | value captured here
-LL | };
- | - `x` dropped here while still borrowed
+ | may outlive borrowed value `x`
+ |
+note: block requires argument type to outlive `'1`
+ --> $DIR/unboxed-closure-region.rs:6:9
+ |
+LL | let _f = {
+ | ^^
+help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
+ |
+LL | move || x
+ | ++++
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0597`.
+For more information about this error, try `rustc --explain E0373`.
error[E0596]: cannot borrow `tick2` as mutable, as it is not declared as mutable
--> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:19:5
|
-LL | let tick2 = || {
- | ----- help: consider changing this to be mutable: `mut tick2`
LL | tick1();
| ----- calling `tick2` requires mutable binding due to mutable borrow of `tick1`
...
LL | tick2();
| ^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut tick2 = || {
+ | +++
error: aborting due to 2 previous errors
--> $DIR/unboxed-closures-infer-fnmut-missing-mut.rs:7:5
|
LL | let tick = || counter += 1;
- | ---- ------- calling `tick` requires mutable binding due to mutable borrow of `counter`
- | |
- | help: consider changing this to be mutable: `mut tick`
+ | ------- calling `tick` requires mutable binding due to mutable borrow of `counter`
LL | tick();
| ^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut tick = || counter += 1;
+ | +++
error: aborting due to previous error
--> $DIR/unboxed-closures-infer-fnmut-move-missing-mut.rs:7:5
|
LL | let tick = move || counter += 1;
- | ---- ------- calling `tick` requires mutable binding due to possible mutation of `counter`
- | |
- | help: consider changing this to be mutable: `mut tick`
+ | ------- calling `tick` requires mutable binding due to possible mutation of `counter`
LL | tick();
| ^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut tick = move || counter += 1;
+ | +++
error: aborting due to previous error
|
LL | T: WithType<&u32>
| ^ explicit lifetime name needed here
+ |
+help: consider introducing a higher-ranked lifetime here with `for<'a>`
+ --> $DIR/where-clause-inherent-impl-ampersand.rs:13:8
+ |
+LL | T: WithType<&u32>
+ | ^
error: aborting due to previous error
|
LL | T: WithType<&u32>
| ^ explicit lifetime name needed here
+ |
+help: consider introducing a higher-ranked lifetime here with `for<'a>`
+ --> $DIR/where-clause-inherent-impl-ampersand.rs:13:8
+ |
+LL | T: WithType<&u32>
+ | ^
error: aborting due to previous error
|
LL | T: WithType<&u32>
| ^ explicit lifetime name needed here
+ |
+help: consider introducing a higher-ranked lifetime here with `for<'a>`
+ --> $DIR/where-clause-trait-impl-region.rs:11:8
+ |
+LL | T: WithType<&u32>
+ | ^
error: aborting due to previous error
|
LL | T: WithType<&u32>
| ^ explicit lifetime name needed here
+ |
+help: consider introducing a higher-ranked lifetime here with `for<'a>`
+ --> $DIR/where-clause-trait-impl-region.rs:11:8
+ |
+LL | T: WithType<&u32>
+ | ^
error: aborting due to previous error
--- /dev/null
+#[macro_export]
+macro_rules! foo {
+ () => {
+ unsafe fn __unsf() {}
+ unsafe fn __foo() {
+ __unsf();
+ }
+ };
+}
--- /dev/null
+// Regression test for #106126.
+// check-pass
+// aux-build:issue-106126.rs
+
+#![deny(unsafe_op_in_unsafe_fn)]
+
+#[macro_use]
+extern crate issue_106126;
+
+foo!();
+
+fn main() {}
impl Foo for u32 {
fn len(&self) -> u32 { *self }
//~^ ERROR method `len` has an incompatible type for trait
- //~| expected fn pointer `unsafe fn(&u32) -> _`
- //~| found fn pointer `fn(&u32) -> _`
+ //~| expected signature `unsafe fn(&u32) -> _`
+ //~| found signature `fn(&u32) -> _`
}
fn main() { }
|
LL | unsafe fn len(&self) -> u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: expected fn pointer `unsafe fn(&u32) -> _`
- found fn pointer `fn(&u32) -> _`
+ = note: expected signature `unsafe fn(&u32) -> _`
+ found signature `fn(&u32) -> _`
error: aborting due to previous error
--- /dev/null
+fn main() {
+ let x: [u8] = vec!(1, 2, 3)[..]; //~ ERROR E0277
+ let x: &[u8] = vec!(1, 2, 3)[..]; //~ ERROR E0308
+ let x: [u8] = &vec!(1, 2, 3)[..]; //~ ERROR E0308
+ //~^ ERROR E0277
+ let x: &[u8] = &vec!(1, 2, 3)[..];
+}
--- /dev/null
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+ --> $DIR/suggest-borrow.rs:2:9
+ |
+LL | let x: [u8] = vec!(1, 2, 3)[..];
+ | ^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[u8]`
+ = note: all local variables must have a statically known size
+ = help: unsized locals are gated as an unstable feature
+help: consider borrowing here
+ |
+LL | let x: &[u8] = vec!(1, 2, 3)[..];
+ | +
+
+error[E0308]: mismatched types
+ --> $DIR/suggest-borrow.rs:3:20
+ |
+LL | let x: &[u8] = vec!(1, 2, 3)[..];
+ | ----- ^^^^^^^^^^^^^^^^^
+ | | |
+ | | expected `&[u8]`, found slice `[{integer}]`
+ | | help: consider borrowing here: `&vec!(1, 2, 3)[..]`
+ | expected due to this
+
+error[E0308]: mismatched types
+ --> $DIR/suggest-borrow.rs:4:19
+ |
+LL | let x: [u8] = &vec!(1, 2, 3)[..];
+ | ---- ^^^^^^^^^^^^^^^^^^ expected slice `[u8]`, found `&[{integer}]`
+ | |
+ | expected due to this
+ |
+help: consider removing the borrow
+ |
+LL - let x: [u8] = &vec!(1, 2, 3)[..];
+LL + let x: [u8] = vec!(1, 2, 3)[..];
+ |
+help: alternatively, consider changing the type annotation
+ |
+LL | let x: &[u8] = &vec!(1, 2, 3)[..];
+ | +
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+ --> $DIR/suggest-borrow.rs:4:9
+ |
+LL | let x: [u8] = &vec!(1, 2, 3)[..];
+ | ^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[u8]`
+ = note: all local variables must have a statically known size
+ = help: unsized locals are gated as an unstable feature
+help: consider borrowing here
+ |
+LL | let x: &[u8] = &vec!(1, 2, 3)[..];
+ | +
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
= help: the trait `Sized` is not implemented for `[u8]`
= note: all local variables must have a statically known size
= help: unsized locals are gated as an unstable feature
+help: consider borrowing here
+ |
+LL | let _foo: &[u8] = *foo;
+ | +
error: aborting due to 3 previous errors
LL - fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) {
LL + fn f1<W: ?Sized, X: ?Sized, Y, Z: ?Sized>(x: &X) {
|
+help: consider borrowing here
+ |
+LL | let y: &Y;
+ | +
error[E0277]: the size for values of type `X` cannot be known at compilation time
--> $DIR/unsized6.rs:7:12
LL - fn f2<X: ?Sized, Y: ?Sized>(x: &X) {
LL + fn f2<X, Y: ?Sized>(x: &X) {
|
+help: consider borrowing here
+ |
+LL | let y: &X;
+ | +
error[E0277]: the size for values of type `Y` cannot be known at compilation time
--> $DIR/unsized6.rs:17:12
LL - fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
LL + fn f3<X>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
|
+help: consider borrowing here
+ |
+LL | let y: &X = *x1;
+ | +
error[E0277]: the size for values of type `X` cannot be known at compilation time
--> $DIR/unsized6.rs:24:9
LL - fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
LL + fn f4<X: T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
|
+help: consider borrowing here
+ |
+LL | let y: &X = *x1;
+ | +
error[E0277]: the size for values of type `X` cannot be known at compilation time
--> $DIR/unsized6.rs:32:9
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0208`.
error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0208`.
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0208`.
error: aborting due to 7 previous errors
+For more information about this error, try `rustc --explain E0208`.
error: aborting due to 5 previous errors
+For more information about this error, try `rustc --explain E0208`.
error: aborting due to 4 previous errors
+For more information about this error, try `rustc --explain E0208`.
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0208`.
error: aborting due to 5 previous errors
+For more information about this error, try `rustc --explain E0208`.
error: aborting due to 6 previous errors
+For more information about this error, try `rustc --explain E0208`.
error[E0277]: the trait bound `<<Self as TraitC<E>>::TypeC<'a> as TraitB>::TypeB: TraitA` is not satisfied
- --> $DIR/issue-103573.rs:18:5
+ --> $DIR/issue-103573.rs:18:18
|
LL | fn g<'a>(_: &<<Self::TypeC<'a> as TraitB>::TypeB as TraitA>::TypeA);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitA` is not implemented for `<<Self as TraitC<E>>::TypeC<'a> as TraitB>::TypeB`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitA` is not implemented for `<<Self as TraitC<E>>::TypeC<'a> as TraitB>::TypeB`
|
help: consider further restricting the associated type
|
error[E0277]: the trait bound `(): Foo` is not satisfied
- --> $DIR/wf-foreign-fn-decl-ret.rs:11:5
+ --> $DIR/wf-foreign-fn-decl-ret.rs:11:25
|
LL | pub fn lint_me() -> <() as Foo>::Assoc;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+ | ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied
--> $DIR/wf-foreign-fn-decl-ret.rs:14:32
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
--> $DIR/writing-to-immutable-vec.rs:3:5
|
-LL | let v: Vec<isize> = vec![1, 2, 3];
- | - help: consider changing this to be mutable: `mut v`
LL | v[1] = 4;
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut v: Vec<isize> = vec![1, 2, 3];
+ | +++
error: aborting due to previous error
| expected `f64`, found `&f64`
| help: change the parameter type to match the trait: `f64`
|
- = note: expected fn pointer `fn(Vec1, f64) -> Vec1`
- found fn pointer `fn(Vec1, &f64) -> Vec1`
+ = note: expected signature `fn(Vec1, f64) -> Vec1`
+ found signature `fn(Vec1, &f64) -> Vec1`
error[E0053]: method `mul` has an incompatible type for trait
--> $DIR/wrong-mul-method-signature.rs:33:21
| expected struct `Vec2`, found `f64`
| help: change the parameter type to match the trait: `Vec2`
|
- = note: expected fn pointer `fn(Vec2, Vec2) -> f64`
- found fn pointer `fn(Vec2, f64) -> Vec2`
+ = note: expected signature `fn(Vec2, Vec2) -> f64`
+ found signature `fn(Vec2, f64) -> Vec2`
error[E0053]: method `mul` has an incompatible type for trait
--> $DIR/wrong-mul-method-signature.rs:52:29
| expected `i32`, found `f64`
| help: change the output type to match the trait: `i32`
|
- = note: expected fn pointer `fn(Vec3, _) -> i32`
- found fn pointer `fn(Vec3, _) -> f64`
+ = note: expected signature `fn(Vec3, _) -> i32`
+ found signature `fn(Vec3, _) -> f64`
error[E0308]: mismatched types
--> $DIR/wrong-mul-method-signature.rs:63:45
+++ /dev/null
-// run-pass
-// This test checks if an unstable feature is enabled with the -Zcrate-attr=feature(foo) flag. If
-// the exact feature used here is causing problems feel free to replace it with another
-// perma-unstable feature.
-
-// compile-flags: -Zcrate-attr=feature(abi_unadjusted)
-
-#![allow(dead_code)]
-
-extern "unadjusted" fn foo() {}
-
-fn main() {}
"aarch64-apple-darwin",
"aarch64-apple-ios",
"aarch64-apple-ios-sim",
- "aarch64-fuchsia",
+ "aarch64-unknown-fuchsia",
"aarch64-linux-android",
"aarch64-pc-windows-msvc",
"aarch64-unknown-hermit",
"x86_64-apple-darwin",
"x86_64-apple-ios",
"x86_64-fortanix-unknown-sgx",
- "x86_64-fuchsia",
+ "x86_64-unknown-fuchsia",
"x86_64-linux-android",
"x86_64-pc-windows-gnu",
"x86_64-pc-windows-msvc",
--- /dev/null
+[package]
+name = "build_helper"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
--- /dev/null
+use std::process::Command;
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum CiEnv {
+ /// Not a CI environment.
+ None,
+ /// The Azure Pipelines environment, for Linux (including Docker), Windows, and macOS builds.
+ AzurePipelines,
+ /// The GitHub Actions environment, for Linux (including Docker), Windows and macOS builds.
+ GitHubActions,
+}
+
+impl CiEnv {
+ /// Obtains the current CI environment.
+ pub fn current() -> CiEnv {
+ if std::env::var("TF_BUILD").map_or(false, |e| e == "True") {
+ CiEnv::AzurePipelines
+ } else if std::env::var("GITHUB_ACTIONS").map_or(false, |e| e == "true") {
+ CiEnv::GitHubActions
+ } else {
+ CiEnv::None
+ }
+ }
+
+ pub fn is_ci() -> bool {
+ Self::current() != CiEnv::None
+ }
+
+ /// If in a CI environment, forces the command to run with colors.
+ pub fn force_coloring_in_ci(self, cmd: &mut Command) {
+ if self != CiEnv::None {
+ // Due to use of stamp/docker, the output stream of rustbuild is not
+ // a TTY in CI, so coloring is by-default turned off.
+ // The explicit `TERM=xterm` environment is needed for
+ // `--color always` to actually work. This env var was lost when
+ // compiling through the Makefile. Very strange.
+ cmd.env("TERM", "xterm").args(&["--color", "always"]);
+ }
+ }
+}
--- /dev/null
+use std::{path::Path, process::Command};
+
+/// Finds the remote for rust-lang/rust.
+/// For example for these remotes it will return `upstream`.
+/// ```text
+/// origin https://github.com/Nilstrieb/rust.git (fetch)
+/// origin https://github.com/Nilstrieb/rust.git (push)
+/// upstream https://github.com/rust-lang/rust (fetch)
+/// upstream https://github.com/rust-lang/rust (push)
+/// ```
+pub fn get_rust_lang_rust_remote(git_dir: Option<&Path>) -> Result<String, String> {
+ let mut git = Command::new("git");
+ if let Some(git_dir) = git_dir {
+ git.current_dir(git_dir);
+ }
+ git.args(["config", "--local", "--get-regex", "remote\\..*\\.url"]);
+
+ let output = git.output().map_err(|err| format!("{err:?}"))?;
+ if !output.status.success() {
+ return Err("failed to execute git config command".to_owned());
+ }
+
+ let stdout = String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))?;
+
+ let rust_lang_remote = stdout
+ .lines()
+ .find(|remote| remote.contains("rust-lang"))
+ .ok_or_else(|| "rust-lang/rust remote not found".to_owned())?;
+
+ let remote_name =
+ rust_lang_remote.split('.').nth(1).ok_or_else(|| "remote name not found".to_owned())?;
+ Ok(remote_name.into())
+}
+
+pub fn rev_exists(rev: &str, git_dir: Option<&Path>) -> Result<bool, String> {
+ let mut git = Command::new("git");
+ if let Some(git_dir) = git_dir {
+ git.current_dir(git_dir);
+ }
+ git.args(["rev-parse", rev]);
+ let output = git.output().map_err(|err| format!("{err:?}"))?;
+
+ match output.status.code() {
+ Some(0) => Ok(true),
+ Some(128) => Ok(false),
+ None => {
+ return Err(format!(
+ "git didn't exit properly: {}",
+ String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
+ ));
+ }
+ Some(code) => {
+ return Err(format!(
+ "git command exited with status code: {code}: {}",
+ String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
+ ));
+ }
+ }
+}
+
+/// Returns the master branch from which we can take diffs to see changes.
+/// This will usually be rust-lang/rust master, but sometimes this might not exist.
+/// This could be because the user is updating their forked master branch using the GitHub UI
+/// and therefore doesn't need an upstream master branch checked out.
+/// We will then fall back to origin/master in the hope that at least this exists.
+pub fn updated_master_branch(git_dir: Option<&Path>) -> Result<String, String> {
+ let upstream_remote = get_rust_lang_rust_remote(git_dir)?;
+ let upstream_master = format!("{upstream_remote}/master");
+ if rev_exists(&upstream_master, git_dir)? {
+ return Ok(upstream_master);
+ }
+
+ // We could implement smarter logic here in the future.
+ Ok("origin/master".into())
+}
--- /dev/null
+pub mod ci;
+pub mod git;
-use anyhow::Error;
+use anyhow::{Context, Error};
use curl::easy::Easy;
use indexmap::IndexMap;
use std::collections::HashMap;
comments: Vec<String>,
channel: Channel,
+ date: Option<String>,
version: [u16; 3],
checksums: IndexMap<String, String>,
}
impl Tool {
- fn new() -> Result<Self, Error> {
+ fn new(date: Option<String>) -> Result<Self, Error> {
let channel = match std::fs::read_to_string("src/ci/channel")?.trim() {
"stable" => Channel::Stable,
"beta" => Channel::Beta,
Ok(Self {
channel,
version,
+ date,
config: existing.config,
comments: existing.comments,
checksums: IndexMap::new(),
Channel::Nightly => "beta".to_string(),
};
- let manifest = fetch_manifest(&self.config, &channel)?;
+ let manifest = fetch_manifest(&self.config, &channel, self.date.as_deref())?;
self.collect_checksums(&manifest, COMPILER_COMPONENTS)?;
Ok(Stage0Toolchain {
date: manifest.date,
return Ok(None);
}
- let manifest = fetch_manifest(&self.config, "nightly")?;
+ let manifest = fetch_manifest(&self.config, "nightly", self.date.as_deref())?;
self.collect_checksums(&manifest, RUSTFMT_COMPONENTS)?;
Ok(Some(Stage0Toolchain { date: manifest.date, version: "nightly".into() }))
}
}
fn main() -> Result<(), Error> {
- let tool = Tool::new()?;
+ let tool = Tool::new(std::env::args().nth(1))?;
tool.update_json()?;
Ok(())
}
-fn fetch_manifest(config: &Config, channel: &str) -> Result<Manifest, Error> {
- Ok(toml::from_slice(&http_get(&format!(
- "{}/dist/channel-rust-{}.toml",
- config.dist_server, channel
- ))?)?)
+fn fetch_manifest(config: &Config, channel: &str, date: Option<&str>) -> Result<Manifest, Error> {
+ let url = if let Some(date) = date {
+ format!("{}/dist/{}/channel-rust-{}.toml", config.dist_server, date, channel)
+ } else {
+ format!("{}/dist/channel-rust-{}.toml", config.dist_server, channel)
+ };
+
+ Ok(toml::from_slice(&http_get(&url)?)?)
}
fn http_get(url: &str) -> Result<Vec<u8>, Error> {
data.extend_from_slice(new_data);
Ok(new_data.len())
})?;
- transfer.perform()?;
+ transfer.perform().context(format!("failed to fetch {url}"))?;
}
Ok(data)
}
-Subproject commit 2381cbdb4e9b07090f552d34a44a529b6e620e44
+Subproject commit 8c460b2237a6359a7e3335890db8da049bdd62fc
[`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const
[`float_equality_without_abs`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_equality_without_abs
[`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons
+[`fn_null_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_null_check
[`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools
[`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
[`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any
[`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none
[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
[`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
+[`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false
[`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters
[`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
[`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
[`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
[`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
[`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count
+[`size_of_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_ref
[`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
[`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
[`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
[`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
[`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
+[`transmute_null_to_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_null_to_fn
[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
[`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
[`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
diag.span_suggestion(
expr.span,
- &format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
+ format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
sugg,
rustc_errors::Applicability::HasPlaceholders,
);
fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let map = cx.tcx.hir();
if_chain! {
- if let Some(parent_id) = map.find_parent_node(expr.hir_id);
+ if let Some(parent_id) = map.opt_parent_id(expr.hir_id);
if let Some(parent) = map.find(parent_id);
then {
let expr = match parent {
crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO,
crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO,
+ crate::fn_null_check::FN_NULL_CHECK_INFO,
crate::format::USELESS_FORMAT_INFO,
crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO,
crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO,
crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO,
crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO,
crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO,
+ crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO,
crate::precedence::PRECEDENCE_INFO,
crate::ptr::CMP_NULL_INFO,
crate::ptr::INVALID_NULL_PTR_USAGE_INFO,
crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO,
crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO,
crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO,
+ crate::size_of_ref::SIZE_OF_REF_INFO,
crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO,
crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO,
crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO,
crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
+ crate::transmute::TRANSMUTE_NULL_TO_FN_INFO,
crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
crate::transmute::TRANSMUTE_PTR_TO_REF_INFO,
precedence: i8,
binder_args: &'tcx List<BoundVariableKind>,
) -> Position {
- let TyKind::Rptr(_, ty) = &ty.kind else {
+ let TyKind::Ref(_, ty) = &ty.kind else {
return Position::Other(precedence);
};
let mut ty = ty;
loop {
break match ty.ty.kind {
- TyKind::Rptr(_, ref ref_ty) => {
+ TyKind::Ref(_, ref ref_ty) => {
ty = ref_ty;
continue;
},
possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
}
let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
- // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
- // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
- // itself. See the comment in that method for an explanation as to why.
- possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
+ // If `place.local` were not included here, the `copyable_iterator::warn` test would fail. The
+ // reason is that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible
+ // borrower of itself. See the comment in that method for an explanation as to why.
+ possible_borrower.at_most_borrowers(cx, &[local, place.local], place.local, location)
&& used_exactly_once(mir, place.local).unwrap_or(false)
} else {
false
_ => return false,
}
- matches!(map.find(map.get_parent_node(id)), Some(Node::Param(_)))
+ matches!(map.find_parent(id), Some(Node::Param(_)))
}
impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
let map = &self.cx.tcx.hir();
if is_argument(*map, cmt.hir_id) {
// Skip closure arguments
- let parent_id = map.get_parent_node(cmt.hir_id);
- if let Some(Node::Expr(..)) = map.find(map.get_parent_node(parent_id)) {
+ let parent_id = map.parent_id(cmt.hir_id);
+ if let Some(Node::Expr(..)) = map.find_parent(parent_id) {
return;
}
let maybe_neg_sugg = |expr, hir_id| {
let sugg = Sugg::hir(cx, expr, "..");
if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id {
- format!("-{sugg}")
+ format!("-{}", sugg.maybe_par())
} else {
sugg.to_string()
}
--- /dev/null
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
+use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for comparing a function pointer to null.
+ ///
+ /// ### Why is this bad?
+ /// Function pointers are assumed to not be null.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */
+ ///
+ /// if (fn_ptr as *const ()).is_null() { ... }
+ /// ```
+ /// Use instead:
+ /// ```rust,ignore
+ /// let fn_ptr: Option<fn()> = /* somehow obtained nullable function pointer */
+ ///
+ /// if fn_ptr.is_none() { ... }
+ /// ```
+ #[clippy::version = "1.67.0"]
+ pub FN_NULL_CHECK,
+ correctness,
+ "`fn()` type assumed to be nullable"
+}
+declare_lint_pass!(FnNullCheck => [FN_NULL_CHECK]);
+
+fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ span_lint_and_help(
+ cx,
+ FN_NULL_CHECK,
+ expr.span,
+ "function pointer assumed to be nullable, even though it isn't",
+ None,
+ "try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value",
+ );
+}
+
+fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ if let ExprKind::Cast(cast_expr, cast_ty) = expr.kind
+ && let TyKind::Ptr(_) = cast_ty.kind
+ {
+ cx.typeck_results().expr_ty_adjusted(cast_expr).is_fn()
+ } else {
+ false
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for FnNullCheck {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ match expr.kind {
+ // Catching:
+ // (fn_ptr as *<const/mut> <ty>).is_null()
+ ExprKind::MethodCall(method_name, receiver, _, _)
+ if method_name.ident.as_str() == "is_null" && is_fn_ptr_cast(cx, receiver) =>
+ {
+ lint_expr(cx, expr);
+ },
+
+ ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => {
+ let to_check: &Expr<'_>;
+ if is_fn_ptr_cast(cx, left) {
+ to_check = right;
+ } else if is_fn_ptr_cast(cx, right) {
+ to_check = left;
+ } else {
+ return;
+ }
+
+ match to_check.kind {
+ // Catching:
+ // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>)
+ ExprKind::Cast(cast_expr, _) if is_integer_literal(cast_expr, 0) => {
+ lint_expr(cx, expr);
+ },
+
+ // Catching:
+ // (fn_ptr as *<const/mut> <ty>) == std::ptr::null()
+ ExprKind::Call(func, []) if is_path_diagnostic_item(cx, func, sym::ptr_null) => {
+ lint_expr(cx, expr);
+ },
+
+ // Catching:
+ // (fn_ptr as *<const/mut> <ty>) == <const that evaluates to null_ptr>
+ _ if matches!(
+ constant(cx, cx.typeck_results(), to_check),
+ Some((Constant::RawPtr(0), _))
+ ) =>
+ {
+ lint_expr(cx, expr);
+ },
+
+ _ => {},
+ }
+ },
+ _ => {},
+ }
+ }
+}
call_site,
&format!("`format!` in `{name}!` args"),
|diag| {
- diag.help(&format!(
+ diag.help(format!(
"combine the `format!(..)` arguments with the outer `{name}!(..)` call"
));
diag.help("or consider changing `format!` to `format_args!`");
/// arguments but are not marked `unsafe`.
///
/// ### Why is this bad?
- /// The function should probably be marked `unsafe`, since
- /// for an arbitrary raw pointer, there is no way of telling for sure if it is
- /// valid.
+ /// The function should almost definitely be marked `unsafe`, since for an
+ /// arbitrary raw pointer, there is no way of telling for sure if it is valid.
+ ///
+ /// In general, this lint should **never be disabled** unless it is definitely a
+ /// false positive (please submit an issue if so) since it breaks Rust's
+ /// soundness guarantees, directly exposing API users to potentially dangerous
+ /// program behavior. This is also true for internal APIs, as it is easy to leak
+ /// unsoundness.
+ ///
+ /// ### Context
+ /// In Rust, an `unsafe {...}` block is used to indicate that the code in that
+ /// section has been verified in some way that the compiler can not. For a
+ /// function that accepts a raw pointer then accesses the pointer's data, this is
+ /// generally impossible as the incoming pointer could point anywhere, valid or
+ /// not. So, the signature should be marked `unsafe fn`: this indicates that the
+ /// function's caller must provide some verification that the arguments it sends
+ /// are valid (and then call the function within an `unsafe` block).
///
/// ### Known problems
/// * It does not check functions recursively so if the pointer is passed to a
/// private non-`unsafe` function which does the dereferencing, the lint won't
- /// trigger.
+ /// trigger (false negative).
/// * It only checks for arguments whose type are raw pointers, not raw pointers
/// got from an argument in some other way (`fn foo(bar: &[*const u8])` or
- /// `some_argument.get_raw_ptr()`).
+ /// `some_argument.get_raw_ptr()`) (false negative).
///
/// ### Example
/// ```rust,ignore
/// pub fn foo(x: *const u8) {
/// println!("{}", unsafe { *x });
/// }
+ ///
+ /// // this call "looks" safe but will segfault or worse!
+ /// // foo(invalid_ptr);
/// ```
///
/// Use instead:
/// pub unsafe fn foo(x: *const u8) {
/// println!("{}", unsafe { *x });
/// }
+ ///
+ /// // this would cause a compiler error for calling without `unsafe`
+ /// // foo(invalid_ptr);
+ ///
+ /// // sound call if the caller knows the pointer is valid
+ /// unsafe { foo(valid_ptr); }
/// ```
#[clippy::version = "pre 1.29.0"]
pub NOT_UNSAFE_PTR_ARG_DEREF,
let map = cx.tcx.hir();
// Checking for slice indexing
- let parent_id = map.get_parent_node(expr.hir_id);
+ let parent_id = map.parent_id(expr.hir_id);
if let Some(hir::Node::Expr(parent_expr)) = map.find(parent_id);
if let hir::ExprKind::Index(_, index_expr) = parent_expr.kind;
if let Some((Constant::Int(index_value), _)) = constant(cx, cx.typeck_results(), index_expr);
if index_value < max_suggested_slice;
// Make sure that this slice index is read only
- let maybe_addrof_id = map.get_parent_node(parent_id);
+ let maybe_addrof_id = map.parent_id(parent_id);
if let Some(hir::Node::Expr(maybe_addrof_expr)) = map.find(maybe_addrof_id);
if let hir::ExprKind::AddrOf(_kind, hir::Mutability::Not, _inner_expr) = maybe_addrof_expr.kind;
then {
}
pub struct LargeConstArrays {
- maximum_allowed_size: u64,
+ maximum_allowed_size: u128,
}
impl LargeConstArrays {
#[must_use]
- pub fn new(maximum_allowed_size: u64) -> Self {
+ pub fn new(maximum_allowed_size: u128) -> Self {
Self { maximum_allowed_size }
}
}
if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind();
if let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx);
if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes());
- if self.maximum_allowed_size < element_count * element_size;
+ if self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size);
then {
let hi_pos = item.ident.span.lo() - BytePos::from_usize(1);
);
diag.span_label(
def.variants[variants_size[1].ind].span,
- &if variants_size[1].fields_size.is_empty() {
+ if variants_size[1].fields_size.is_empty() {
"the second-largest variant carries no data at all".to_owned()
} else {
format!(
}
pub struct LargeStackArrays {
- maximum_allowed_size: u64,
+ maximum_allowed_size: u128,
}
impl LargeStackArrays {
#[must_use]
- pub fn new(maximum_allowed_size: u64) -> Self {
+ pub fn new(maximum_allowed_size: u128) -> Self {
Self { maximum_allowed_size }
}
}
&& let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
&& !cx.tcx.hir().parent_iter(expr.hir_id)
.any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. })))
- && self.maximum_allowed_size < element_count * element_size {
+ && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) {
span_lint_and_help(
cx,
LARGE_STACK_ARRAYS,
db.span_note(span, "`is_empty` defined here");
}
if let Some(self_kind) = self_kind {
- db.note(&output.expected_sig(self_kind));
+ db.note(output.expected_sig(self_kind));
}
});
}
mod fallible_impl_from;
mod float_literal;
mod floating_point_arithmetic;
+mod fn_null_check;
mod format;
mod format_args;
mod format_impl;
mod partialeq_to_none;
mod pass_by_ref_or_value;
mod pattern_type_mismatch;
+mod permissions_set_readonly_false;
mod precedence;
mod ptr;
mod ptr_offset_with_cast;
mod single_char_lifetime_names;
mod single_component_path_imports;
mod size_of_in_element_count;
+mod size_of_ref;
mod slow_vector_initialization;
mod std_instead_of_core;
mod strings;
Ok(Some(path)) => path,
Ok(None) => return Conf::default(),
Err(error) => {
- sess.struct_err(&format!("error finding Clippy's configuration file: {error}"))
+ sess.struct_err(format!("error finding Clippy's configuration file: {error}"))
.emit();
return Conf::default();
},
store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock));
+ store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
+ store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
+ store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
// add lints here, do not remove this comment, it's used in `new_lint`
}
applicability,
);
- diag.note(&format!(
+ diag.note(format!(
"`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`"
));
},
if let Node::Pat(pat) = node;
if let PatKind::Binding(bind_ann, ..) = pat.kind;
if !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut));
- let parent_node = cx.tcx.hir().get_parent_node(hir_id);
+ let parent_node = cx.tcx.hir().parent_id(hir_id);
if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node);
if let Some(init) = parent_let_expr.init;
then {
let help = format!("make the function `async` and {ret_sugg}");
diag.span_suggestion(
header_span,
- &help,
+ help,
format!("async {}{ret_snip}", &header_snip[..ret_pos]),
Applicability::MachineApplicable
);
let input_lifetimes: Vec<LifetimeName> = inputs
.iter()
.filter_map(|ty| {
- if let TyKind::Rptr(lt, _) = ty.kind {
+ if let TyKind::Ref(lt, _) = ty.kind {
Some(lt.res)
} else {
None
/// Some may consider panicking in these situations to be desirable, but it also may
/// introduce panicking where there wasn't any before.
///
+ /// See also [the discussion in the
+ /// PR](https://github.com/rust-lang/rust-clippy/pull/9484#issuecomment-1278922613).
+ ///
/// ### Examples
/// ```rust
/// # let (input, min, max) = (0, -2, 1);
/// ```
#[clippy::version = "1.66.0"]
pub MANUAL_CLAMP,
- complexity,
+ nursery,
"using a clamp pattern instead of the clamp function"
}
impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]);
&& let Some(hir_id) = path_to_local(expr3)
&& let Some(Node::Pat(_)) = cx.tcx.hir().find(hir_id) {
// Apply only to params or locals with annotated types
- match cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
+ match cx.tcx.hir().find_parent(hir_id) {
Some(Node::Param(..)) => (),
Some(Node::Local(local)) => {
let Some(ty) = local.ty else { return };
let test_span = expr.span.until(then.span);
span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| {
- diag.span_note(test_span, &format!("the {kind_word} was tested here"));
+ diag.span_note(test_span, format!("the {kind_word} was tested here"));
multispan_sugg(
diag,
&format!("try using the `strip_{kind_word}` method"),
use clippy_utils::visitors::contains_unsafe_block;
use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id};
-use rustc_hir::LangItem::OptionSome;
+use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind};
use rustc_lint::LateContext;
use rustc_span::{sym, SyntaxContext};
if let Some(block_expr) = peels_blocks_incl_unsafe_opt(expr);
if let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind;
if let PatKind::Binding(_,target, ..) = pat.kind;
- if let (then_visitor, else_visitor)
- = (is_some_expr(cx, target, ctxt, then_expr),
- is_some_expr(cx, target, ctxt, else_expr));
- if then_visitor != else_visitor; // check that one expr resolves to `Some(x)`, the other to `None`
+ if is_some_expr(cx, target, ctxt, then_expr) && is_none_expr(cx, else_expr)
+ || is_none_expr(cx, then_expr) && is_some_expr(cx, target, ctxt, else_expr); // check that one expr resolves to `Some(x)`, the other to `None`
then {
return Some(SomeExpr {
expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()),
needs_unsafe_block: contains_unsafe_block(cx, expr),
- needs_negated: !then_visitor // if the `then_expr` resolves to `None`, need to negate the cond
+ needs_negated: is_none_expr(cx, then_expr) // if the `then_expr` resolves to `None`, need to negate the cond
})
}
};
false
}
+fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
+ return is_res_lang_ctor(cx, path_res(cx, inner_expr), OptionNone);
+ };
+ false
+}
+
// given the closure: `|<pattern>| <expr>`
// returns `|&<pattern>| <expr>`
fn add_ampersand_if_copy(body_str: String, has_copy_trait: bool) -> String {
};
// Do we need to add ';' to suggestion ?
- match match_body.kind {
- ExprKind::Block(block, _) => {
- // macro + expr_ty(body) == ()
- if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() {
- snippet_body.push(';');
- }
- },
- _ => {
- // expr_ty(body) == ()
- if cx.typeck_results().expr_ty(match_body).is_unit() {
- snippet_body.push(';');
- }
- },
+ if let ExprKind::Block(block, _) = match_body.kind {
+ // macro + expr_ty(body) == ()
+ if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() {
+ snippet_body.push(';');
+ }
}
let mut applicability = Applicability::MaybeIncorrect;
fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<AssignmentExpr> {
let map = &cx.tcx.hir();
- if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id)) {
- return match map.find(map.get_parent_node(parent_arm_expr.hir_id)) {
+ if let Some(Node::Expr(parent_arm_expr)) = map.find_parent(ex.hir_id) {
+ return match map.find_parent(parent_arm_expr.hir_id) {
Some(Node::Local(parent_let_expr)) => Some(AssignmentExpr::Local {
span: parent_let_expr.span,
pat_span: parent_let_expr.pat.span(),
// If the parent is already an arm, and the body is another match statement,
// we need curly braces around suggestion
- let parent_node_id = cx.tcx.hir().get_parent_node(match_expr.hir_id);
- if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) {
+ if let Node::Arm(arm) = &cx.tcx.hir().get_parent(match_expr.hir_id) {
if let ExprKind::Match(..) = arm.body.kind {
cbrace_end = format!("\n{indent}}}");
// Fix body indent due to the match
let mut has_non_wild = false;
for arm in arms {
match peel_hir_pat_refs(arm.pat).0.kind {
- PatKind::Wild => wildcard_span = Some(arm.pat.span),
+ PatKind::Wild if arm.guard.is_none() => wildcard_span = Some(arm.pat.span),
PatKind::Binding(_, _, ident, None) => {
wildcard_span = Some(arm.pat.span);
wildcard_ident = Some(ident);
expr.span,
&format!("calling `to_string` on `{arg_ty}`"),
|diag| {
- diag.help(&format!(
+ diag.help(format!(
"`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`"
));
let mut applicability = Applicability::MachineApplicable;
application = Applicability::Unspecified;
diag.span_help(
pat.span,
- &format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
+ format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
);
}
}
(Self::Unit, &hir::FnRetTy::Return(ty)) if is_unit(ty) => true,
(Self::Bool, &hir::FnRetTy::Return(ty)) if is_bool(ty) => true,
(Self::Any, &hir::FnRetTy::Return(ty)) if !is_unit(ty) => true,
- (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Rptr(_, _)),
+ (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Ref(_, _)),
_ => false,
}
}
suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, ")));
}
- diag.multipart_suggestion(&format!("use `{suggest}` instead"), suggestion, applicability);
+ diag.multipart_suggestion(format!("use `{suggest}` instead"), suggestion, applicability);
});
}
}
};
diag.span_suggestion_verbose(
local.span,
- &format!("try `{r}split_once`"),
+ format!("try `{r}split_once`"),
format!("let ({lhs}, {rhs}) = {self_snip}.{r}split_once({pat_snip}){unwrap};"),
app,
);
span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| {
diag.span_suggestion(
span,
- &format!("use `{simplify_using}(..)` instead"),
+ format!("use `{simplify_using}(..)` instead"),
format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")),
applicability,
);
let map = &vis.cx.tcx.hir();
let mut cur_id = vis.write_expr.hir_id;
loop {
- let parent_id = map.get_parent_node(cur_id);
+ let parent_id = map.parent_id(cur_id);
if parent_id == cur_id {
break;
}
return;
}
- if let hir::TyKind::Rptr(
+ if let hir::TyKind::Ref(
_,
hir::MutTy {
ty: pty,
},
) = ty.kind
{
- if let hir::TyKind::Rptr(
+ if let hir::TyKind::Ref(
_,
hir::MutTy {
mutbl: hir::Mutability::Mut,
check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl);
}
},
- TyKind::Rptr(lifetime, mut_ty) => {
+ TyKind::Ref(lifetime, mut_ty) => {
if_chain! {
if let TyKind::Path(None, path) = &mut_ty.ty.kind;
if let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind;
diag.span_suggestion(
assign.lhs_span,
- &format!("declare `{binding_name}` here"),
+ format!("declare `{binding_name}` here"),
let_snippet,
Applicability::MachineApplicable,
);
diag.span_suggestion_verbose(
usage.stmt.span.shrink_to_lo(),
- &format!("declare `{binding_name}` here"),
+ format!("declare `{binding_name}` here"),
format!("{let_snippet} = "),
applicability,
);
diag.span_suggestion_verbose(
usage.stmt.span.shrink_to_lo(),
- &format!("declare `{binding_name}` here"),
+ format!("declare `{binding_name}` here"),
format!("{let_snippet} = "),
applicability,
);
}
// Exclude non-inherent impls
- if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
+ if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
if matches!(
item.kind,
ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
let mut dereferenced_expr = expr;
let mut needs_check_adjustment = true;
loop {
- let parent_id = cx.tcx.hir().get_parent_node(cur_expr.hir_id);
+ let parent_id = cx.tcx.hir().parent_id(cur_expr.hir_id);
if parent_id == cur_expr.hir_id {
break;
}
if is_string { "string" } else { "byte string" }
),
|diag| {
- diag.help(&format!(
+ diag.help(format!(
"octal escapes are not supported, `\\0` is always a null {}",
if is_string { "character" } else { "byte" }
));
// suggestion 2: unambiguous null byte
diag.span_suggestion(
span,
- &format!(
+ format!(
"if the null {} is intended, disambiguate using",
if is_string { "character" } else { "byte" }
),
let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r));
diag.span_suggestion(
expr.span,
- &format!(
+ format!(
"did you mean `{snip_a} = {snip_a} {} {snip_r}` or `{long}`? Consider replacing it with",
op.as_str()
),
if is_copy(cx, ty)
&& let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes())
&& size <= self.ref_min_size
- && let hir::TyKind::Rptr(_, MutTy { ty: decl_ty, .. }) = input.kind
+ && let hir::TyKind::Ref(_, MutTy { ty: decl_ty, .. }) = input.kind
{
if let Some(typeck) = cx.maybe_typeck_results() {
// Don't lint if an unsafe pointer is created.
}
// Exclude non-inherent impls
- if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
+ if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
if matches!(
item.kind,
ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::paths;
+use clippy_utils::ty::match_type;
+use rustc_ast::ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`.
+ ///
+ /// ### Why is this bad?
+ /// On Unix platforms this results in the file being world writable,
+ /// equivalent to `chmod a+w <file>`.
+ /// ### Example
+ /// ```rust
+ /// use std::fs::File;
+ /// let f = File::create("foo.txt").unwrap();
+ /// let metadata = f.metadata().unwrap();
+ /// let mut permissions = metadata.permissions();
+ /// permissions.set_readonly(false);
+ /// ```
+ #[clippy::version = "1.66.0"]
+ pub PERMISSIONS_SET_READONLY_FALSE,
+ suspicious,
+ "Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`"
+}
+declare_lint_pass!(PermissionsSetReadonlyFalse => [PERMISSIONS_SET_READONLY_FALSE]);
+
+impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+ if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind
+ && match_type(cx, cx.typeck_results().expr_ty(receiver), &paths::PERMISSIONS)
+ && path.ident.name == sym!(set_readonly)
+ && let ExprKind::Lit(lit) = &arg.kind
+ && LitKind::Bool(false) == lit.node
+ {
+ span_lint_and_then(
+ cx,
+ PERMISSIONS_SET_READONLY_FALSE,
+ expr.span,
+ "call to `set_readonly` with argument `false`",
+ |diag| {
+ diag.note("on Unix platforms this results in the file being world writable");
+ diag.help("you can set the desired permissions using `PermissionsExt`. For more information, see\n\
+ https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html");
+ }
+ );
+ }
+ }
+}
if let ty::Ref(_, ty, mutability) = *ty.kind();
if let ty::Adt(adt, substs) = *ty.kind();
- if let TyKind::Rptr(lt, ref ty) = hir_ty.kind;
+ if let TyKind::Ref(lt, ref ty) = hir_ty.kind;
if let TyKind::Path(QPath::Resolved(None, path)) = ty.ty.kind;
// Check that the name as typed matches the actual name of the type.
fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Option<&'tcx Body<'_>>) {
if let FnRetTy::Return(ty) = sig.decl.output
- && let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty)
+ && let Some((out, Mutability::Mut, _)) = get_ref_lm(ty)
{
let out_region = cx.tcx.named_region(out.hir_id);
let args: Option<Vec<_>> = sig
.decl
.inputs
.iter()
- .filter_map(get_rptr_lm)
+ .filter_map(get_ref_lm)
.filter(|&(lt, _, _)| cx.tcx.named_region(lt.hir_id) == out_region)
.map(|(_, mutability, span)| (mutability == Mutability::Not).then_some(span))
.collect();
})
}
-fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
- if let TyKind::Rptr(lt, ref m) = ty.kind {
+fn get_ref_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
+ if let TyKind::Ref(lt, ref m) = ty.kind {
Some((lt, m.mutbl, ty.span))
} else {
None
// `res = clone(arg)` can be turned into `res = move arg;`
// if `arg` is the only borrow of `cloned` at this point.
- if cannot_move_out || !possible_borrower.only_borrowers(&[arg], cloned, loc) {
+ if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg], cloned, loc) {
continue;
}
// StorageDead(pred_arg);
// res = to_path_buf(cloned);
// ```
- if cannot_move_out || !possible_borrower.only_borrowers(&[arg, cloned], local, loc) {
+ if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg, cloned], local, loc) {
continue;
}
}
},
// This is what we are looking for !
- TyKind::Rptr(ref optional_lifetime, ref borrow_type) => {
+ TyKind::Ref(ref optional_lifetime, ref borrow_type) => {
// Match the 'static lifetime
if let Some(lifetime) = *optional_lifetime {
match borrow_type.ty.kind {
impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
if_chain! {
- if let TyKind::Rptr(_, ref mut_ty) = ty.kind;
+ if let TyKind::Ref(_, ref mut_ty) = ty.kind;
if mut_ty.mutbl == Mutability::Not;
if let TyKind::Path(ref qpath) = &mut_ty.ty.kind;
let last = last_path_segment(qpath);
GenericArg::Type(inner_ty) => Some(inner_ty),
_ => None,
});
- if let TyKind::Rptr(_, ref inner_mut_ty) = inner_ty.kind;
+ if let TyKind::Ref(_, ref inner_mut_ty) = inner_ty.kind;
if inner_mut_ty.mutbl == Mutability::Not;
then {
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind};
+use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, LangItem, MatchSource, PatKind, QPath, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind;
match &peeled_drop_expr.kind {
// simple return is always "bad"
ExprKind::Ret(ref inner) => {
+ // if desugar of `do yeet`, don't lint
+ if let Some(inner_expr) = inner
+ && let ExprKind::Call(path_expr, _) = inner_expr.kind
+ && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind {
+ return;
+ }
if cx.tcx.hir().attrs(expr.hir_id).is_empty() {
let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
if !borrows {
|diag| {
diag.span_note(
trait_method_span,
- &format!("existing `{method_name}` defined here"),
+ format!("existing `{method_name}` defined here"),
);
},
);
// iterate on trait_spans?
diag.span_note(
trait_spans[0],
- &format!("existing `{method_name}` defined here"),
+ format!("existing `{method_name}` defined here"),
);
},
);
--- /dev/null
+use clippy_utils::{diagnostics::span_lint_and_help, path_def_id, ty::peel_mid_ty_refs};
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// Checks for calls to `std::mem::size_of_val()` where the argument is
+ /// a reference to a reference.
+ ///
+ /// ### Why is this bad?
+ ///
+ /// Calling `size_of_val()` with a reference to a reference as the argument
+ /// yields the size of the reference-type, not the size of the value behind
+ /// the reference.
+ ///
+ /// ### Example
+ /// ```rust
+ /// struct Foo {
+ /// buffer: [u8],
+ /// }
+ ///
+ /// impl Foo {
+ /// fn size(&self) -> usize {
+ /// // Note that `&self` as an argument is a `&&Foo`: Because `self`
+ /// // is already a reference, `&self` is a double-reference.
+ /// // The return value of `size_of_val()` therefor is the
+ /// // size of the reference-type, not the size of `self`.
+ /// std::mem::size_of_val(&self)
+ /// }
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// struct Foo {
+ /// buffer: [u8],
+ /// }
+ ///
+ /// impl Foo {
+ /// fn size(&self) -> usize {
+ /// // Correct
+ /// std::mem::size_of_val(self)
+ /// }
+ /// }
+ /// ```
+ #[clippy::version = "1.67.0"]
+ pub SIZE_OF_REF,
+ suspicious,
+ "Argument to `std::mem::size_of_val()` is a double-reference, which is almost certainly unintended"
+}
+declare_lint_pass!(SizeOfRef => [SIZE_OF_REF]);
+
+impl LateLintPass<'_> for SizeOfRef {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
+ if let ExprKind::Call(path, [arg]) = expr.kind
+ && let Some(def_id) = path_def_id(cx, path)
+ && cx.tcx.is_diagnostic_item(sym::mem_size_of_val, def_id)
+ && let arg_ty = cx.typeck_results().expr_ty(arg)
+ && peel_mid_ty_refs(arg_ty).1 > 1
+ {
+ span_lint_and_help(
+ cx,
+ SIZE_OF_REF,
+ expr.span,
+ "argument to `std::mem::size_of_val()` is a reference to a reference",
+ None,
+ "dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type",
+ );
+ }
+ }
+}
applicability,
);
if !is_xor_based {
- diag.note(&format!("or maybe you should use `{sugg}::mem::replace`?"));
+ diag.note(format!("or maybe you should use `{sugg}::mem::replace`?"));
}
},
);
Applicability::MaybeIncorrect,
);
diag.note(
- &format!("or maybe you should use `{sugg}::mem::replace`?")
+ format!("or maybe you should use `{sugg}::mem::replace`?")
);
}
});
mod transmute_int_to_bool;
mod transmute_int_to_char;
mod transmute_int_to_float;
+mod transmute_null_to_fn;
mod transmute_num_to_bytes;
mod transmute_ptr_to_ptr;
mod transmute_ptr_to_ref;
"transmutes from a null pointer to a reference, which is undefined behavior"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for null function pointer creation through transmute.
+ ///
+ /// ### Why is this bad?
+ /// Creating a null function pointer is undefined behavior.
+ ///
+ /// More info: https://doc.rust-lang.org/nomicon/ffi.html#the-nullable-pointer-optimization
+ ///
+ /// ### Known problems
+ /// Not all cases can be detected at the moment of this writing.
+ /// For example, variables which hold a null pointer and are then fed to a `transmute`
+ /// call, aren't detectable yet.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let null_fn: fn() = unsafe { std::mem::transmute( std::ptr::null::<()>() ) };
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let null_fn: Option<fn()> = None;
+ /// ```
+ #[clippy::version = "1.67.0"]
+ pub TRANSMUTE_NULL_TO_FN,
+ correctness,
+ "transmute results in a null function pointer, which is undefined behavior"
+}
+
pub struct Transmute {
msrv: Msrv,
}
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
TRANSMUTE_UNDEFINED_REPR,
TRANSMUTING_NULL,
+ TRANSMUTE_NULL_TO_FN,
]);
impl Transmute {
#[must_use]
let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
| crosspointer_transmute::check(cx, e, from_ty, to_ty)
| transmuting_null::check(cx, e, arg, to_ty)
+ | transmute_null_to_fn::check(cx, e, arg, to_ty)
| transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv)
| transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
| transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
--- /dev/null
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+use rustc_span::symbol::sym;
+
+use super::TRANSMUTE_NULL_TO_FN;
+
+fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ span_lint_and_then(
+ cx,
+ TRANSMUTE_NULL_TO_FN,
+ expr.span,
+ "transmuting a known null pointer into a function pointer",
+ |diag| {
+ diag.span_label(expr.span, "this transmute results in undefined behavior");
+ diag.help(
+ "try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value"
+ );
+ },
+ );
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, to_ty: Ty<'tcx>) -> bool {
+ if !to_ty.is_fn() {
+ return false;
+ }
+
+ match arg.kind {
+ // Catching:
+ // transmute over constants that resolve to `null`.
+ ExprKind::Path(ref _qpath)
+ if matches!(constant(cx, cx.typeck_results(), arg), Some((Constant::RawPtr(0), _))) =>
+ {
+ lint_expr(cx, expr);
+ true
+ },
+
+ // Catching:
+ // `std::mem::transmute(0 as *const i32)`
+ ExprKind::Cast(inner_expr, _cast_ty) if is_integer_literal(inner_expr, 0) => {
+ lint_expr(cx, expr);
+ true
+ },
+
+ // Catching:
+ // `std::mem::transmute(std::ptr::null::<i32>())`
+ ExprKind::Call(func1, []) if is_path_diagnostic_item(cx, func1, sym::ptr_null) => {
+ lint_expr(cx, expr);
+ true
+ },
+
+ _ => {
+ // FIXME:
+ // Also catch transmutations of variables which are known nulls.
+ // To do this, MIR const propagation seems to be the better tool.
+ // Whenever MIR const prop routines are more developed, this will
+ // become available. As of this writing (25/03/19) it is not yet.
+ false
+ },
+ }
+}
/// Gets the type `Bar` in `…::transmute<Foo, &Bar>`.
fn get_explicit_type<'tcx>(path: &'tcx Path<'tcx>) -> Option<&'tcx hir::Ty<'tcx>> {
if let GenericArg::Type(ty) = path.segments.last()?.args?.args.get(1)?
- && let TyKind::Rptr(_, ty) = &ty.kind
+ && let TyKind::Ref(_, ty) = &ty.kind
{
Some(ty.ty)
} else {
&format!("transmute from `{from_ty_orig}` which has an undefined layout"),
|diag| {
if from_ty_orig.peel_refs() != from_ty.peel_refs() {
- diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+ diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
}
},
);
&format!("transmute to `{to_ty_orig}` which has an undefined layout"),
|diag| {
if to_ty_orig.peel_refs() != to_ty.peel_refs() {
- diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+ diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
}
},
);
),
|diag| {
if let Some(same_adt_did) = same_adt_did {
- diag.note(&format!(
+ diag.note(format!(
"two instances of the same generic type (`{}`) may have different layouts",
cx.tcx.item_name(same_adt_did)
));
} else {
if from_ty_orig.peel_refs() != from_ty {
- diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+ diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
}
if to_ty_orig.peel_refs() != to_ty {
- diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+ diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
}
}
},
&format!("transmute from `{from_ty_orig}` which has an undefined layout"),
|diag| {
if from_ty_orig.peel_refs() != from_ty {
- diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+ diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
}
},
);
&format!("transmute into `{to_ty_orig}` which has an undefined layout"),
|diag| {
if to_ty_orig.peel_refs() != to_ty {
- diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+ diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
}
},
);
&format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
|diag| {
if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
- let sugg = arg.as_ty(&to_ty.to_string()).to_string();
+ let sugg = arg.as_ty(to_ty.to_string()).to_string();
diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
}
},
// Catching transmute over constants that resolve to `null`.
let mut const_eval_context = constant_context(cx, cx.typeck_results());
if let ExprKind::Path(ref _qpath) = arg.kind &&
- let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg) &&
- x == 0
+ let Some(Constant::RawPtr(0)) = const_eval_context.expr(arg)
{
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
return true;
"transmute from an integer to a pointer",
|diag| {
if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
- diag.span_suggestion(e.span, "try", arg.as_ty(&to_ty.to_string()), Applicability::Unspecified);
+ diag.span_suggestion(e.span, "try", arg.as_ty(to_ty.to_string()), Applicability::Unspecified);
}
},
);
QPath::LangItem(..) => {},
}
},
- TyKind::Rptr(lt, ref mut_ty) => {
+ TyKind::Ref(lt, ref mut_ty) => {
context.is_nested_call = true;
if !borrowed_box::check(cx, hir_ty, lt, mut_ty) {
self.check_ty(cx, mut_ty.ty, context);
&format!("usage of `{outer_sym}<{generic_snippet}>`"),
|diag| {
diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability);
- diag.note(&format!(
+ diag.note(format!(
"`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap"
));
},
format!("{outer_sym}<{generic_snippet}>"),
applicability,
);
- diag.note(&format!(
+ diag.note(format!(
"`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
));
},
hir_ty.span,
&format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
|diag| {
- diag.note(&format!(
+ diag.note(format!(
"`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
));
- diag.help(&format!(
+ diag.help(format!(
"consider using just `{outer_sym}<{generic_snippet}>` or `{inner_sym}<{generic_snippet}>`"
));
},
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
let (add_score, sub_nest) = match ty.kind {
// _, &x and *x have only small overhead; don't mess with nesting level
- TyKind::Infer | TyKind::Ptr(..) | TyKind::Rptr(..) => (1, 0),
+ TyKind::Infer | TyKind::Ptr(..) | TyKind::Ref(..) => (1, 0),
// the "normal" components of a type: named types, arrays/tuples
TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
GenericArg::Type(ty) => Some(ty),
_ => None,
});
- if let TyKind::Rptr(..) = ty.kind;
+ if let TyKind::Ref(..) = ty.kind;
then {
return Some(ty.span);
}
return;
}
let map = &cx.tcx.hir();
- let opt_parent_node = map.find(map.get_parent_node(expr.hir_id));
+ let opt_parent_node = map.find_parent(expr.hir_id);
if_chain! {
if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node;
if is_questionmark_desugar_marked_call(parent_expr);
if arg_snippets_without_empty_blocks.is_empty() {
db.multipart_suggestion(
- &format!("use {singular}unit literal{plural} instead"),
+ format!("use {singular}unit literal{plural} instead"),
args_to_recover
.iter()
.map(|arg| (arg.span, "()".to_string()))
let it_or_them = if plural { "them" } else { "it" };
db.span_suggestion(
expr.span,
- &format!(
+ format!(
"{or}move the expression{empty_or_s} in front of the call and replace {it_or_them} with the unit literal `()`"
),
sugg,
let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent)));
// expr is not in a block statement or result expression position, wrap in a block
- let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(call_expr.hir_id));
+ let parent_node = cx.tcx.hir().find_parent(call_expr.hir_id);
if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) {
let block_indent = call_expr_indent + 4;
stmts_and_call_snippet =
}
// Abort if the method is implementing a trait or of it a trait method.
- if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
+ if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
if matches!(
item.kind,
ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
use clippy_utils::source::{snippet, snippet_with_macro_callsite};
use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts};
-use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, paths};
+use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts};
+use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
}
}
if is_trait_method(cx, e, sym::IntoIterator) && name.ident.name == sym::into_iter {
- if let Some(parent_expr) = get_parent_expr(cx, e) {
- if let ExprKind::MethodCall(parent_name, ..) = parent_expr.kind {
- if parent_name.ident.name != sym::into_iter {
- return;
- }
- }
+ if get_parent_expr(cx, e).is_some() &&
+ let Some(id) = path_to_local(recv) &&
+ let Node::Pat(pat) = cx.tcx.hir().get(id) &&
+ let PatKind::Binding(ann, ..) = pat.kind &&
+ ann != BindingAnnotation::MUT
+ {
+ // Do not remove .into_iter() applied to a non-mutable local variable used in
+ // a larger expression context as it would differ in mutability.
+ return;
}
+
let a = cx.typeck_results().expr_ty(e);
let b = cx.typeck_results().expr_ty(recv);
- if same_type_and_consts(a, b) {
+
+ // If the types are identical then .into_iter() can be removed, unless the type
+ // implements Copy, in which case .into_iter() returns a copy of the receiver and
+ // cannot be safely omitted.
+ if same_type_and_consts(a, b) && !is_copy(cx, b) {
let sugg = snippet(cx, recv.span, "<expr>").into_owned();
span_lint_and_sugg(
cx,
/// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS.
///
/// The maximum allowed size for arrays on the stack
- (array_size_threshold: u64 = 512_000),
+ (array_size_threshold: u128 = 512_000),
/// Lint: VEC_BOX.
///
/// The size of the boxed type in bytes, where boxing in a `Vec` is allowed
}
pub(super) fn is_lint_ref_type(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
- if let TyKind::Rptr(
+ if let TyKind::Ref(
_,
MutTy {
ty: inner,
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
writeln!(
f,
- "* `{}`: `{}`: {} (defaults to `{}`)",
- self.name, self.config_type, self.doc, self.default
+ "* `{}`: `{}`(defaults to `{}`): {}",
+ self.name, self.config_type, self.default, self.doc
)
}
}
fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
let map = cx.tcx.hir();
- match map.find(map.get_parent_node(hir_id)) {
+ match map.find_parent((hir_id)) {
Some(hir::Node::Local(local)) => Some(local),
Some(hir::Node::Pat(pattern)) => get_parent_local_hir_id(cx, pattern.hir_id),
_ => None,
match peel_hir_expr_refs(expr).0.kind {
ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) {
Res::Local(hir_id) => {
- let parent_id = cx.tcx.hir().get_parent_node(hir_id);
+ let parent_id = cx.tcx.hir().parent_id(hir_id);
if let Some(Node::Local(Local { init: Some(init), .. })) = cx.tcx.hir().find(parent_id) {
path_to_matched_type(cx, init)
} else {
// print!("\n"), write!(f, "\n")
diag.multipart_suggestion(
- &format!("use `{name}ln!` instead"),
+ format!("use `{name}ln!` instead"),
vec![(name_span, format!("{name}ln")), (format_string_span, String::new())],
Applicability::MachineApplicable,
);
let newline_span = format_string_span.with_lo(hi - BytePos(3)).with_hi(hi - BytePos(1));
diag.multipart_suggestion(
- &format!("use `{name}ln!` instead"),
+ format!("use `{name}ln!` instead"),
vec![(name_span, format!("{name}ln")), (newline_span, String::new())],
Applicability::MachineApplicable,
);
(Slice(l), Slice(r)) => eq_ty(l, r),
(Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value),
(Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty),
- (Rptr(ll, l), Rptr(rl, r)) => {
+ (Ref(ll, l), Ref(rl, r)) => {
both(ll, rl, |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
},
(BareFn(l), BareFn(r)) => {
ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
int.try_into().expect("invalid f64 bit representation"),
))),
- ty::RawPtr(type_and_mut) => {
- if let ty::Uint(_) = type_and_mut.ty.kind() {
- return Some(Constant::RawPtr(int.assert_bits(int.size())));
- }
- None
- },
+ ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
// FIXME: implement other conversions.
_ => None,
}
fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) {
if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
if let Some(lint) = lint.name_lower().strip_prefix("clippy::") {
- diag.help(&format!(
+ diag.help(format!(
"for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}",
&option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
// extract just major + minor version and ignore patch versions
(&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
(&TyKind::Array(lt, ll), &TyKind::Array(rt, rl)) => self.eq_ty(lt, rt) && self.eq_array_length(ll, rl),
(TyKind::Ptr(l_mut), TyKind::Ptr(r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(l_mut.ty, r_mut.ty),
- (TyKind::Rptr(_, l_rmut), TyKind::Rptr(_, r_rmut)) => {
+ (TyKind::Ref(_, l_rmut), TyKind::Ref(_, r_rmut)) => {
l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(l_rmut.ty, r_rmut.ty)
},
(TyKind::Path(l), TyKind::Path(r)) => self.eq_qpath(l, r),
self.hash_ty(mut_ty.ty);
mut_ty.mutbl.hash(&mut self.s);
},
- TyKind::Rptr(lifetime, ref mut_ty) => {
+ TyKind::Ref(lifetime, ref mut_ty) => {
self.hash_lifetime(lifetime);
self.hash_ty(mut_ty.ty);
mut_ty.mutbl.hash(&mut self.s);
if_chain! {
if let Some(Node::Pat(pat)) = hir.find(hir_id);
if matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..));
- let parent = hir.get_parent_node(hir_id);
+ let parent = hir.parent_id(hir_id);
if let Some(Node::Local(local)) = hir.find(parent);
then {
return local.init;
/// Gets the parent node, if any.
pub fn get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option<Node<'_>> {
- tcx.hir().parent_iter(id).next().map(|(_, node)| node)
+ tcx.hir().find_parent(id)
}
/// Gets the parent expression, if any –- this is useful to constrain a lint.
/// }
/// ```
pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
- if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
+ if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
} else {
false
let mut count = 0;
loop {
match &ty.kind {
- TyKind::Rptr(_, ref_ty) => {
+ TyKind::Ref(_, ref_ty) => {
ty = ref_ty.ty;
count += 1;
},
+++ /dev/null
-use rustc_index::bit_set::BitSet;
-use rustc_middle::mir;
-use rustc_mir_dataflow::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis};
-
-/// Determines liveness of each local purely based on `StorageLive`/`Dead`.
-#[derive(Copy, Clone)]
-pub(super) struct MaybeStorageLive;
-
-impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
- type Domain = BitSet<mir::Local>;
- const NAME: &'static str = "maybe_storage_live";
-
- fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
- // bottom = dead
- BitSet::new_empty(body.local_decls.len())
- }
-
- fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
- for arg in body.args_iter() {
- state.insert(arg);
- }
- }
-}
-
-impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
- type Idx = mir::Local;
-
- fn statement_effect(&self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, _: mir::Location) {
- match stmt.kind {
- mir::StatementKind::StorageLive(l) => trans.gen(l),
- mir::StatementKind::StorageDead(l) => trans.kill(l),
- _ => (),
- }
- }
-
- fn terminator_effect(
- &self,
- _trans: &mut impl GenKill<Self::Idx>,
- _terminator: &mir::Terminator<'tcx>,
- _loc: mir::Location,
- ) {
- }
-
- fn call_return_effect(
- &self,
- _trans: &mut impl GenKill<Self::Idx>,
- _block: mir::BasicBlock,
- _return_places: CallReturnPlaces<'_, 'tcx>,
- ) {
- // Nothing to do when a call returns successfully
- }
-}
};
use rustc_middle::ty::TyCtxt;
-mod maybe_storage_live;
-
mod possible_borrower;
pub use possible_borrower::PossibleBorrowerMap;
-use super::{
- maybe_storage_live::MaybeStorageLive, possible_origin::PossibleOriginVisitor,
- transitive_relation::TransitiveRelation,
-};
+use super::possible_origin::PossibleOriginVisitor;
use crate::ty::is_copy;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_index::bit_set::{BitSet, HybridBitSet};
use rustc_lint::LateContext;
-use rustc_middle::mir::{self, visit::Visitor as _, Mutability};
-use rustc_middle::ty::{self, visit::TypeVisitor};
-use rustc_mir_dataflow::{Analysis, ResultsCursor};
+use rustc_middle::mir::{
+ self, visit::Visitor as _, BasicBlock, Local, Location, Mutability, Statement, StatementKind, Terminator,
+};
+use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt};
+use rustc_mir_dataflow::{
+ fmt::DebugWithContext, impls::MaybeStorageLive, lattice::JoinSemiLattice, Analysis, AnalysisDomain,
+ CallReturnPlaces, ResultsCursor,
+};
+use std::borrow::Cow;
use std::ops::ControlFlow;
/// Collects the possible borrowers of each local.
/// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
/// possible borrowers of `a`.
#[allow(clippy::module_name_repetitions)]
-struct PossibleBorrowerVisitor<'a, 'b, 'tcx> {
- possible_borrower: TransitiveRelation,
+struct PossibleBorrowerAnalysis<'b, 'tcx> {
+ tcx: TyCtxt<'tcx>,
body: &'b mir::Body<'tcx>,
- cx: &'a LateContext<'tcx>,
possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
}
-impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
- fn new(
- cx: &'a LateContext<'tcx>,
- body: &'b mir::Body<'tcx>,
- possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
- ) -> Self {
+#[derive(Clone, Debug, Eq, PartialEq)]
+struct PossibleBorrowerState {
+ map: FxIndexMap<Local, BitSet<Local>>,
+ domain_size: usize,
+}
+
+impl PossibleBorrowerState {
+ fn new(domain_size: usize) -> Self {
Self {
- possible_borrower: TransitiveRelation::default(),
- cx,
- body,
- possible_origin,
+ map: FxIndexMap::default(),
+ domain_size,
}
}
- fn into_map(
- self,
- cx: &'a LateContext<'tcx>,
- maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>,
- ) -> PossibleBorrowerMap<'b, 'tcx> {
- let mut map = FxHashMap::default();
- for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
- if is_copy(cx, self.body.local_decls[row].ty) {
- continue;
- }
+ #[allow(clippy::similar_names)]
+ fn add(&mut self, borrowed: Local, borrower: Local) {
+ self.map
+ .entry(borrowed)
+ .or_insert(BitSet::new_empty(self.domain_size))
+ .insert(borrower);
+ }
+}
- let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len());
- borrowers.remove(mir::Local::from_usize(0));
+impl<C> DebugWithContext<C> for PossibleBorrowerState {
+ fn fmt_with(&self, _ctxt: &C, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ <_ as std::fmt::Debug>::fmt(self, f)
+ }
+ fn fmt_diff_with(&self, _old: &Self, _ctxt: &C, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ unimplemented!()
+ }
+}
+
+impl JoinSemiLattice for PossibleBorrowerState {
+ fn join(&mut self, other: &Self) -> bool {
+ let mut changed = false;
+ for (&borrowed, borrowers) in other.map.iter() {
if !borrowers.is_empty() {
- map.insert(row, borrowers);
+ changed |= self
+ .map
+ .entry(borrowed)
+ .or_insert(BitSet::new_empty(self.domain_size))
+ .union(borrowers);
}
}
+ changed
+ }
+}
- let bs = BitSet::new_empty(self.body.local_decls.len());
- PossibleBorrowerMap {
- map,
- maybe_live,
- bitset: (bs.clone(), bs),
+impl<'b, 'tcx> AnalysisDomain<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
+ type Domain = PossibleBorrowerState;
+
+ const NAME: &'static str = "possible_borrower";
+
+ fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+ PossibleBorrowerState::new(body.local_decls.len())
+ }
+
+ fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _entry_set: &mut Self::Domain) {}
+}
+
+impl<'b, 'tcx> PossibleBorrowerAnalysis<'b, 'tcx> {
+ fn new(
+ tcx: TyCtxt<'tcx>,
+ body: &'b mir::Body<'tcx>,
+ possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
+ ) -> Self {
+ Self {
+ tcx,
+ body,
+ possible_origin,
}
}
}
-impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> {
- fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
- let lhs = place.local;
- match rvalue {
- mir::Rvalue::Ref(_, _, borrowed) => {
- self.possible_borrower.add(borrowed.local, lhs);
- },
- other => {
- if ContainsRegion
- .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty)
- .is_continue()
- {
- return;
- }
- rvalue_locals(other, |rhs| {
- if lhs != rhs {
- self.possible_borrower.add(rhs, lhs);
+impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
+ fn apply_call_return_effect(
+ &self,
+ _state: &mut Self::Domain,
+ _block: BasicBlock,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
+ ) {
+ }
+
+ fn apply_statement_effect(&self, state: &mut Self::Domain, statement: &Statement<'tcx>, _location: Location) {
+ if let StatementKind::Assign(box (place, rvalue)) = &statement.kind {
+ let lhs = place.local;
+ match rvalue {
+ mir::Rvalue::Ref(_, _, borrowed) => {
+ state.add(borrowed.local, lhs);
+ },
+ other => {
+ if ContainsRegion
+ .visit_ty(place.ty(&self.body.local_decls, self.tcx).ty)
+ .is_continue()
+ {
+ return;
}
- });
- },
+ rvalue_locals(other, |rhs| {
+ if lhs != rhs {
+ state.add(rhs, lhs);
+ }
+ });
+ },
+ }
}
}
- fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) {
+ fn apply_terminator_effect(&self, state: &mut Self::Domain, terminator: &Terminator<'tcx>, _location: Location) {
if let mir::TerminatorKind::Call {
args,
destination: mir::Place { local: dest, .. },
for y in mutable_variables {
for x in &immutable_borrowers {
- self.possible_borrower.add(*x, y);
+ state.add(*x, y);
}
for x in &mutable_borrowers {
- self.possible_borrower.add(*x, y);
+ state.add(*x, y);
}
}
}
}
}
-/// Result of `PossibleBorrowerVisitor`.
+/// Result of `PossibleBorrowerAnalysis`.
#[allow(clippy::module_name_repetitions)]
pub struct PossibleBorrowerMap<'b, 'tcx> {
- /// Mapping `Local -> its possible borrowers`
- pub map: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
- maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>,
- // Caches to avoid allocation of `BitSet` on every query
- pub bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
+ body: &'b mir::Body<'tcx>,
+ possible_borrower: ResultsCursor<'b, 'tcx, PossibleBorrowerAnalysis<'b, 'tcx>>,
+ maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'b>>,
+ pushed: BitSet<Local>,
+ stack: Vec<Local>,
}
-impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
- pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
+impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
+ pub fn new(cx: &LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
let possible_origin = {
let mut vis = PossibleOriginVisitor::new(mir);
vis.visit_body(mir);
vis.into_map(cx)
};
- let maybe_storage_live_result = MaybeStorageLive
+ let possible_borrower = PossibleBorrowerAnalysis::new(cx.tcx, mir, possible_origin)
.into_engine(cx.tcx, mir)
- .pass_name("redundant_clone")
+ .pass_name("possible_borrower")
.iterate_to_fixpoint()
.into_results_cursor(mir);
- let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
- vis.visit_body(mir);
- vis.into_map(cx, maybe_storage_live_result)
- }
-
- /// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`.
- pub fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool {
- self.bounded_borrowers(borrowers, borrowers, borrowed, at)
+ let maybe_live = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
+ .into_engine(cx.tcx, mir)
+ .pass_name("possible_borrower")
+ .iterate_to_fixpoint()
+ .into_results_cursor(mir);
+ PossibleBorrowerMap {
+ body: mir,
+ possible_borrower,
+ maybe_live,
+ pushed: BitSet::new_empty(mir.local_decls.len()),
+ stack: Vec::with_capacity(mir.local_decls.len()),
+ }
}
- /// Returns true if the set of borrowers of `borrowed` living at `at` includes at least `below`
- /// but no more than `above`.
- pub fn bounded_borrowers(
+ /// Returns true if the set of borrowers of `borrowed` living at `at` includes no more than
+ /// `borrowers`.
+ /// Notes:
+ /// 1. It would be nice if `PossibleBorrowerMap` could store `cx` so that `at_most_borrowers`
+ /// would not require it to be passed in. But a `PossibleBorrowerMap` is stored in `LintPass`
+ /// `Dereferencing`, which outlives any `LateContext`.
+ /// 2. In all current uses of `at_most_borrowers`, `borrowers` is a slice of at most two
+ /// elements. Thus, `borrowers.contains(...)` is effectively a constant-time operation. If
+ /// `at_most_borrowers`'s uses were to expand beyond this, its implementation might have to be
+ /// adjusted.
+ pub fn at_most_borrowers(
&mut self,
- below: &[mir::Local],
- above: &[mir::Local],
+ cx: &LateContext<'tcx>,
+ borrowers: &[mir::Local],
borrowed: mir::Local,
at: mir::Location,
) -> bool {
- self.maybe_live.seek_after_primary_effect(at);
+ if is_copy(cx, self.body.local_decls[borrowed].ty) {
+ return true;
+ }
- self.bitset.0.clear();
- let maybe_live = &mut self.maybe_live;
- if let Some(bitset) = self.map.get(&borrowed) {
- for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) {
- self.bitset.0.insert(b);
+ self.possible_borrower.seek_before_primary_effect(at);
+ self.maybe_live.seek_before_primary_effect(at);
+
+ let possible_borrower = &self.possible_borrower.get().map;
+ let maybe_live = &self.maybe_live;
+
+ self.pushed.clear();
+ self.stack.clear();
+
+ if let Some(borrowers) = possible_borrower.get(&borrowed) {
+ for b in borrowers.iter() {
+ if self.pushed.insert(b) {
+ self.stack.push(b);
+ }
}
} else {
- return false;
+ // Nothing borrows `borrowed` at `at`.
+ return true;
}
- self.bitset.1.clear();
- for b in below {
- self.bitset.1.insert(*b);
- }
-
- if !self.bitset.0.superset(&self.bitset.1) {
- return false;
- }
+ while let Some(borrower) = self.stack.pop() {
+ if maybe_live.contains(borrower) && !borrowers.contains(&borrower) {
+ return false;
+ }
- for b in above {
- self.bitset.0.remove(*b);
+ if let Some(borrowers) = possible_borrower.get(&borrower) {
+ for b in borrowers.iter() {
+ if self.pushed.insert(b) {
+ self.stack.push(b);
+ }
+ }
+ }
}
- self.bitset.0.is_empty()
+ true
}
pub fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {
) -> Self {
use rustc_ast::ast::RangeLimits;
- #[expect(clippy::match_wildcard_for_single_variants)]
match expr.kind {
_ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0),
ast::ExprKind::AddrOf(..)
let closure_body = cx.tcx.hir().body(body);
// is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`)
// a type annotation is present if param `kind` is different from `TyKind::Infer`
- let closure_arg_is_type_annotated_double_ref = if let TyKind::Rptr(_, MutTy { ty, .. }) = fn_decl.inputs[0].kind
+ let closure_arg_is_type_annotated_double_ref = if let TyKind::Ref(_, MutTy { ty, .. }) = fn_decl.inputs[0].kind
{
- matches!(ty.kind, TyKind::Rptr(_, MutTy { .. }))
+ matches!(ty.kind, TyKind::Ref(_, MutTy { .. }))
} else {
false
};
/// Returns the base type for HIR references and pointers.
pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
match ty.kind {
- TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty),
+ TyKind::Ptr(ref mut_ty) | TyKind::Ref(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty),
_ => ty,
}
}
[toolchain]
-channel = "nightly-2022-12-17"
+channel = "nightly-2022-12-29"
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
|
LL | let _h = async {
| _____________________-
-LL | | async {
- | | _________^
+LL | |/ async {
LL | || 3
LL | || }
| ||_________^ awaitable value not awaited
|
LL | let _j = async || {
| ________________________-
-LL | | async {
- | | _________^
+LL | |/ async {
LL | || 3
LL | || }
| ||_________^ awaitable value not awaited
--- /dev/null
+fn main() {
+ [0; usize::MAX];
+}
--- /dev/null
+error: statement with no effect
+ --> $DIR/ice-10044.rs:2:5
+ |
+LL | [0; usize::MAX];
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::no-effect` implied by `-D warnings`
+
+error: aborting due to previous error
+
let _ = (y as f32).mul_add(y as f32, x);
let _ = x.mul_add(x, y).sqrt();
let _ = y.mul_add(y, x).sqrt();
+
+ let _ = (x - 1.0).mul_add(x - 1.0, -y);
+ let _ = (x - 1.0).mul_add(x - 1.0, -y) + 3.0;
+ let _ = (x - 1.0).mul_add(x - 1.0, -(y + 3.0));
+ let _ = (y + 1.0).mul_add(-(y + 1.0), x);
+ let _ = (3.0 * y).mul_add(-(3.0 * y), x);
+ let _ = (y + 1.0 + x).mul_add(-(y + 1.0 + x), x);
+ let _ = (y + 1.0 + 2.0).mul_add(-(y + 1.0 + 2.0), x);
+
// Cases where the lint shouldn't be applied
let _ = x.powi(2);
let _ = x.powi(1 + 1);
let _ = x + (y as f32).powi(2);
let _ = (x.powi(2) + y).sqrt();
let _ = (x + y.powi(2)).sqrt();
+
+ let _ = (x - 1.0).powi(2) - y;
+ let _ = (x - 1.0).powi(2) - y + 3.0;
+ let _ = (x - 1.0).powi(2) - (y + 3.0);
+ let _ = x - (y + 1.0).powi(2);
+ let _ = x - (3.0 * y).powi(2);
+ let _ = x - (y + 1.0 + x).powi(2);
+ let _ = x - (y + 1.0 + 2.0).powi(2);
+
// Cases where the lint shouldn't be applied
let _ = x.powi(2);
let _ = x.powi(1 + 1);
LL | let _ = (x + y.powi(2)).sqrt();
| ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
-error: aborting due to 7 previous errors
+error: multiply and add expressions can be calculated more efficiently and accurately
+ --> $DIR/floating_point_powi.rs:18:13
+ |
+LL | let _ = (x - 1.0).powi(2) - y;
+ | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -y)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+ --> $DIR/floating_point_powi.rs:19:13
+ |
+LL | let _ = (x - 1.0).powi(2) - y + 3.0;
+ | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -y)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+ --> $DIR/floating_point_powi.rs:20:13
+ |
+LL | let _ = (x - 1.0).powi(2) - (y + 3.0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -(y + 3.0))`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+ --> $DIR/floating_point_powi.rs:21:13
+ |
+LL | let _ = x - (y + 1.0).powi(2);
+ | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0).mul_add(-(y + 1.0), x)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+ --> $DIR/floating_point_powi.rs:22:13
+ |
+LL | let _ = x - (3.0 * y).powi(2);
+ | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(3.0 * y).mul_add(-(3.0 * y), x)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+ --> $DIR/floating_point_powi.rs:23:13
+ |
+LL | let _ = x - (y + 1.0 + x).powi(2);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0 + x).mul_add(-(y + 1.0 + x), x)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+ --> $DIR/floating_point_powi.rs:24:13
+ |
+LL | let _ = x - (y + 1.0 + 2.0).powi(2);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0 + 2.0).mul_add(-(y + 1.0 + 2.0), x)`
+
+error: aborting due to 14 previous errors
--- /dev/null
+#![allow(unused)]
+#![warn(clippy::fn_null_check)]
+#![allow(clippy::cmp_null)]
+#![allow(clippy::ptr_eq)]
+#![allow(clippy::zero_ptr)]
+
+pub const ZPTR: *const () = 0 as *const _;
+pub const NOT_ZPTR: *const () = 1 as *const _;
+
+fn main() {
+ let fn_ptr = main;
+
+ if (fn_ptr as *mut ()).is_null() {}
+ if (fn_ptr as *const u8).is_null() {}
+ if (fn_ptr as *const ()) == std::ptr::null() {}
+ if (fn_ptr as *const ()) == (0 as *const ()) {}
+ if (fn_ptr as *const ()) == ZPTR {}
+
+ // no lint
+ if (fn_ptr as *const ()) == NOT_ZPTR {}
+}
--- /dev/null
+error: function pointer assumed to be nullable, even though it isn't
+ --> $DIR/fn_null_check.rs:13:8
+ |
+LL | if (fn_ptr as *mut ()).is_null() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+ = note: `-D clippy::fn-null-check` implied by `-D warnings`
+
+error: function pointer assumed to be nullable, even though it isn't
+ --> $DIR/fn_null_check.rs:14:8
+ |
+LL | if (fn_ptr as *const u8).is_null() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: function pointer assumed to be nullable, even though it isn't
+ --> $DIR/fn_null_check.rs:15:8
+ |
+LL | if (fn_ptr as *const ()) == std::ptr::null() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: function pointer assumed to be nullable, even though it isn't
+ --> $DIR/fn_null_check.rs:16:8
+ |
+LL | if (fn_ptr as *const ()) == (0 as *const ()) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: function pointer assumed to be nullable, even though it isn't
+ --> $DIR/fn_null_check.rs:17:8
+ |
+LL | if (fn_ptr as *const ()) == ZPTR {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: aborting due to 5 previous errors
+
},
None => None,
};
+
+ match Some(20) {
+ // Don't Lint, because `Some(3*x)` is not `None`
+ None => None,
+ Some(x) => {
+ if x > 0 {
+ Some(3 * x)
+ } else {
+ Some(x)
+ }
+ },
+ };
+
+ // Don't lint: https://github.com/rust-lang/rust-clippy/issues/10088
+ let result = if let Some(a) = maybe_some() {
+ if let Some(b) = maybe_some() {
+ Some(a + b)
+ } else {
+ Some(a)
+ }
+ } else {
+ None
+ };
+
+ let allowed_integers = vec![3, 4, 5, 6];
+ // Don't lint, since there's a side effect in the else branch
+ match Some(21) {
+ Some(x) => {
+ if allowed_integers.contains(&x) {
+ Some(x)
+ } else {
+ println!("Invalid integer: {x:?}");
+ None
+ }
+ },
+ None => None,
+ };
+}
+
+fn maybe_some() -> Option<u32> {
+ Some(0)
}
},
None => None,
};
+
+ match Some(20) {
+ // Don't Lint, because `Some(3*x)` is not `None`
+ None => None,
+ Some(x) => {
+ if x > 0 {
+ Some(3 * x)
+ } else {
+ Some(x)
+ }
+ },
+ };
+
+ // Don't lint: https://github.com/rust-lang/rust-clippy/issues/10088
+ let result = if let Some(a) = maybe_some() {
+ if let Some(b) = maybe_some() {
+ Some(a + b)
+ } else {
+ Some(a)
+ }
+ } else {
+ None
+ };
+
+ let allowed_integers = vec![3, 4, 5, 6];
+ // Don't lint, since there's a side effect in the else branch
+ match Some(21) {
+ Some(x) => {
+ if allowed_integers.contains(&x) {
+ Some(x)
+ } else {
+ println!("Invalid integer: {x:?}");
+ None
+ }
+ },
+ None => None,
+ };
+}
+
+fn maybe_some() -> Option<u32> {
+ Some(0)
}
// run-rustfix
#![warn(clippy::manual_retain)]
-#![allow(unused)]
+#![allow(unused, clippy::redundant_clone)]
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::BinaryHeap;
// run-rustfix
#![warn(clippy::manual_retain)]
-#![allow(unused)]
+#![allow(unused, clippy::redundant_clone)]
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::BinaryHeap;
println!("Needs curlies");
};
}
+
+#[allow(dead_code)]
+fn issue_9725(r: Option<u32>) {
+ let x = r;
+ match x {
+ Some(_) => {
+ println!("Some");
+ },
+ None => {
+ println!("None");
+ },
+ };
+}
_ => println!("Needs curlies"),
};
}
+
+#[allow(dead_code)]
+fn issue_9725(r: Option<u32>) {
+ match r {
+ x => match x {
+ Some(_) => {
+ println!("Some");
+ },
+ None => {
+ println!("None");
+ },
+ },
+ };
+}
LL ~ };
|
-error: aborting due to 14 previous errors
+error: this match could be written as a `let` statement
+ --> $DIR/match_single_binding.rs:154:5
+ |
+LL | / match r {
+LL | | x => match x {
+LL | | Some(_) => {
+LL | | println!("Some");
+... |
+LL | | },
+LL | | };
+ | |_____^
+ |
+help: consider using a `let` statement
+ |
+LL ~ let x = r;
+LL + match x {
+LL + Some(_) => {
+LL + println!("Some");
+LL + },
+LL + None => {
+LL + println!("None");
+LL + },
+LL ~ };
+ |
+
+error: aborting due to 15 previous errors
}
}
}
+
+mod issue9993 {
+ enum Foo {
+ A(bool),
+ B,
+ }
+
+ fn test() {
+ let _ = match Foo::A(true) {
+ _ if false => 0,
+ Foo::A(true) => 1,
+ Foo::A(false) => 2,
+ Foo::B => 3,
+ };
+
+ let _ = match Foo::B {
+ _ if false => 0,
+ Foo::A(_) => 1,
+ Foo::B => 2,
+ };
+ }
+}
}
}
}
+
+mod issue9993 {
+ enum Foo {
+ A(bool),
+ B,
+ }
+
+ fn test() {
+ let _ = match Foo::A(true) {
+ _ if false => 0,
+ Foo::A(true) => 1,
+ Foo::A(false) => 2,
+ Foo::B => 3,
+ };
+
+ let _ = match Foo::B {
+ _ if false => 0,
+ Foo::A(_) => 1,
+ _ => 2,
+ };
+ }
+}
LL | _ => (),
| ^ help: try this: `Color::Blue`
-error: aborting due to 8 previous errors
+error: wildcard matches only a single variant and will also match any future added variants
+ --> $DIR/match_wildcard_for_single_variants.rs:153:13
+ |
+LL | _ => 2,
+ | ^ help: try this: `Foo::B`
+
+error: aborting due to 9 previous errors
// run-rustfix
-#![feature(lint_reasons)]
+#![feature(custom_inner_attributes, lint_reasons, rustc_private)]
#![allow(
unused,
clippy::uninlined_format_args,
S.foo::<&[u8; 100]>(&a);
}
}
+
+extern crate rustc_lint;
+extern crate rustc_span;
+
+#[allow(dead_code)]
+mod span_lint {
+ use rustc_lint::{LateContext, Lint, LintContext};
+ fn foo(cx: &LateContext<'_>, lint: &'static Lint) {
+ cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(String::new()));
+ }
+}
// run-rustfix
-#![feature(lint_reasons)]
+#![feature(custom_inner_attributes, lint_reasons, rustc_private)]
#![allow(
unused,
clippy::uninlined_format_args,
S.foo::<&[u8; 100]>(&a);
}
}
+
+extern crate rustc_lint;
+extern crate rustc_span;
+
+#[allow(dead_code)]
+mod span_lint {
+ use rustc_lint::{LateContext, Lint, LintContext};
+ fn foo(cx: &LateContext<'_>, lint: &'static Lint) {
+ cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new()));
+ }
+}
LL | foo(&a);
| ^^ help: change this to: `a`
-error: aborting due to 36 previous errors
+error: the borrowed expression implements the required traits
+ --> $DIR/needless_borrow.rs:502:85
+ |
+LL | cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new()));
+ | ^^^^^^^^^^^^^^ help: change this to: `String::new()`
+
+error: aborting due to 37 previous errors
// run-rustfix
#![feature(lint_reasons)]
+#![feature(yeet_expr)]
#![allow(unused)]
#![allow(
clippy::if_same_then_else,
}
}
+fn issue9947() -> Result<(), String> {
+ do yeet "hello";
+}
+
fn main() {}
// run-rustfix
#![feature(lint_reasons)]
+#![feature(yeet_expr)]
#![allow(unused)]
#![allow(
clippy::if_same_then_else,
}
}
+fn issue9947() -> Result<(), String> {
+ do yeet "hello";
+}
+
fn main() {}
error: unneeded `return` statement
- --> $DIR/needless_return.rs:26:5
+ --> $DIR/needless_return.rs:27:5
|
LL | return true;
| ^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:30:5
+ --> $DIR/needless_return.rs:31:5
|
LL | return true;
| ^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:35:9
+ --> $DIR/needless_return.rs:36:9
|
LL | return true;
| ^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:37:9
+ --> $DIR/needless_return.rs:38:9
|
LL | return false;
| ^^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:43:17
+ --> $DIR/needless_return.rs:44:17
|
LL | true => return false,
| ^^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:45:13
+ --> $DIR/needless_return.rs:46:13
|
LL | return true;
| ^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:52:9
+ --> $DIR/needless_return.rs:53:9
|
LL | return true;
| ^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:54:16
+ --> $DIR/needless_return.rs:55:16
|
LL | let _ = || return true;
| ^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:58:5
+ --> $DIR/needless_return.rs:59:5
|
LL | return the_answer!();
| ^^^^^^^^^^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:61:21
+ --> $DIR/needless_return.rs:62:21
|
LL | fn test_void_fun() {
| _____________________^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:66:11
+ --> $DIR/needless_return.rs:67:11
|
LL | if b {
| ___________^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:68:13
+ --> $DIR/needless_return.rs:69:13
|
LL | } else {
| _____________^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:76:14
+ --> $DIR/needless_return.rs:77:14
|
LL | _ => return,
| ^^^^^^
= help: replace `return` with a unit value
error: unneeded `return` statement
- --> $DIR/needless_return.rs:84:24
+ --> $DIR/needless_return.rs:85:24
|
LL | let _ = 42;
| ________________________^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:87:14
+ --> $DIR/needless_return.rs:88:14
|
LL | _ => return,
| ^^^^^^
= help: replace `return` with a unit value
error: unneeded `return` statement
- --> $DIR/needless_return.rs:100:9
+ --> $DIR/needless_return.rs:101:9
|
LL | return String::from("test");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:102:9
+ --> $DIR/needless_return.rs:103:9
|
LL | return String::new();
| ^^^^^^^^^^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:124:32
+ --> $DIR/needless_return.rs:125:32
|
LL | bar.unwrap_or_else(|_| return)
| ^^^^^^
= help: replace `return` with an empty block
error: unneeded `return` statement
- --> $DIR/needless_return.rs:128:21
+ --> $DIR/needless_return.rs:129:21
|
LL | let _ = || {
| _____________________^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:131:20
+ --> $DIR/needless_return.rs:132:20
|
LL | let _ = || return;
| ^^^^^^
= help: replace `return` with an empty block
error: unneeded `return` statement
- --> $DIR/needless_return.rs:137:32
+ --> $DIR/needless_return.rs:138:32
|
LL | res.unwrap_or_else(|_| return Foo)
| ^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:146:5
+ --> $DIR/needless_return.rs:147:5
|
LL | return true;
| ^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:150:5
+ --> $DIR/needless_return.rs:151:5
|
LL | return true;
| ^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:155:9
+ --> $DIR/needless_return.rs:156:9
|
LL | return true;
| ^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:157:9
+ --> $DIR/needless_return.rs:158:9
|
LL | return false;
| ^^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:163:17
+ --> $DIR/needless_return.rs:164:17
|
LL | true => return false,
| ^^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:165:13
+ --> $DIR/needless_return.rs:166:13
|
LL | return true;
| ^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:172:9
+ --> $DIR/needless_return.rs:173:9
|
LL | return true;
| ^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:174:16
+ --> $DIR/needless_return.rs:175:16
|
LL | let _ = || return true;
| ^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:178:5
+ --> $DIR/needless_return.rs:179:5
|
LL | return the_answer!();
| ^^^^^^^^^^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:181:33
+ --> $DIR/needless_return.rs:182:33
|
LL | async fn async_test_void_fun() {
| _________________________________^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:186:11
+ --> $DIR/needless_return.rs:187:11
|
LL | if b {
| ___________^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:188:13
+ --> $DIR/needless_return.rs:189:13
|
LL | } else {
| _____________^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:196:14
+ --> $DIR/needless_return.rs:197:14
|
LL | _ => return,
| ^^^^^^
= help: replace `return` with a unit value
error: unneeded `return` statement
- --> $DIR/needless_return.rs:209:9
+ --> $DIR/needless_return.rs:210:9
|
LL | return String::from("test");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:211:9
+ --> $DIR/needless_return.rs:212:9
|
LL | return String::new();
| ^^^^^^^^^^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:227:5
+ --> $DIR/needless_return.rs:228:5
|
LL | return format!("Hello {}", "world!");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:238:9
+ --> $DIR/needless_return.rs:239:9
|
LL | return true;
| ^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:240:9
+ --> $DIR/needless_return.rs:241:9
|
LL | return false;
| ^^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:247:13
+ --> $DIR/needless_return.rs:248:13
|
LL | return 10;
| ^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:250:13
+ --> $DIR/needless_return.rs:251:13
|
LL | return 100;
| ^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:258:9
+ --> $DIR/needless_return.rs:259:9
|
LL | return 0;
| ^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:265:13
+ --> $DIR/needless_return.rs:266:13
|
LL | return *(x as *const isize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:267:13
+ --> $DIR/needless_return.rs:268:13
|
LL | return !*(x as *const isize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:274:20
+ --> $DIR/needless_return.rs:275:20
|
LL | let _ = 42;
| ____________________^
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:281:20
+ --> $DIR/needless_return.rs:282:20
|
LL | let _ = 42; return;
| ^^^^^^^
--- /dev/null
+#![allow(unused)]
+#![warn(clippy::permissions_set_readonly_false)]
+
+use std::fs::File;
+
+struct A;
+
+impl A {
+ pub fn set_readonly(&mut self, b: bool) {}
+}
+
+fn set_readonly(b: bool) {}
+
+fn main() {
+ let f = File::create("foo.txt").unwrap();
+ let metadata = f.metadata().unwrap();
+ let mut permissions = metadata.permissions();
+ // lint here
+ permissions.set_readonly(false);
+ // no lint
+ permissions.set_readonly(true);
+
+ let mut a = A;
+ // no lint here - a is not of type std::fs::Permissions
+ a.set_readonly(false);
+
+ // no lint here - plain function
+ set_readonly(false);
+}
--- /dev/null
+error: call to `set_readonly` with argument `false`
+ --> $DIR/permissions_set_readonly_false.rs:19:5
+ |
+LL | permissions.set_readonly(false);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: on Unix platforms this results in the file being world writable
+ = help: you can set the desired permissions using `PermissionsExt`. For more information, see
+ https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html
+ = note: `-D clippy::permissions-set-readonly-false` implied by `-D warnings`
+
+error: aborting due to previous error
+
let _z = x.clone(); // pr 7346 can't lint on `x`
drop(y);
}
+
+#[allow(unused, clippy::manual_retain)]
+fn possible_borrower_improvements() {
+ let mut s = String::from("foobar");
+ s = s.chars().filter(|&c| c != 'o').collect();
+}
let _z = x.clone(); // pr 7346 can't lint on `x`
drop(y);
}
+
+#[allow(unused, clippy::manual_retain)]
+fn possible_borrower_improvements() {
+ let mut s = String::from("foobar");
+ s = s.chars().filter(|&c| c != 'o').to_owned().collect();
+}
LL | foo(&x.clone(), move || {
| ^
-error: aborting due to 15 previous errors
+error: redundant clone
+ --> $DIR/redundant_clone.rs:246:40
+ |
+LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect();
+ | ^^^^^^^^^^^ help: remove this
+ |
+note: this value is dropped without further use
+ --> $DIR/redundant_clone.rs:246:9
+ |
+LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 16 previous errors
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_unfixable.rs:29:5
|
-LL | x.field.map(|value| {
- | ______^
- | | _____|
- | ||
+LL | // x.field.map(|value| {
LL | || do_nothing(value);
LL | || do_nothing(value)
LL | || });
--- /dev/null
+#![allow(unused)]
+#![warn(clippy::size_of_ref)]
+
+use std::mem::size_of_val;
+
+fn main() {
+ let x = 5;
+ let y = &x;
+
+ size_of_val(&x); // no lint
+ size_of_val(y); // no lint
+
+ size_of_val(&&x);
+ size_of_val(&y);
+}
+
+struct S {
+ field: u32,
+ data: Vec<u8>,
+}
+
+impl S {
+ /// Get size of object including `self`, in bytes.
+ pub fn size(&self) -> usize {
+ std::mem::size_of_val(&self) + (std::mem::size_of::<u8>() * self.data.capacity())
+ }
+}
--- /dev/null
+error: argument to `std::mem::size_of_val()` is a reference to a reference
+ --> $DIR/size_of_ref.rs:13:5
+ |
+LL | size_of_val(&&x);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type
+ = note: `-D clippy::size-of-ref` implied by `-D warnings`
+
+error: argument to `std::mem::size_of_val()` is a reference to a reference
+ --> $DIR/size_of_ref.rs:14:5
+ |
+LL | size_of_val(&y);
+ | ^^^^^^^^^^^^^^^
+ |
+ = help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type
+
+error: argument to `std::mem::size_of_val()` is a reference to a reference
+ --> $DIR/size_of_ref.rs:25:9
+ |
+LL | std::mem::size_of_val(&self) + (std::mem::size_of::<u8>() * self.data.capacity())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+#![allow(dead_code)]
+#![warn(clippy::transmute_null_to_fn)]
+#![allow(clippy::zero_ptr)]
+
+// Easy to lint because these only span one line.
+fn one_liners() {
+ unsafe {
+ let _: fn() = std::mem::transmute(0 as *const ());
+ let _: fn() = std::mem::transmute(std::ptr::null::<()>());
+ }
+}
+
+pub const ZPTR: *const usize = 0 as *const _;
+pub const NOT_ZPTR: *const usize = 1 as *const _;
+
+fn transmute_const() {
+ unsafe {
+ // Should raise a lint.
+ let _: fn() = std::mem::transmute(ZPTR);
+ // Should NOT raise a lint.
+ let _: fn() = std::mem::transmute(NOT_ZPTR);
+ }
+}
+
+fn main() {
+ one_liners();
+ transmute_const();
+}
--- /dev/null
+error: transmuting a known null pointer into a function pointer
+ --> $DIR/transmute_null_to_fn.rs:8:23
+ |
+LL | let _: fn() = std::mem::transmute(0 as *const ());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
+ |
+ = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
+ = note: `-D clippy::transmute-null-to-fn` implied by `-D warnings`
+
+error: transmuting a known null pointer into a function pointer
+ --> $DIR/transmute_null_to_fn.rs:9:23
+ |
+LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
+ |
+ = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
+
+error: transmuting a known null pointer into a function pointer
+ --> $DIR/transmute_null_to_fn.rs:19:23
+ |
+LL | let _: fn() = std::mem::transmute(ZPTR);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
+ |
+ = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
+
+error: aborting due to 3 previous errors
+
Ok(())
}
-fn test_issue_5833() -> Result<(), ()> {
+fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() {
let text = "foo\r\nbar\n\nbaz\n";
let lines = text.lines();
if Some("ok") == lines.into_iter().next() {}
+}
- Ok(())
+fn lint_into_iter_on_mutable_local_implementing_iterator_in_expr() {
+ let text = "foo\r\nbar\n\nbaz\n";
+ let mut lines = text.lines();
+ if Some("ok") == lines.next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator() {
+ let text = "foo\r\nbar\n\nbaz\n";
+ let mut lines = text.lines();
+ if Some("ok") == lines.next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator_2() {
+ let text = "foo\r\nbar\n\nbaz\n";
+ if Some("ok") == text.lines().next() {}
+}
+
+#[allow(const_item_mutation)]
+fn lint_into_iter_on_const_implementing_iterator() {
+ const NUMBERS: std::ops::Range<i32> = 0..10;
+ let _ = NUMBERS.next();
+}
+
+fn lint_into_iter_on_const_implementing_iterator_2() {
+ const NUMBERS: std::ops::Range<i32> = 0..10;
+ let mut n = NUMBERS;
+ n.next();
+}
+
+#[derive(Clone, Copy)]
+struct CopiableCounter {
+ counter: u32,
+}
+
+impl Iterator for CopiableCounter {
+ type Item = u32;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.counter = self.counter.wrapping_add(1);
+ Some(self.counter)
+ }
+}
+
+fn dont_lint_into_iter_on_copy_iter() {
+ let mut c = CopiableCounter { counter: 0 };
+ assert_eq!(c.into_iter().next(), Some(1));
+ assert_eq!(c.into_iter().next(), Some(1));
+ assert_eq!(c.next(), Some(1));
+ assert_eq!(c.next(), Some(2));
+}
+
+fn dont_lint_into_iter_on_static_copy_iter() {
+ static mut C: CopiableCounter = CopiableCounter { counter: 0 };
+ unsafe {
+ assert_eq!(C.into_iter().next(), Some(1));
+ assert_eq!(C.into_iter().next(), Some(1));
+ assert_eq!(C.next(), Some(1));
+ assert_eq!(C.next(), Some(2));
+ }
}
fn main() {
test_generic2::<i32, i32>(10i32);
test_questionmark().unwrap();
test_issue_3913().unwrap();
- test_issue_5833().unwrap();
+
+ dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr();
+ lint_into_iter_on_mutable_local_implementing_iterator_in_expr();
+ lint_into_iter_on_expr_implementing_iterator();
+ lint_into_iter_on_expr_implementing_iterator_2();
+ lint_into_iter_on_const_implementing_iterator();
+ lint_into_iter_on_const_implementing_iterator_2();
+ dont_lint_into_iter_on_copy_iter();
+ dont_lint_into_iter_on_static_copy_iter();
let _: String = "foo".into();
let _: String = From::from("foo");
Ok(())
}
-fn test_issue_5833() -> Result<(), ()> {
+fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() {
let text = "foo\r\nbar\n\nbaz\n";
let lines = text.lines();
if Some("ok") == lines.into_iter().next() {}
+}
- Ok(())
+fn lint_into_iter_on_mutable_local_implementing_iterator_in_expr() {
+ let text = "foo\r\nbar\n\nbaz\n";
+ let mut lines = text.lines();
+ if Some("ok") == lines.into_iter().next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator() {
+ let text = "foo\r\nbar\n\nbaz\n";
+ let mut lines = text.lines().into_iter();
+ if Some("ok") == lines.next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator_2() {
+ let text = "foo\r\nbar\n\nbaz\n";
+ if Some("ok") == text.lines().into_iter().next() {}
+}
+
+#[allow(const_item_mutation)]
+fn lint_into_iter_on_const_implementing_iterator() {
+ const NUMBERS: std::ops::Range<i32> = 0..10;
+ let _ = NUMBERS.into_iter().next();
+}
+
+fn lint_into_iter_on_const_implementing_iterator_2() {
+ const NUMBERS: std::ops::Range<i32> = 0..10;
+ let mut n = NUMBERS.into_iter();
+ n.next();
+}
+
+#[derive(Clone, Copy)]
+struct CopiableCounter {
+ counter: u32,
+}
+
+impl Iterator for CopiableCounter {
+ type Item = u32;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.counter = self.counter.wrapping_add(1);
+ Some(self.counter)
+ }
+}
+
+fn dont_lint_into_iter_on_copy_iter() {
+ let mut c = CopiableCounter { counter: 0 };
+ assert_eq!(c.into_iter().next(), Some(1));
+ assert_eq!(c.into_iter().next(), Some(1));
+ assert_eq!(c.next(), Some(1));
+ assert_eq!(c.next(), Some(2));
+}
+
+fn dont_lint_into_iter_on_static_copy_iter() {
+ static mut C: CopiableCounter = CopiableCounter { counter: 0 };
+ unsafe {
+ assert_eq!(C.into_iter().next(), Some(1));
+ assert_eq!(C.into_iter().next(), Some(1));
+ assert_eq!(C.next(), Some(1));
+ assert_eq!(C.next(), Some(2));
+ }
}
fn main() {
test_generic2::<i32, i32>(10i32);
test_questionmark().unwrap();
test_issue_3913().unwrap();
- test_issue_5833().unwrap();
+
+ dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr();
+ lint_into_iter_on_mutable_local_implementing_iterator_in_expr();
+ lint_into_iter_on_expr_implementing_iterator();
+ lint_into_iter_on_expr_implementing_iterator_2();
+ lint_into_iter_on_const_implementing_iterator();
+ lint_into_iter_on_const_implementing_iterator_2();
+ dont_lint_into_iter_on_copy_iter();
+ dont_lint_into_iter_on_static_copy_iter();
let _: String = "foo".into();
let _: String = From::from("foo");
LL | let _: i32 = 0i32.into();
| ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
+error: useless conversion to the same type: `std::str::Lines<'_>`
+ --> $DIR/useless_conversion.rs:45:22
+ |
+LL | if Some("ok") == lines.into_iter().next() {}
+ | ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines`
+
+error: useless conversion to the same type: `std::str::Lines<'_>`
+ --> $DIR/useless_conversion.rs:50:21
+ |
+LL | let mut lines = text.lines().into_iter();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()`
+
+error: useless conversion to the same type: `std::str::Lines<'_>`
+ --> $DIR/useless_conversion.rs:56:22
+ |
+LL | if Some("ok") == text.lines().into_iter().next() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()`
+
+error: useless conversion to the same type: `std::ops::Range<i32>`
+ --> $DIR/useless_conversion.rs:62:13
+ |
+LL | let _ = NUMBERS.into_iter().next();
+ | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS`
+
+error: useless conversion to the same type: `std::ops::Range<i32>`
+ --> $DIR/useless_conversion.rs:67:17
+ |
+LL | let mut n = NUMBERS.into_iter();
+ | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS`
+
error: useless conversion to the same type: `std::string::String`
- --> $DIR/useless_conversion.rs:61:21
+ --> $DIR/useless_conversion.rs:128:21
|
LL | let _: String = "foo".to_string().into();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
error: useless conversion to the same type: `std::string::String`
- --> $DIR/useless_conversion.rs:62:21
+ --> $DIR/useless_conversion.rs:129:21
|
LL | let _: String = From::from("foo".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
error: useless conversion to the same type: `std::string::String`
- --> $DIR/useless_conversion.rs:63:13
+ --> $DIR/useless_conversion.rs:130:13
|
LL | let _ = String::from("foo".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
error: useless conversion to the same type: `std::string::String`
- --> $DIR/useless_conversion.rs:64:13
+ --> $DIR/useless_conversion.rs:131:13
|
LL | let _ = String::from(format!("A: {:04}", 123));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
error: useless conversion to the same type: `std::str::Lines<'_>`
- --> $DIR/useless_conversion.rs:65:13
+ --> $DIR/useless_conversion.rs:132:13
|
LL | let _ = "".lines().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
error: useless conversion to the same type: `std::vec::IntoIter<i32>`
- --> $DIR/useless_conversion.rs:66:13
+ --> $DIR/useless_conversion.rs:133:13
|
LL | let _ = vec![1, 2, 3].into_iter().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
error: useless conversion to the same type: `std::string::String`
- --> $DIR/useless_conversion.rs:67:21
+ --> $DIR/useless_conversion.rs:134:21
|
LL | let _: String = format!("Hello {}", "world").into();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`
error: useless conversion to the same type: `i32`
- --> $DIR/useless_conversion.rs:72:13
+ --> $DIR/useless_conversion.rs:139:13
|
LL | let _ = i32::from(a + b) * 3;
| ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)`
error: useless conversion to the same type: `Foo<'a'>`
- --> $DIR/useless_conversion.rs:78:23
+ --> $DIR/useless_conversion.rs:145:23
|
LL | let _: Foo<'a'> = s2.into();
| ^^^^^^^^^ help: consider removing `.into()`: `s2`
error: useless conversion to the same type: `Foo<'a'>`
- --> $DIR/useless_conversion.rs:80:13
+ --> $DIR/useless_conversion.rs:147:13
|
LL | let _ = Foo::<'a'>::from(s3);
| ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3`
error: useless conversion to the same type: `std::vec::IntoIter<Foo<'a'>>`
- --> $DIR/useless_conversion.rs:82:13
+ --> $DIR/useless_conversion.rs:149:13
|
LL | let _ = vec![s4, s4, s4].into_iter().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()`
-error: aborting due to 14 previous errors
+error: aborting due to 19 previous errors
// the 2015 edition here is needed because edition 2018 changed the module system
// (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
// no longer detects some of the cases starting with Rust 2018.
-// FIXME: We should likely add another edition 2021 test case for this lint
#![warn(clippy::wildcard_imports)]
#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
// the 2015 edition here is needed because edition 2018 changed the module system
// (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
// no longer detects some of the cases starting with Rust 2018.
-// FIXME: We should likely add another edition 2021 test case for this lint
#![warn(clippy::wildcard_imports)]
#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:16:5
+ --> $DIR/wildcard_imports.rs:15:5
|
LL | use crate::fn_mod::*;
| ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
= note: `-D clippy::wildcard-imports` implied by `-D warnings`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:17:5
+ --> $DIR/wildcard_imports.rs:16:5
|
LL | use crate::mod_mod::*;
| ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:18:5
+ --> $DIR/wildcard_imports.rs:17:5
|
LL | use crate::multi_fn_mod::*;
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:20:5
+ --> $DIR/wildcard_imports.rs:19:5
|
LL | use crate::struct_mod::*;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:24:5
+ --> $DIR/wildcard_imports.rs:23:5
|
LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:25:5
+ --> $DIR/wildcard_imports.rs:24:5
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:96:13
+ --> $DIR/wildcard_imports.rs:95:13
|
LL | use crate::fn_mod::*;
| ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:102:75
+ --> $DIR/wildcard_imports.rs:101:75
|
LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
| ^ help: try: `inner_extern_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:103:13
+ --> $DIR/wildcard_imports.rs:102:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:114:20
+ --> $DIR/wildcard_imports.rs:113:20
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^ help: try: `inner::inner_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:114:30
+ --> $DIR/wildcard_imports.rs:113:30
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^^ help: try: `inner2::inner_bar`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:121:13
+ --> $DIR/wildcard_imports.rs:120:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:150:9
+ --> $DIR/wildcard_imports.rs:149:9
|
LL | use crate::in_fn_test::*;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:159:9
+ --> $DIR/wildcard_imports.rs:158:9
|
LL | use crate:: in_fn_test:: * ;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:160:9
+ --> $DIR/wildcard_imports.rs:159:9
|
LL | use crate:: fn_mod::
| _________^
| |_________^ help: try: `crate:: fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:171:13
+ --> $DIR/wildcard_imports.rs:170:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:206:17
+ --> $DIR/wildcard_imports.rs:205:17
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::insidefoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:214:13
+ --> $DIR/wildcard_imports.rs:213:13
|
LL | use super_imports::*;
| ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:223:17
+ --> $DIR/wildcard_imports.rs:222:17
|
LL | use super::super::*;
| ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:232:13
+ --> $DIR/wildcard_imports.rs:231:13
|
LL | use super::super::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:240:13
+ --> $DIR/wildcard_imports.rs:239:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
--- /dev/null
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+// aux-build:wildcard_imports_helper.rs
+
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+#![warn(unused_imports)]
+
+extern crate wildcard_imports_helper;
+
+use crate::fn_mod::foo;
+use crate::mod_mod::inner_mod;
+use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod};
+use crate::struct_mod::{A, inner_struct_mod};
+
+#[allow(unused_imports)]
+use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
+use wildcard_imports_helper::prelude::v1::*;
+use wildcard_imports_helper::{ExternA, extern_foo};
+
+use std::io::prelude::*;
+
+struct ReadFoo;
+
+impl Read for ReadFoo {
+ fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
+ Ok(0)
+ }
+}
+
+mod fn_mod {
+ pub fn foo() {}
+}
+
+mod mod_mod {
+ pub mod inner_mod {
+ pub fn foo() {}
+ }
+}
+
+mod multi_fn_mod {
+ pub fn multi_foo() {}
+ pub fn multi_bar() {}
+ pub fn multi_baz() {}
+ pub mod multi_inner_mod {
+ pub fn foo() {}
+ }
+}
+
+mod struct_mod {
+ pub struct A;
+ pub struct B;
+ pub mod inner_struct_mod {
+ pub struct C;
+ }
+
+ #[macro_export]
+ macro_rules! double_struct_import_test {
+ () => {
+ let _ = A;
+ };
+ }
+}
+
+fn main() {
+ foo();
+ multi_foo();
+ multi_bar();
+ multi_inner_mod::foo();
+ inner_mod::foo();
+ extern_foo();
+ inner_extern_bar();
+
+ let _ = A;
+ let _ = inner_struct_mod::C;
+ let _ = ExternA;
+ let _ = PreludeModAnywhere;
+
+ double_struct_import_test!();
+ double_struct_import_test!();
+}
+
+mod in_fn_test {
+ pub use self::inner_exported::*;
+ #[allow(unused_imports)]
+ pub(crate) use self::inner_exported2::*;
+
+ fn test_intern() {
+ use crate::fn_mod::foo;
+
+ foo();
+ }
+
+ fn test_extern() {
+ use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo};
+ use wildcard_imports_helper::{ExternA, extern_foo};
+
+ inner_for_self_import::inner_extern_foo();
+ inner_extern_foo();
+
+ extern_foo();
+
+ let _ = ExternA;
+ }
+
+ fn test_inner_nested() {
+ use self::{inner::inner_foo, inner2::inner_bar};
+
+ inner_foo();
+ inner_bar();
+ }
+
+ fn test_extern_reexported() {
+ use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported};
+
+ extern_exported();
+ let _ = ExternExportedStruct;
+ let _ = ExternExportedEnum::A;
+ }
+
+ mod inner_exported {
+ pub fn exported() {}
+ pub struct ExportedStruct;
+ pub enum ExportedEnum {
+ A,
+ }
+ }
+
+ mod inner_exported2 {
+ pub(crate) fn exported2() {}
+ }
+
+ mod inner {
+ pub fn inner_foo() {}
+ }
+
+ mod inner2 {
+ pub fn inner_bar() {}
+ }
+}
+
+fn test_reexported() {
+ use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported};
+
+ exported();
+ let _ = ExportedStruct;
+ let _ = ExportedEnum::A;
+}
+
+#[rustfmt::skip]
+fn test_weird_formatting() {
+ use crate:: in_fn_test::exported;
+ use crate:: fn_mod::foo;
+
+ exported();
+ foo();
+}
+
+mod super_imports {
+ fn foofoo() {}
+
+ mod should_be_replaced {
+ use super::foofoo;
+
+ fn with_super() {
+ let _ = foofoo();
+ }
+ }
+
+ mod test_should_pass {
+ use super::*;
+
+ fn with_super() {
+ let _ = foofoo();
+ }
+ }
+
+ mod test_should_pass_inside_function {
+ fn with_super_inside_function() {
+ use super::*;
+ let _ = foofoo();
+ }
+ }
+
+ mod test_should_pass_further_inside {
+ fn insidefoo() {}
+ mod inner {
+ use super::*;
+ fn with_super() {
+ let _ = insidefoo();
+ }
+ }
+ }
+
+ mod should_be_replaced_further_inside {
+ fn insidefoo() {}
+ mod inner {
+ use super::insidefoo;
+ fn with_super() {
+ let _ = insidefoo();
+ }
+ }
+ }
+
+ mod use_explicit_should_be_replaced {
+ use crate::super_imports::foofoo;
+
+ fn with_explicit() {
+ let _ = foofoo();
+ }
+ }
+
+ mod use_double_super_should_be_replaced {
+ mod inner {
+ use super::super::foofoo;
+
+ fn with_double_super() {
+ let _ = foofoo();
+ }
+ }
+ }
+
+ mod use_super_explicit_should_be_replaced {
+ use super::super::super_imports::foofoo;
+
+ fn with_super_explicit() {
+ let _ = foofoo();
+ }
+ }
+
+ mod attestation_should_be_replaced {
+ use super::foofoo;
+
+ fn with_explicit() {
+ let _ = foofoo();
+ }
+ }
+}
--- /dev/null
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:13:5
+ |
+LL | use crate::fn_mod::*;
+ | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+ |
+ = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:14:5
+ |
+LL | use crate::mod_mod::*;
+ | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:15:5
+ |
+LL | use crate::multi_fn_mod::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:16:5
+ |
+LL | use crate::struct_mod::*;
+ | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:19:5
+ |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:21:5
+ |
+LL | use wildcard_imports_helper::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:91:13
+ |
+LL | use crate::fn_mod::*;
+ | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:97:75
+ |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+ | ^ help: try: `inner_extern_foo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:98:13
+ |
+LL | use wildcard_imports_helper::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:109:20
+ |
+LL | use self::{inner::*, inner2::*};
+ | ^^^^^^^^ help: try: `inner::inner_foo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:109:30
+ |
+LL | use self::{inner::*, inner2::*};
+ | ^^^^^^^^^ help: try: `inner2::inner_bar`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:116:13
+ |
+LL | use wildcard_imports_helper::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:145:9
+ |
+LL | use crate::in_fn_test::*;
+ | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:154:9
+ |
+LL | use crate:: in_fn_test:: * ;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:155:9
+ |
+LL | use crate:: fn_mod::
+ | _________^
+LL | | *;
+ | |_________^ help: try: `crate:: fn_mod::foo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:166:13
+ |
+LL | use super::*;
+ | ^^^^^^^^ help: try: `super::foofoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:201:17
+ |
+LL | use super::*;
+ | ^^^^^^^^ help: try: `super::insidefoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:209:13
+ |
+LL | use crate::super_imports::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:218:17
+ |
+LL | use super::super::*;
+ | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:227:13
+ |
+LL | use super::super::super_imports::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:235:13
+ |
+LL | use super::*;
+ | ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
+
--- /dev/null
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+// aux-build:wildcard_imports_helper.rs
+
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+#![warn(unused_imports)]
+
+extern crate wildcard_imports_helper;
+
+use crate::fn_mod::foo;
+use crate::mod_mod::inner_mod;
+use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod};
+use crate::struct_mod::{A, inner_struct_mod};
+
+#[allow(unused_imports)]
+use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
+use wildcard_imports_helper::prelude::v1::*;
+use wildcard_imports_helper::{ExternA, extern_foo};
+
+use std::io::prelude::*;
+
+struct ReadFoo;
+
+impl Read for ReadFoo {
+ fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
+ Ok(0)
+ }
+}
+
+mod fn_mod {
+ pub fn foo() {}
+}
+
+mod mod_mod {
+ pub mod inner_mod {
+ pub fn foo() {}
+ }
+}
+
+mod multi_fn_mod {
+ pub fn multi_foo() {}
+ pub fn multi_bar() {}
+ pub fn multi_baz() {}
+ pub mod multi_inner_mod {
+ pub fn foo() {}
+ }
+}
+
+mod struct_mod {
+ pub struct A;
+ pub struct B;
+ pub mod inner_struct_mod {
+ pub struct C;
+ }
+
+ #[macro_export]
+ macro_rules! double_struct_import_test {
+ () => {
+ let _ = A;
+ };
+ }
+}
+
+fn main() {
+ foo();
+ multi_foo();
+ multi_bar();
+ multi_inner_mod::foo();
+ inner_mod::foo();
+ extern_foo();
+ inner_extern_bar();
+
+ let _ = A;
+ let _ = inner_struct_mod::C;
+ let _ = ExternA;
+ let _ = PreludeModAnywhere;
+
+ double_struct_import_test!();
+ double_struct_import_test!();
+}
+
+mod in_fn_test {
+ pub use self::inner_exported::*;
+ #[allow(unused_imports)]
+ pub(crate) use self::inner_exported2::*;
+
+ fn test_intern() {
+ use crate::fn_mod::foo;
+
+ foo();
+ }
+
+ fn test_extern() {
+ use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo};
+ use wildcard_imports_helper::{ExternA, extern_foo};
+
+ inner_for_self_import::inner_extern_foo();
+ inner_extern_foo();
+
+ extern_foo();
+
+ let _ = ExternA;
+ }
+
+ fn test_inner_nested() {
+ use self::{inner::inner_foo, inner2::inner_bar};
+
+ inner_foo();
+ inner_bar();
+ }
+
+ fn test_extern_reexported() {
+ use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported};
+
+ extern_exported();
+ let _ = ExternExportedStruct;
+ let _ = ExternExportedEnum::A;
+ }
+
+ mod inner_exported {
+ pub fn exported() {}
+ pub struct ExportedStruct;
+ pub enum ExportedEnum {
+ A,
+ }
+ }
+
+ mod inner_exported2 {
+ pub(crate) fn exported2() {}
+ }
+
+ mod inner {
+ pub fn inner_foo() {}
+ }
+
+ mod inner2 {
+ pub fn inner_bar() {}
+ }
+}
+
+fn test_reexported() {
+ use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported};
+
+ exported();
+ let _ = ExportedStruct;
+ let _ = ExportedEnum::A;
+}
+
+#[rustfmt::skip]
+fn test_weird_formatting() {
+ use crate:: in_fn_test::exported;
+ use crate:: fn_mod::foo;
+
+ exported();
+ foo();
+}
+
+mod super_imports {
+ fn foofoo() {}
+
+ mod should_be_replaced {
+ use super::foofoo;
+
+ fn with_super() {
+ let _ = foofoo();
+ }
+ }
+
+ mod test_should_pass {
+ use super::*;
+
+ fn with_super() {
+ let _ = foofoo();
+ }
+ }
+
+ mod test_should_pass_inside_function {
+ fn with_super_inside_function() {
+ use super::*;
+ let _ = foofoo();
+ }
+ }
+
+ mod test_should_pass_further_inside {
+ fn insidefoo() {}
+ mod inner {
+ use super::*;
+ fn with_super() {
+ let _ = insidefoo();
+ }
+ }
+ }
+
+ mod should_be_replaced_further_inside {
+ fn insidefoo() {}
+ mod inner {
+ use super::insidefoo;
+ fn with_super() {
+ let _ = insidefoo();
+ }
+ }
+ }
+
+ mod use_explicit_should_be_replaced {
+ use crate::super_imports::foofoo;
+
+ fn with_explicit() {
+ let _ = foofoo();
+ }
+ }
+
+ mod use_double_super_should_be_replaced {
+ mod inner {
+ use super::super::foofoo;
+
+ fn with_double_super() {
+ let _ = foofoo();
+ }
+ }
+ }
+
+ mod use_super_explicit_should_be_replaced {
+ use super::super::super_imports::foofoo;
+
+ fn with_super_explicit() {
+ let _ = foofoo();
+ }
+ }
+
+ mod attestation_should_be_replaced {
+ use super::foofoo;
+
+ fn with_explicit() {
+ let _ = foofoo();
+ }
+ }
+}
--- /dev/null
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:13:5
+ |
+LL | use crate::fn_mod::*;
+ | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+ |
+ = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:14:5
+ |
+LL | use crate::mod_mod::*;
+ | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:15:5
+ |
+LL | use crate::multi_fn_mod::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:16:5
+ |
+LL | use crate::struct_mod::*;
+ | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:19:5
+ |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:21:5
+ |
+LL | use wildcard_imports_helper::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:91:13
+ |
+LL | use crate::fn_mod::*;
+ | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:97:75
+ |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+ | ^ help: try: `inner_extern_foo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:98:13
+ |
+LL | use wildcard_imports_helper::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:109:20
+ |
+LL | use self::{inner::*, inner2::*};
+ | ^^^^^^^^ help: try: `inner::inner_foo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:109:30
+ |
+LL | use self::{inner::*, inner2::*};
+ | ^^^^^^^^^ help: try: `inner2::inner_bar`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:116:13
+ |
+LL | use wildcard_imports_helper::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:145:9
+ |
+LL | use crate::in_fn_test::*;
+ | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:154:9
+ |
+LL | use crate:: in_fn_test:: * ;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:155:9
+ |
+LL | use crate:: fn_mod::
+ | _________^
+LL | | *;
+ | |_________^ help: try: `crate:: fn_mod::foo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:166:13
+ |
+LL | use super::*;
+ | ^^^^^^^^ help: try: `super::foofoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:201:17
+ |
+LL | use super::*;
+ | ^^^^^^^^ help: try: `super::insidefoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:209:13
+ |
+LL | use crate::super_imports::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:218:17
+ |
+LL | use super::super::*;
+ | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:227:13
+ |
+LL | use super::super::super_imports::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:235:13
+ |
+LL | use super::*;
+ | ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
+
--- /dev/null
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+// aux-build:wildcard_imports_helper.rs
+
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+#![warn(unused_imports)]
+
+extern crate wildcard_imports_helper;
+
+use crate::fn_mod::*;
+use crate::mod_mod::*;
+use crate::multi_fn_mod::*;
+use crate::struct_mod::*;
+
+#[allow(unused_imports)]
+use wildcard_imports_helper::inner::inner_for_self_import::*;
+use wildcard_imports_helper::prelude::v1::*;
+use wildcard_imports_helper::*;
+
+use std::io::prelude::*;
+
+struct ReadFoo;
+
+impl Read for ReadFoo {
+ fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
+ Ok(0)
+ }
+}
+
+mod fn_mod {
+ pub fn foo() {}
+}
+
+mod mod_mod {
+ pub mod inner_mod {
+ pub fn foo() {}
+ }
+}
+
+mod multi_fn_mod {
+ pub fn multi_foo() {}
+ pub fn multi_bar() {}
+ pub fn multi_baz() {}
+ pub mod multi_inner_mod {
+ pub fn foo() {}
+ }
+}
+
+mod struct_mod {
+ pub struct A;
+ pub struct B;
+ pub mod inner_struct_mod {
+ pub struct C;
+ }
+
+ #[macro_export]
+ macro_rules! double_struct_import_test {
+ () => {
+ let _ = A;
+ };
+ }
+}
+
+fn main() {
+ foo();
+ multi_foo();
+ multi_bar();
+ multi_inner_mod::foo();
+ inner_mod::foo();
+ extern_foo();
+ inner_extern_bar();
+
+ let _ = A;
+ let _ = inner_struct_mod::C;
+ let _ = ExternA;
+ let _ = PreludeModAnywhere;
+
+ double_struct_import_test!();
+ double_struct_import_test!();
+}
+
+mod in_fn_test {
+ pub use self::inner_exported::*;
+ #[allow(unused_imports)]
+ pub(crate) use self::inner_exported2::*;
+
+ fn test_intern() {
+ use crate::fn_mod::*;
+
+ foo();
+ }
+
+ fn test_extern() {
+ use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+ use wildcard_imports_helper::*;
+
+ inner_for_self_import::inner_extern_foo();
+ inner_extern_foo();
+
+ extern_foo();
+
+ let _ = ExternA;
+ }
+
+ fn test_inner_nested() {
+ use self::{inner::*, inner2::*};
+
+ inner_foo();
+ inner_bar();
+ }
+
+ fn test_extern_reexported() {
+ use wildcard_imports_helper::*;
+
+ extern_exported();
+ let _ = ExternExportedStruct;
+ let _ = ExternExportedEnum::A;
+ }
+
+ mod inner_exported {
+ pub fn exported() {}
+ pub struct ExportedStruct;
+ pub enum ExportedEnum {
+ A,
+ }
+ }
+
+ mod inner_exported2 {
+ pub(crate) fn exported2() {}
+ }
+
+ mod inner {
+ pub fn inner_foo() {}
+ }
+
+ mod inner2 {
+ pub fn inner_bar() {}
+ }
+}
+
+fn test_reexported() {
+ use crate::in_fn_test::*;
+
+ exported();
+ let _ = ExportedStruct;
+ let _ = ExportedEnum::A;
+}
+
+#[rustfmt::skip]
+fn test_weird_formatting() {
+ use crate:: in_fn_test:: * ;
+ use crate:: fn_mod::
+ *;
+
+ exported();
+ foo();
+}
+
+mod super_imports {
+ fn foofoo() {}
+
+ mod should_be_replaced {
+ use super::*;
+
+ fn with_super() {
+ let _ = foofoo();
+ }
+ }
+
+ mod test_should_pass {
+ use super::*;
+
+ fn with_super() {
+ let _ = foofoo();
+ }
+ }
+
+ mod test_should_pass_inside_function {
+ fn with_super_inside_function() {
+ use super::*;
+ let _ = foofoo();
+ }
+ }
+
+ mod test_should_pass_further_inside {
+ fn insidefoo() {}
+ mod inner {
+ use super::*;
+ fn with_super() {
+ let _ = insidefoo();
+ }
+ }
+ }
+
+ mod should_be_replaced_further_inside {
+ fn insidefoo() {}
+ mod inner {
+ use super::*;
+ fn with_super() {
+ let _ = insidefoo();
+ }
+ }
+ }
+
+ mod use_explicit_should_be_replaced {
+ use crate::super_imports::*;
+
+ fn with_explicit() {
+ let _ = foofoo();
+ }
+ }
+
+ mod use_double_super_should_be_replaced {
+ mod inner {
+ use super::super::*;
+
+ fn with_double_super() {
+ let _ = foofoo();
+ }
+ }
+ }
+
+ mod use_super_explicit_should_be_replaced {
+ use super::super::super_imports::*;
+
+ fn with_super_explicit() {
+ let _ = foofoo();
+ }
+ }
+
+ mod attestation_should_be_replaced {
+ use super::*;
+
+ fn with_explicit() {
+ let _ = foofoo();
+ }
+ }
+}
--- /dev/null
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:9:5
+ |
+LL | use crate::fn_mod::*;
+ | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+ |
+ = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:10:5
+ |
+LL | use crate::mod_mod::*;
+ | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:11:5
+ |
+LL | use crate::multi_fn_mod::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:12:5
+ |
+LL | use crate::struct_mod::*;
+ | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:15:5
+ |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:17:5
+ |
+LL | use wildcard_imports_helper::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:87:13
+ |
+LL | use crate::fn_mod::*;
+ | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:93:75
+ |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+ | ^ help: try: `inner_extern_foo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:94:13
+ |
+LL | use wildcard_imports_helper::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:105:20
+ |
+LL | use self::{inner::*, inner2::*};
+ | ^^^^^^^^ help: try: `inner::inner_foo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:105:30
+ |
+LL | use self::{inner::*, inner2::*};
+ | ^^^^^^^^^ help: try: `inner2::inner_bar`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:112:13
+ |
+LL | use wildcard_imports_helper::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:141:9
+ |
+LL | use crate::in_fn_test::*;
+ | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:150:9
+ |
+LL | use crate:: in_fn_test:: * ;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:151:9
+ |
+LL | use crate:: fn_mod::
+ | _________^
+LL | | *;
+ | |_________^ help: try: `crate:: fn_mod::foo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:162:13
+ |
+LL | use super::*;
+ | ^^^^^^^^ help: try: `super::foofoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:197:17
+ |
+LL | use super::*;
+ | ^^^^^^^^ help: try: `super::insidefoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:205:13
+ |
+LL | use crate::super_imports::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:214:17
+ |
+LL | use super::super::*;
+ | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:223:13
+ |
+LL | use super::super::super_imports::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:231:13
+ |
+LL | use super::*;
+ | ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
+
rustc.args(&["-Zpolonius"]);
}
Some(CompareMode::Chalk) => {
- rustc.args(&["-Zchalk"]);
+ rustc.args(&["-Ztrait-solver=chalk"]);
}
Some(CompareMode::SplitDwarf) if self.config.target.contains("windows") => {
rustc.args(&["-Csplit-debuginfo=unpacked", "-Zunstable-options"]);
pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[
"aarch64-apple-darwin",
- "aarch64-fuchsia",
+ "aarch64-unknown-fuchsia",
"aarch64-linux-android",
"aarch64-unknown-linux-gnu",
"arm-linux-androideabi",
"i686-linux-android",
"i686-unknown-linux-gnu",
"x86_64-apple-darwin",
- "x86_64-fuchsia",
+ "x86_64-unknown-fuchsia",
"x86_64-linux-android",
"x86_64-unknown-freebsd",
"x86_64-unknown-linux-gnu",
// FIXME(rcvalle): More targets are likely supported.
pub const CFI_SUPPORTED_TARGETS: &[&str] = &[
"aarch64-apple-darwin",
- "aarch64-fuchsia",
+ "aarch64-unknown-fuchsia",
"aarch64-linux-android",
"aarch64-unknown-freebsd",
"aarch64-unknown-linux-gnu",
"x86_64-apple-darwin",
- "x86_64-fuchsia",
+ "x86_64-unknown-fuchsia",
"x86_64-pc-solaris",
"x86_64-unknown-freebsd",
"x86_64-unknown-illumos",
git-repository-url = "https://github.com/rust-lang/rust/"
additional-css = ["error-index.css"]
additional-js = ["error-index.js"]
+input-404 = ""
[output.html.search]
enable = true
fn render_html(output_path: &Path) -> Result<(), Box<dyn Error>> {
let mut introduction = format!(
- "<script src='redirect.js'></script>
-# Rust error codes index
+ "# Rust error codes index
This page lists all the error codes emitted by the Rust compiler.
book.book.sections.push(BookItem::Chapter(chapter));
book.build()?;
- // We can't put this content into another file, otherwise `mbdbook` will also put it into the
+ // The error-index used to be generated manually (without mdbook), and the
+ // index was located at the top level. Now that it is generated with
+ // mdbook, error-index.html has moved to error_codes/error-index.html.
+ // This adds a redirect so that old links go to the new location.
+ //
+ // We can't put this content into another file, otherwise `mdbook` will also put it into the
// output directory, making a duplicate.
fs::write(
output_path.join("error-index.html"),
</head>
<body>
<div>If you are not automatically redirected to the error code index, please <a id="index-link" href="./error_codes/error-index.html">here</a>.
- <script>document.getElementById("index-link").click()</script>
</body>
</html>"#,
)?;
- // No need for a 404 file, it's already handled by the server.
- fs::remove_file(output_path.join("error_codes/404.html"))?;
-
Ok(())
}
let code = window.location.hash.replace(/^#/, '');
// We have to make sure this pattern matches to avoid inadvertently creating an
// open redirect.
- if (!/^E[0-9]+$/.test(code)) {
+ if (/^E[0-9]+$/.test(code)) {
+ window.location.replace('./error_codes/' + code + '.html');
return;
}
- if (window.location.pathname.indexOf("/error_codes/") !== -1) {
- // We're not at the top level, so we don't prepend with "./error_codes/".
- window.location = './' + code + '.html';
- } else {
- window.location = './error_codes/' + code + '.html';
- }
}
+ window.location.replace('./error_codes/error-index.html');
})()
[dependencies]
anyhow = "1.0.62"
+clap = { version = "4.0.15", features = ["derive"] }
fs-err = "2.8.1"
rustdoc-json-types = { version = "0.1.0", path = "../../rustdoc-json-types" }
+serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.85"
use std::fmt::Write;
+use serde::Serialize;
use serde_json::Value;
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub enum SelectorPart {
Field(String),
Index(usize),
-use std::env;
+use std::io::{BufWriter, Write};
-use anyhow::{anyhow, bail, Result};
+use anyhow::{bail, Result};
+use clap::Parser;
use fs_err as fs;
use rustdoc_json_types::{Crate, Id, FORMAT_VERSION};
+use serde::Serialize;
use serde_json::Value;
pub(crate) mod item_kind;
mod json_find;
mod validator;
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq, Serialize, Clone)]
struct Error {
kind: ErrorKind,
id: Id,
}
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq, Serialize, Clone)]
enum ErrorKind {
- NotFound,
+ NotFound(Vec<json_find::Selector>),
Custom(String),
}
+#[derive(Debug, Serialize)]
+struct JsonOutput {
+ path: String,
+ errors: Vec<Error>,
+}
+
+#[derive(Parser)]
+struct Cli {
+ /// The path to the json file to be linted
+ path: String,
+
+ /// Show verbose output
+ #[arg(long)]
+ verbose: bool,
+
+ #[arg(long)]
+ json_output: Option<String>,
+}
+
fn main() -> Result<()> {
- let path = env::args().nth(1).ok_or_else(|| anyhow!("no path given"))?;
+ let Cli { path, verbose, json_output } = Cli::parse();
+
let contents = fs::read_to_string(&path)?;
let krate: Crate = serde_json::from_str(&contents)?;
assert_eq!(krate.format_version, FORMAT_VERSION);
- let mut validator = validator::Validator::new(&krate);
+ let krate_json: Value = serde_json::from_str(&contents)?;
+
+ let mut validator = validator::Validator::new(&krate, krate_json);
validator.check_crate();
+ if let Some(json_output) = json_output {
+ let output = JsonOutput { path: path.clone(), errors: validator.errs.clone() };
+ let mut f = BufWriter::new(fs::File::create(json_output)?);
+ serde_json::to_writer(&mut f, &output)?;
+ f.flush()?;
+ }
+
if !validator.errs.is_empty() {
for err in validator.errs {
match err.kind {
- ErrorKind::NotFound => {
- let krate_json: Value = serde_json::from_str(&contents)?;
-
- let sels =
- json_find::find_selector(&krate_json, &Value::String(err.id.0.clone()));
- match &sels[..] {
- [] => unreachable!(
- "id must be in crate, or it wouldn't be reported as not found"
- ),
- [sel] => eprintln!(
- "{} not in index or paths, but refered to at '{}'",
- err.id.0,
- json_find::to_jsonpath(&sel)
- ),
- [sel, ..] => eprintln!(
- "{} not in index or paths, but refered to at '{}' and more",
- err.id.0,
- json_find::to_jsonpath(&sel)
- ),
+ ErrorKind::NotFound(sels) => match &sels[..] {
+ [] => {
+ unreachable!(
+ "id {:?} must be in crate, or it wouldn't be reported as not found",
+ err.id
+ )
+ }
+ [sel] => eprintln!(
+ "{} not in index or paths, but refered to at '{}'",
+ err.id.0,
+ json_find::to_jsonpath(&sel)
+ ),
+ [sel, ..] => {
+ if verbose {
+ let sels = sels
+ .iter()
+ .map(json_find::to_jsonpath)
+ .map(|i| format!("'{i}'"))
+ .collect::<Vec<_>>()
+ .join(", ");
+ eprintln!(
+ "{} not in index or paths, but refered to at {sels}",
+ err.id.0
+ );
+ } else {
+ eprintln!(
+ "{} not in index or paths, but refered to at '{}' and {} more",
+ err.id.0,
+ json_find::to_jsonpath(&sel),
+ sels.len() - 1,
+ )
+ }
}
- }
+ },
ErrorKind::Custom(msg) => eprintln!("{}: {}", err.id.0, msg),
}
}
use rustdoc_json_types::{
Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs,
- GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, Module, OpaqueTy, Path,
- Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding,
- TypeBindingKind, Typedef, Union, Variant, WherePredicate,
+ GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, ItemSummary, Module,
+ OpaqueTy, Path, Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias,
+ Type, TypeBinding, TypeBindingKind, Typedef, Union, Variant, VariantKind, WherePredicate,
};
+use serde_json::Value;
-use crate::{item_kind::Kind, Error, ErrorKind};
+use crate::{item_kind::Kind, json_find, Error, ErrorKind};
+
+// This is a rustc implementation detail that we rely on here
+const LOCAL_CRATE_ID: u32 = 0;
/// The Validator walks over the JSON tree, and ensures it is well formed.
/// It is made of several parts.
pub struct Validator<'a> {
pub(crate) errs: Vec<Error>,
krate: &'a Crate,
+ krate_json: Value,
/// Worklist of Ids to check.
todo: HashSet<&'a Id>,
/// Ids that have already been visited, so don't need to be checked again.
}
impl<'a> Validator<'a> {
- pub fn new(krate: &'a Crate) -> Self {
+ pub fn new(krate: &'a Crate, krate_json: Value) -> Self {
Self {
krate,
+ krate_json,
errs: Vec::new(),
seen_ids: HashSet::new(),
todo: HashSet::new(),
}
pub fn check_crate(&mut self) {
+ // Graph traverse the index
let root = &self.krate.root;
self.add_mod_id(root);
while let Some(id) = set_remove(&mut self.todo) {
self.seen_ids.insert(id);
self.check_item(id);
}
+
+ let root_crate_id = self.krate.index[root].crate_id;
+ assert_eq!(root_crate_id, LOCAL_CRATE_ID, "LOCAL_CRATE_ID is wrong");
+ for (id, item_info) in &self.krate.paths {
+ self.check_item_info(id, item_info);
+ }
}
fn check_item(&mut self, id: &'a Id) {
}
fn check_variant(&mut self, x: &'a Variant, id: &'a Id) {
- match x {
- Variant::Plain(discr) => {
- if let Some(discr) = discr {
- if let (Err(_), Err(_)) =
- (discr.value.parse::<i128>(), discr.value.parse::<u128>())
- {
- self.fail(
- id,
- ErrorKind::Custom(format!(
- "Failed to parse discriminant value `{}`",
- discr.value
- )),
- );
- }
- }
+ let Variant { kind, discriminant } = x;
+
+ if let Some(discr) = discriminant {
+ if let (Err(_), Err(_)) = (discr.value.parse::<i128>(), discr.value.parse::<u128>()) {
+ self.fail(
+ id,
+ ErrorKind::Custom(format!(
+ "Failed to parse discriminant value `{}`",
+ discr.value
+ )),
+ );
}
- Variant::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
- Variant::Struct { fields, fields_stripped: _ } => {
+ }
+
+ match kind {
+ VariantKind::Plain => {}
+ VariantKind::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
+ VariantKind::Struct { fields, fields_stripped: _ } => {
fields.iter().for_each(|f| self.add_field_id(f))
}
}
fp.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
}
+ fn check_item_info(&mut self, id: &Id, item_info: &ItemSummary) {
+ // FIXME: Their should be a better way to determine if an item is local, rather than relying on `LOCAL_CRATE_ID`,
+ // which encodes rustc implementation details.
+ if item_info.crate_id == LOCAL_CRATE_ID && !self.krate.index.contains_key(id) {
+ self.errs.push(Error {
+ id: id.clone(),
+ kind: ErrorKind::Custom(
+ "Id for local item in `paths` but not in `index`".to_owned(),
+ ),
+ })
+ }
+ }
+
fn add_id_checked(&mut self, id: &'a Id, valid: fn(Kind) -> bool, expected: &str) {
if let Some(kind) = self.kind_of(id) {
if valid(kind) {
} else {
if !self.missing_ids.contains(id) {
self.missing_ids.insert(id);
- self.fail(id, ErrorKind::NotFound)
+
+ let sels = json_find::find_selector(&self.krate_json, &Value::String(id.0.clone()));
+ assert_ne!(sels.len(), 0);
+
+ self.fail(id, ErrorKind::NotFound(sels))
}
}
}
use std::collections::HashMap;
-use rustdoc_json_types::{Crate, Item, Visibility};
+use rustdoc_json_types::{Crate, Item, ItemKind, ItemSummary, Visibility, FORMAT_VERSION};
+
+use crate::json_find::SelectorPart;
use super::*;
#[track_caller]
fn check(krate: &Crate, errs: &[Error]) {
- let mut validator = Validator::new(krate);
+ let krate_string = serde_json::to_string(krate).unwrap();
+ let krate_json = serde_json::from_str(&krate_string).unwrap();
+
+ let mut validator = Validator::new(krate, krate_json);
validator.check_crate();
assert_eq!(errs, &validator.errs[..]);
format_version: rustdoc_json_types::FORMAT_VERSION,
};
- check(&k, &[Error { kind: ErrorKind::NotFound, id: id("1") }]);
+ check(
+ &k,
+ &[Error {
+ kind: ErrorKind::NotFound(vec![vec![
+ SelectorPart::Field("index".to_owned()),
+ SelectorPart::Field("0".to_owned()),
+ SelectorPart::Field("links".to_owned()),
+ SelectorPart::Field("Not Found".to_owned()),
+ ]]),
+ id: id("1"),
+ }],
+ );
+}
+
+// Test we would catch
+// https://github.com/rust-lang/rust/issues/104064#issuecomment-1368589718
+#[test]
+fn errors_on_local_in_paths_and_not_index() {
+ let krate = Crate {
+ root: id("0:0:1572"),
+ crate_version: None,
+ includes_private: false,
+ index: HashMap::from_iter([
+ (
+ id("0:0:1572"),
+ Item {
+ id: id("0:0:1572"),
+ crate_id: 0,
+ name: Some("microcore".to_owned()),
+ span: None,
+ visibility: Visibility::Public,
+ docs: None,
+ links: HashMap::from_iter([(("prim@i32".to_owned(), id("0:1:1571")))]),
+ attrs: Vec::new(),
+ deprecation: None,
+ inner: ItemEnum::Module(Module {
+ is_crate: true,
+ items: vec![id("0:1:717")],
+ is_stripped: false,
+ }),
+ },
+ ),
+ (
+ id("0:1:717"),
+ Item {
+ id: id("0:1:717"),
+ crate_id: 0,
+ name: Some("i32".to_owned()),
+ span: None,
+ visibility: Visibility::Public,
+ docs: None,
+ links: HashMap::default(),
+ attrs: Vec::new(),
+ deprecation: None,
+ inner: ItemEnum::Primitive(Primitive { name: "i32".to_owned(), impls: vec![] }),
+ },
+ ),
+ ]),
+ paths: HashMap::from_iter([(
+ id("0:1:1571"),
+ ItemSummary {
+ crate_id: 0,
+ path: vec!["microcore".to_owned(), "i32".to_owned()],
+ kind: ItemKind::Primitive,
+ },
+ )]),
+ external_crates: HashMap::default(),
+ format_version: rustdoc_json_types::FORMAT_VERSION,
+ };
+
+ check(
+ &krate,
+ &[Error {
+ id: id("0:1:1571"),
+ kind: ErrorKind::Custom("Id for local item in `paths` but not in `index`".to_owned()),
+ }],
+ );
+}
+
+#[test]
+#[should_panic = "LOCAL_CRATE_ID is wrong"]
+fn checks_local_crate_id_is_correct() {
+ let krate = Crate {
+ root: id("root"),
+ crate_version: None,
+ includes_private: false,
+ index: HashMap::from_iter([(
+ id("root"),
+ Item {
+ id: id("root"),
+ crate_id: LOCAL_CRATE_ID.wrapping_add(1),
+ name: Some("irrelavent".to_owned()),
+ span: None,
+ visibility: Visibility::Public,
+ docs: None,
+ links: HashMap::default(),
+ attrs: Vec::new(),
+ deprecation: None,
+ inner: ItemEnum::Module(Module {
+ is_crate: true,
+ items: vec![],
+ is_stripped: false,
+ }),
+ },
+ )]),
+ paths: HashMap::default(),
+ external_crates: HashMap::default(),
+ format_version: FORMAT_VERSION,
+ };
+ check(&krate, &[]);
}
[[package]]
name = "addr2line"
-version = "0.17.0"
+version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
+checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
dependencies = [
"gimli",
]
[[package]]
name = "aho-corasick"
-version = "0.7.19"
+version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
+checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "backtrace"
-version = "0.3.66"
+version = "0.3.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
+checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
dependencies = [
"addr2line",
"cc",
[[package]]
name = "bstr"
-version = "1.0.1"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd"
+checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b"
dependencies = [
"memchr",
"once_cell",
[[package]]
name = "cargo_metadata"
-version = "0.15.0"
+version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36"
+checksum = "982a0cf6a99c350d7246035613882e376d58cebe571785abc5da4f648d53ac0a"
dependencies = [
"camino",
"cargo-platform",
"semver",
"serde",
"serde_json",
+ "thiserror",
]
[[package]]
name = "cc"
-version = "1.0.73"
+version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
+checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
[[package]]
name = "cfg-if"
[[package]]
name = "crossbeam-utils"
-version = "0.8.11"
+version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
+checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
dependencies = [
"cfg-if",
- "once_cell",
]
[[package]]
[[package]]
name = "env_logger"
-version = "0.9.1"
+version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272"
+checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
dependencies = [
"atty",
"humantime",
[[package]]
name = "getrandom"
-version = "0.2.7"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
+checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if",
"libc",
[[package]]
name = "gimli"
-version = "0.26.2"
+version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
+checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793"
[[package]]
name = "hermit-abi"
[[package]]
name = "itoa"
-version = "1.0.3"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
+checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "lazy_static"
[[package]]
name = "libc"
-version = "0.2.133"
+version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "libffi"
[[package]]
name = "libloading"
-version = "0.7.3"
+version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
[[package]]
name = "miniz_oxide"
-version = "0.5.4"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
+checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
dependencies = [
"adler",
]
[[package]]
name = "object"
-version = "0.29.0"
+version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
+checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
-version = "1.15.0"
+version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "owo-colors"
[[package]]
name = "parking_lot_core"
-version = "0.8.5"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
+checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
dependencies = [
"cfg-if",
"instant",
[[package]]
name = "ppv-lite86"
-version = "0.2.16"
+version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
-version = "1.0.45"
+version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3edcd08cf4fea98d1ae6c9ddd3b8ccb1acac7c3693d62625969a7daa04a2ae36"
+checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.21"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
-version = "1.6.0"
+version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
+checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"aho-corasick",
"memchr",
[[package]]
name = "regex-syntax"
-version = "0.6.27"
+version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
+checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "remove_dir_all"
[[package]]
name = "ryu"
-version = "1.0.11"
+version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
+checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "scopeguard"
[[package]]
name = "semver"
-version = "1.0.14"
+version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
+checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
dependencies = [
"serde",
]
[[package]]
name = "serde"
-version = "1.0.145"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.145"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "serde_json"
-version = "1.0.85"
+version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
+checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
dependencies = [
"itoa",
"ryu",
[[package]]
name = "smallvec"
-version = "1.9.0"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "syn"
-version = "1.0.101"
+version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
"winapi-util",
]
+[[package]]
+name = "thiserror"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "thread_local"
version = "1.1.4"
[[package]]
name = "tracing"
-version = "0.1.36"
+version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
+checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if",
"pin-project-lite",
[[package]]
name = "tracing-core"
-version = "0.1.29"
+version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
+checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
dependencies = [
"once_cell",
"valuable",
[[package]]
name = "tracing-subscriber"
-version = "0.3.15"
+version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b"
+checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
dependencies = [
"sharded-slab",
"thread_local",
[[package]]
name = "unicode-ident"
-version = "1.0.4"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "valuable"
[[package]]
name = "anyhow"
-version = "1.0.65"
+version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
+checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
[[package]]
name = "bitflags"
[[package]]
name = "cargo_metadata"
-version = "0.15.0"
+version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36"
+checksum = "982a0cf6a99c350d7246035613882e376d58cebe571785abc5da4f648d53ac0a"
dependencies = [
"camino",
"cargo-platform",
"semver",
"serde",
"serde_json",
+ "thiserror",
]
[[package]]
[[package]]
name = "getrandom"
-version = "0.2.7"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
+checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if",
"libc",
[[package]]
name = "itoa"
-version = "1.0.3"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
+checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "libc"
-version = "0.2.133"
+version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "proc-macro2"
-version = "1.0.45"
+version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3edcd08cf4fea98d1ae6c9ddd3b8ccb1acac7c3693d62625969a7daa04a2ae36"
+checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.21"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustc-build-sysroot"
-version = "0.4.0"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20c4b4625eeb148cccf82d5e9b90ad7fab3b11a0204cf75cc7fa04981a0fdffd"
+checksum = "d65b1271cdac365b71b59570ea35d945dea2dd2cc47eba3d33b4bd1e0190ac6d"
dependencies = [
"anyhow",
"rustc_version",
[[package]]
name = "ryu"
-version = "1.0.11"
+version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
+checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "semver"
-version = "1.0.14"
+version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
+checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
dependencies = [
"serde",
]
[[package]]
name = "serde"
-version = "1.0.145"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.145"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "serde_json"
-version = "1.0.85"
+version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
+checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
dependencies = [
"itoa",
"ryu",
[[package]]
name = "syn"
-version = "1.0.101"
+version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "thiserror"
-version = "1.0.37"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.37"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "unicode-ident"
-version = "1.0.4"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "wasi"
rustc_version = "0.4"
serde_json = "1.0.40"
cargo_metadata = "0.15.0"
-rustc-build-sysroot = "0.4"
+rustc-build-sysroot = "0.4.1"
# 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`
is_bin || is_test
}
- fn out_filename(prefix: &str, suffix: &str) -> PathBuf {
- if let Some(out_dir) = get_arg_flag_value("--out-dir") {
- let mut path = PathBuf::from(out_dir);
- path.push(format!(
- "{}{}{}{}",
- prefix,
- get_arg_flag_value("--crate-name").unwrap(),
- // This is technically a `-C` flag but the prefix seems unique enough...
- // (and cargo passes this before the filename so it should be unique)
- get_arg_flag_value("extra-filename").unwrap_or_default(),
- suffix,
- ));
- path
+ fn out_filenames() -> Vec<PathBuf> {
+ if let Some(out_file) = get_arg_flag_value("-o") {
+ // `-o` has precedence over `--out-dir`.
+ vec![PathBuf::from(out_file)]
} else {
- let out_file = get_arg_flag_value("-o").unwrap();
- PathBuf::from(out_file)
+ let out_dir = get_arg_flag_value("--out-dir").unwrap_or_default();
+ let path = PathBuf::from(out_dir);
+ // Ask rustc for the filename (since that is target-dependent).
+ let mut rustc = miri_for_host(); // sysroot doesn't matter for this so we just use the host
+ rustc.arg("--print").arg("file-names");
+ for flag in ["--crate-name", "--crate-type", "--target"] {
+ for val in get_arg_flag_values(flag) {
+ rustc.arg(flag).arg(val);
+ }
+ }
+ // This is technically passed as `-C extra-filename=...`, but the prefix seems unique
+ // enough... (and cargo passes this before the filename so it should be unique)
+ if let Some(extra) = get_arg_flag_value("extra-filename") {
+ rustc.arg("-C").arg(format!("extra-filename={extra}"));
+ }
+ rustc.arg("-");
+
+ let output = rustc.output().expect("cannot run rustc to determine file name");
+ assert!(
+ output.status.success(),
+ "rustc failed when determining file name:\n{output:?}"
+ );
+ let output =
+ String::from_utf8(output.stdout).expect("rustc returned non-UTF-8 filename");
+ output.lines().filter(|l| !l.is_empty()).map(|l| path.join(l)).collect()
}
}
let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV");
let store_json = |info: CrateRunInfo| {
- // Create a stub .d file to stop Cargo from "rebuilding" the crate:
- // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693
- // As we store a JSON file instead of building the crate here, an empty file is fine.
- let dep_info_name = out_filename("", ".d");
- if verbose > 0 {
- eprintln!("[cargo-miri rustc] writing stub dep-info to `{}`", dep_info_name.display());
+ if get_arg_flag_value("--emit").unwrap_or_default().split(',').any(|e| e == "dep-info") {
+ // Create a stub .d file to stop Cargo from "rebuilding" the crate:
+ // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693
+ // As we store a JSON file instead of building the crate here, an empty file is fine.
+ let dep_info_name = format!(
+ "{}/{}{}.d",
+ get_arg_flag_value("--out-dir").unwrap(),
+ get_arg_flag_value("--crate-name").unwrap(),
+ get_arg_flag_value("extra-filename").unwrap_or_default(),
+ );
+ if verbose > 0 {
+ eprintln!("[cargo-miri rustc] writing stub dep-info to `{dep_info_name}`");
+ }
+ File::create(dep_info_name).expect("failed to create fake .d file");
}
- File::create(dep_info_name).expect("failed to create fake .d file");
- let filename = out_filename("", "");
- if verbose > 0 {
- eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display());
+ for filename in out_filenames() {
+ if verbose > 0 {
+ eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display());
+ }
+ info.store(&filename);
}
- info.store(&filename);
- // For Windows and WASM, do the same thing again with `.exe`/`.wasm` appended to the filename.
- // (Need to do this here as cargo moves that "binary" to a different place before running it.)
- info.store(&out_filename("", ".exe"));
- info.store(&out_filename("", ".wasm"));
};
let runnable_crate = !info_query && is_runnable_crate();
// Alter the `-o` parameter so that it does not overwrite the JSON file we stored above.
let mut args = env.args;
+ let mut out_filename = None;
for i in 0..args.len() {
if args[i] == "-o" {
+ out_filename = Some(args[i + 1].clone());
args[i + 1].push_str(".miri");
}
}
+ let out_filename = out_filename.expect("rustdoc must pass `-o`");
cmd.args(&args);
cmd.env("MIRI_BE_RUSTC", "target");
eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{cmd:?}");
}
- exec_with_pipe(cmd, &env.stdin, format!("{}.stdin", out_filename("", "").display()));
+ exec_with_pipe(cmd, &env.stdin, format!("{out_filename}.stdin"));
}
return;
// Create a stub .rlib file if "link" was requested by cargo.
// This is necessary to prevent cargo from doing rebuilds all the time.
if emit_link_hack {
- // Some platforms prepend "lib", some do not... let's just create both files.
- File::create(out_filename("lib", ".rlib")).expect("failed to create fake .rlib file");
- File::create(out_filename("", ".rlib")).expect("failed to create fake .rlib file");
- // Just in case this is a cdylib or staticlib, also create those fake files.
- File::create(out_filename("lib", ".so")).expect("failed to create fake .so file");
- File::create(out_filename("lib", ".a")).expect("failed to create fake .a file");
- File::create(out_filename("lib", ".dylib")).expect("failed to create fake .dylib file");
- File::create(out_filename("", ".dll")).expect("failed to create fake .dll file");
- File::create(out_filename("", ".lib")).expect("failed to create fake .lib file");
+ for filename in out_filenames() {
+ if verbose > 0 {
+ eprintln!("[cargo-miri rustc] creating fake lib file at `{}`", filename.display());
+ }
+ File::create(filename).expect("failed to create fake lib file");
+ }
}
debug_cmd("[cargo-miri rustc]", verbose, &cmd);
.rustflags(rustflags)
.cargo(cargo_cmd)
.build_from_source(&rust_src)
- .unwrap_or_else(|_| {
- if only_setup {
- show_error!("failed to build sysroot, see error details above")
+ .unwrap_or_else(|err| {
+ if print_sysroot {
+ show_error!("failed to build sysroot")
+ } else if only_setup {
+ show_error!("failed to build sysroot: {err:?}")
} else {
show_error!(
"failed to build sysroot; run `cargo miri setup` to see the error details"
MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var
MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
- MIRI_TEST_TARGET=wasm32-wasi MIRI_NO_STD=1 run_tests_minimal no_std # supports std but miri doesn't support it
+ MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer
MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture
+ MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std # JSON target file
;;
x86_64-apple-darwin)
MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture
extern crate rustc_span;
extern crate rustc_target;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
mod borrow_tracker;
mod clock;
mod concurrency;
let min_align = match this.tcx.sess.target.arch.as_ref() {
"x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8,
"x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16,
- arch => bug!("Unsupported target architecture: {}", arch),
+ arch => bug!("unsupported target architecture for malloc: `{}`", arch),
};
// Windows always aligns, even small allocations.
// Source: <https://support.microsoft.com/en-us/help/286470/how-to-use-pageheap-exe-in-windows-xp-windows-2000-and-windows-server>
return Ok(Some(body));
}
- this.handle_unsupported(format!("can't call foreign function: {link_name}"))?;
+ this.handle_unsupported(format!(
+ "can't call foreign function `{link_name}` on OS `{os}`",
+ os = this.tcx.sess.target.os,
+ ))?;
return Ok(None);
}
}
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
let this = self.eval_context_mut();
- let allocator_kind = if let Some(allocator_kind) = this.tcx.allocator_kind(()) {
- allocator_kind
- } else {
+ let Some(allocator_kind) = this.tcx.allocator_kind(()) else {
// in real code, this symbol does not exist without an allocator
return Ok(EmulateByNameResult::NotSupported);
};
let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr).map_err(|_e| {
- err_machine_stop!(TerminationInfo::Abort(
- format!("pointer passed to miri_get_alloc_id must not be dangling, got {ptr:?}")
- ))
+ err_machine_stop!(TerminationInfo::Abort(format!(
+ "pointer passed to miri_get_alloc_id must not be dangling, got {ptr:?}"
+ )))
})?;
this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?;
}
let ptr = this.read_pointer(ptr)?;
let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr)?;
if offset != Size::ZERO {
- throw_unsup_format!("pointer passed to miri_static_root must point to beginning of an allocated block");
+ throw_unsup_format!(
+ "pointer passed to miri_static_root must point to beginning of an allocated block"
+ );
}
this.machine.static_roots.push(alloc_id);
}
// We read this as a plain OsStr and write it as a path, which will convert it to the target.
let path = this.read_os_str_from_c_str(ptr)?.to_owned();
- let (success, needed_size) = this.write_path_to_c_str(Path::new(&path), out, out_size)?;
+ let (success, needed_size) =
+ this.write_path_to_c_str(Path::new(&path), out, out_size)?;
// Return value: 0 on success, otherwise the size it would have needed.
this.write_int(if success { 0 } else { needed_size }, dest)?;
}
this.write_pointer(res, dest)?;
}
"calloc" => {
- let [items, len] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+ let [items, len] =
+ this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let items = this.read_machine_usize(items)?;
let len = this.read_machine_usize(len)?;
- let size =
- items.checked_mul(len).ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?;
+ let size = items
+ .checked_mul(len)
+ .ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?;
let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C)?;
this.write_pointer(res, dest)?;
}
this.free(ptr, MiriMemoryKind::C)?;
}
"realloc" => {
- let [old_ptr, new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+ let [old_ptr, new_size] =
+ this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let old_ptr = this.read_pointer(old_ptr)?;
let new_size = this.read_machine_usize(new_size)?;
let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?;
};
match link_name.as_str() {
- "__rust_alloc" => return this.emulate_allocator(Symbol::intern("__rg_alloc"), default),
+ "__rust_alloc" =>
+ return this.emulate_allocator(Symbol::intern("__rg_alloc"), default),
"miri_alloc" => {
default(this)?;
return Ok(EmulateByNameResult::NeedsJumping);
- },
+ }
_ => unreachable!(),
}
}
)?;
// We just allocated this, the access is definitely in-bounds.
- this.write_bytes_ptr(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap();
+ this.write_bytes_ptr(
+ ptr.into(),
+ iter::repeat(0u8).take(usize::try_from(size).unwrap()),
+ )
+ .unwrap();
this.write_pointer(ptr, dest)
});
}
};
match link_name.as_str() {
- "__rust_dealloc" => return this.emulate_allocator(Symbol::intern("__rg_dealloc"), default),
+ "__rust_dealloc" =>
+ return this.emulate_allocator(Symbol::intern("__rg_dealloc"), default),
"miri_dealloc" => {
default(this)?;
return Ok(EmulateByNameResult::NeedsJumping);
}
}
"__rust_realloc" => {
- let [ptr, old_size, align, new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?;
+ let [ptr, old_size, align, new_size] =
+ this.check_shim(abi, Abi::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let old_size = this.read_machine_usize(old_size)?;
let align = this.read_machine_usize(align)?;
// C memory handling functions
"memcmp" => {
- let [left, right, n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+ let [left, right, n] =
+ this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let left = this.read_pointer(left)?;
let right = this.read_pointer(right)?;
let n = Size::from_bytes(this.read_machine_usize(n)?);
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"memrchr" => {
- let [ptr, val, num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+ let [ptr, val, num] =
+ this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let val = this.read_scalar(val)?.to_i32()?;
let num = this.read_machine_usize(num)?;
}
}
"memchr" => {
- let [ptr, val, num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+ let [ptr, val, num] =
+ this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let val = this.read_scalar(val)?.to_i32()?;
let num = this.read_machine_usize(num)?;
let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let n = this.read_c_str(ptr)?.len();
- this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?;
+ this.write_scalar(
+ Scalar::from_machine_usize(u64::try_from(n).unwrap(), this),
+ dest,
+ )?;
}
// math functions (note that there are also intrinsics for some other functions)
let a = this.read_scalar(a)?.to_u64()?;
let b = this.read_scalar(b)?.to_u64()?;
- #[allow(clippy::integer_arithmetic)] // adding two u64 and a u8 cannot wrap in a u128
+ #[allow(clippy::integer_arithmetic)]
+ // adding two u64 and a u8 cannot wrap in a u128
let wide_sum = u128::from(c_in) + u128::from(a) + u128::from(b);
#[allow(clippy::integer_arithmetic)] // it's a u128, we can shift by 64
let (c_out, sum) = ((wide_sum >> 64).truncate::<u8>(), wide_sum.truncate::<u64>());
let sum_field = this.place_field(dest, 1)?;
this.write_scalar(Scalar::from_u64(sum), &sum_field)?;
}
- "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => {
+ "llvm.x86.sse2.pause"
+ if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" =>
+ {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
this.yield_active_thread();
}
let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
let arg = this.read_scalar(arg)?.to_i32()?;
match arg {
- 15 => { // SY ("full system scope")
+ // SY ("full system scope")
+ 15 => {
this.yield_active_thread();
}
_ => {
}
// Platform-specific shims
- _ => match this.tcx.sess.target.os.as_ref() {
- target if target_os_is_unix(target) => return shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
- "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
- target => throw_unsup_format!("the target `{}` is not supported", target),
- }
+ _ =>
+ return match this.tcx.sess.target.os.as_ref() {
+ target_os if target_os_is_unix(target_os) =>
+ shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(
+ this, link_name, abi, args, dest,
+ ),
+ "windows" =>
+ shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(
+ this, link_name, abi, args, dest,
+ ),
+ _ => Ok(EmulateByNameResult::NotSupported),
+ },
};
// We only fall through to here if we did *not* hit the `_` arm above,
// i.e., if we actually emulated the function with one of the shims.
// And move to the final state.
self.0 = Done;
}
- "wasi" | "none" => {
- // No OS, no TLS dtors.
+ _ => {
+ // No TLS dtor support.
// FIXME: should we do something on wasi?
self.0 = Done;
}
- os => {
- throw_unsup_format!(
- "the TLS machinery does not know how to handle OS `{os}`"
- );
- }
}
}
PthreadDtors(state) => {
// Platform-specific shims
_ => {
let target_os = &*this.tcx.sess.target.os;
- match target_os {
- "android" => return shims::unix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
- "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
- "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
- "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
- _ => panic!("unsupported Unix OS {target_os}"),
- }
+ return match target_os {
+ "android" => shims::unix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
+ "freebsd" => shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
+ "linux" => shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
+ "macos" => shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
+ _ => Ok(EmulateByNameResult::NotSupported),
+ };
}
};
[[package]]
name = "proc-macro2"
-version = "1.0.44"
+version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58"
+checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.21"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
[[package]]
name = "serde_derive"
-version = "1.0.145"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "syn"
-version = "1.0.101"
+version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "unicode-ident"
-version = "1.0.4"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "hermit-abi"
-version = "0.1.19"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"libc",
]
[[package]]
name = "libc"
-version = "0.2.137"
+version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "lock_api"
[[package]]
name = "num_cpus"
-version = "1.14.0"
+version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
+checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
dependencies = [
"hermit-abi",
"libc",
[[package]]
name = "parking_lot_core"
-version = "0.9.4"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
+checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
dependencies = [
"cfg-if",
"libc",
[[package]]
name = "proc-macro2"
-version = "1.0.47"
+version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
+checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.21"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
-version = "1.0.103"
+version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "tokio"
-version = "1.22.0"
+version = "1.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3"
+checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46"
dependencies = [
"autocfg",
"bytes",
"signal-hook-registry",
"socket2",
"tokio-macros",
- "winapi",
+ "windows-sys",
]
[[package]]
name = "tokio-macros"
-version = "1.8.0"
+version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
+checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "unicode-ident"
-version = "1.0.5"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "wasi"
[dependencies]
# all dependencies (and their transitive ones) listed here can be used in `tests/`.
-tokio = { version = "1.0", features = ["full"] }
libc = "0.2"
-page_size = "0.5"
num_cpus = "1.10.1"
getrandom_1 = { package = "getrandom", version = "0.1" }
getrandom = { version = "0.2" }
rand = { version = "0.8", features = ["small_rng"] }
+[target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
+page_size = "0.5"
+tokio = { version = "1.0", features = ["full"] }
+
[workspace]
--- /dev/null
+{
+ "arch": "avr",
+ "cpu": "atmega328p",
+ "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8",
+ "env": "",
+ "executables": true,
+ "linker": "avr-gcc",
+ "linker-flavor": "gcc",
+ "linker-is-gnu": true,
+ "llvm-target": "avr-unknown-unknown",
+ "os": "unknown",
+ "position-independent-executables": false,
+ "exe-suffix": ".elf",
+ "eh-frame-header": false,
+ "pre-link-args": {
+ "gcc": ["-mmcu=atmega328p"]
+ },
+ "late-link-args": {
+ "gcc": ["-lgcc"]
+ },
+ "target-c-int-width": "16",
+ "target-endian": "little",
+ "target-pointer-width": "16",
+ "vendor": "unknown"
+}
//@only-target-linux
//@only-on-host
+//@normalize-stderr-test: "OS `.*`" -> "$$OS"
extern "C" {
fn foo();
fn main() {
unsafe {
- foo(); //~ ERROR: unsupported operation: can't call foreign function: foo
+ foo(); //~ ERROR: unsupported operation: can't call foreign function `foo`
}
}
-error: unsupported operation: can't call foreign function: foo
+error: unsupported operation: can't call foreign function `foo` on $OS
--> $DIR/function_not_in_so.rs:LL:CC
|
LL | foo();
- | ^^^^^ can't call foreign function: foo
+ | ^^^^^ can't call foreign function `foo` on $OS
|
= help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
= note: BACKTRACE:
+//@normalize-stderr-test: "OS `.*`" -> "$$OS"
// Make sure we pretend the allocation symbols don't exist when there is no allocator
#![feature(lang_items, start)]
#[start]
fn start(_: isize, _: *const *const u8) -> isize {
unsafe {
- __rust_alloc(1, 1); //~ERROR: unsupported operation: can't call foreign function: __rust_alloc
+ __rust_alloc(1, 1); //~ERROR: unsupported operation: can't call foreign function `__rust_alloc`
}
0
-error: unsupported operation: can't call foreign function: __rust_alloc
+error: unsupported operation: can't call foreign function `__rust_alloc` on $OS
--> $DIR/no_global_allocator.rs:LL:CC
|
LL | __rust_alloc(1, 1);
- | ^^^^^^^^^^^^^^^^^^ can't call foreign function: __rust_alloc
+ | ^^^^^^^^^^^^^^^^^^ can't call foreign function `__rust_alloc` on $OS
|
= help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
= note: BACKTRACE:
+//@normalize-stderr-test: "OS `.*`" -> "$$OS"
+
fn main() {
extern "Rust" {
fn foo();
}
unsafe {
- foo(); //~ ERROR: unsupported operation: can't call foreign function: foo
+ foo(); //~ ERROR: unsupported operation: can't call foreign function `foo`
}
}
-error: unsupported operation: can't call foreign function: foo
+error: unsupported operation: can't call foreign function `foo` on $OS
--> $DIR/unsupported_foreign_function.rs:LL:CC
|
LL | foo();
- | ^^^^^ can't call foreign function: foo
+ | ^^^^^ can't call foreign function `foo` on $OS
|
= help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
= note: BACKTRACE:
--- /dev/null
+//! `signal()` is special on Linux and macOS that it's only supported within libstd.
+//! The implementation is not complete enough to permit user code to call it.
+//@ignore-target-windows: No libc on Windows
+//@normalize-stderr-test: "OS `.*`" -> "$$OS"
+
+fn main() {
+ unsafe {
+ libc::signal(libc::SIGPIPE, libc::SIG_IGN);
+ //~^ ERROR: unsupported operation: can't call foreign function `signal`
+ }
+}
--- /dev/null
+error: unsupported operation: can't call foreign function `signal` on $OS
+ --> $DIR/unsupported_incomplete_function.rs:LL:CC
+ |
+LL | libc::signal(libc::SIGPIPE, libc::SIG_IGN);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function `signal` on $OS
+ |
+ = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
+ = note: BACKTRACE:
+ = note: inside `main` at $DIR/unsupported_incomplete_function.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
+++ /dev/null
-//! `signal()` is special on Linux and macOS that it's only supported within libstd.
-//! The implementation is not complete enough to permit user code to call it.
-//@ignore-target-windows: No libc on Windows
-
-fn main() {
- unsafe {
- libc::signal(libc::SIGPIPE, libc::SIG_IGN);
- //~^ ERROR: unsupported operation: can't call foreign function: signal
- }
-}
+++ /dev/null
-error: unsupported operation: can't call foreign function: signal
- --> $DIR/unsupported_signal.rs:LL:CC
- |
-LL | libc::signal(libc::SIGPIPE, libc::SIG_IGN);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: signal
- |
- = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
- = note: BACKTRACE:
- = note: inside `main` at $DIR/unsupported_signal.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to previous error
-
//@compile-flags: -Zmiri-panic-on-unsupported
+//@normalize-stderr-test: "OS `.*`" -> "$$OS"
fn main() {
extern "Rust" {
-thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function: foo', $DIR/unsupported_foreign_function.rs:LL:CC
+thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function `foo` on $OS', $DIR/unsupported_foreign_function.rs:LL:CC
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-Subproject commit 300b5ec61ef38855a07e6bb4955a37aa1c414c00
+Subproject commit 5b2eee7eed72b4894909c5eecbf014ea0b5ad995
curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true }
# Ensure `extra_traits` of libc, which is used transitively by Cargo.
libc = { version = "0.2", features = ["extra_traits"] }
+# Ensure `js` of getrandom, which is (unfortunately) used transitively by Cargo.
+getrandom = { version = "0.2", features = ["js"] }
# Ensure default features of libz-sys, which are disabled in some scenarios.
libz-sys = { version = "1.1.2" }
# Ensure default features of regex, which are disabled in some scenarios.
const os = require('os');
const {Options, runTest} = require('browser-ui-test');
+// If a test fails or errors, we will retry it two more times in case it was a flaky failure.
+const NB_RETRY = 3;
+
function showHelp() {
console.log("rustdoc-js options:");
console.log(" --doc-folder [PATH] : location of the generated doc folder");
};
}
-/// Sort array by .file_name property
+// Sort array by .file_name property
function by_filename(a, b) {
return a.file_name - b.file_name;
}
+async function runTests(opts, framework_options, files, results, status_bar, showTestFailures) {
+ const tests_queue = [];
+
+ for (const testPath of files) {
+ const callback = runTest(testPath, framework_options)
+ .then(out => {
+ const [output, nb_failures] = out;
+ results[nb_failures === 0 ? "successful" : "failed"].push({
+ file_name: testPath,
+ output: output,
+ });
+ if (nb_failures === 0) {
+ status_bar.successful();
+ } else if (showTestFailures) {
+ status_bar.erroneous();
+ }
+ })
+ .catch(err => {
+ results.errored.push({
+ file_name: testPath,
+ output: err,
+ });
+ if (showTestFailures) {
+ status_bar.erroneous();
+ }
+ })
+ .finally(() => {
+ // We now remove the promise from the tests_queue.
+ tests_queue.splice(tests_queue.indexOf(callback), 1);
+ });
+ tests_queue.push(callback);
+ if (opts["jobs"] > 0 && tests_queue.length >= opts["jobs"]) {
+ await Promise.race(tests_queue);
+ }
+ }
+ if (tests_queue.length > 0) {
+ await Promise.all(tests_queue);
+ }
+}
+
+function createEmptyResults() {
+ return {
+ successful: [],
+ failed: [],
+ errored: [],
+ };
+}
+
async function main(argv) {
let opts = parseOptions(argv.slice(2));
if (opts === null) {
let debug = false;
// Run tests in sequentially
let headless = true;
- const options = new Options();
+ const framework_options = new Options();
try {
// This is more convenient that setting fields one by one.
let args = [
args.push("--executable-path");
args.push(opts["executable_path"]);
}
- options.parseArguments(args);
+ framework_options.parseArguments(args);
} catch (error) {
console.error(`invalid argument: ${error}`);
process.exit(1);
}
- let failed = false;
let files;
if (opts["files"].length === 0) {
files = fs.readdirSync(opts["tests_folder"]);
console.error("rustdoc-gui: No test selected");
process.exit(2);
}
+ files.forEach((file_name, index) => {
+ files[index] = path.join(opts["tests_folder"], file_name);
+ });
files.sort();
if (!headless) {
};
process.on('exit', exitHandling);
- const tests_queue = [];
- let results = {
- successful: [],
- failed: [],
- errored: [],
- };
+ const originalFilesLen = files.length;
+ let results = createEmptyResults();
const status_bar = char_printer(files.length);
- for (let i = 0; i < files.length; ++i) {
- const file_name = files[i];
- const testPath = path.join(opts["tests_folder"], file_name);
- const callback = runTest(testPath, options)
- .then(out => {
- const [output, nb_failures] = out;
- results[nb_failures === 0 ? "successful" : "failed"].push({
- file_name: testPath,
- output: output,
- });
- if (nb_failures > 0) {
- status_bar.erroneous();
- failed = true;
- } else {
- status_bar.successful();
- }
- })
- .catch(err => {
- results.errored.push({
- file_name: testPath + file_name,
- output: err,
- });
- status_bar.erroneous();
- failed = true;
- })
- .finally(() => {
- // We now remove the promise from the tests_queue.
- tests_queue.splice(tests_queue.indexOf(callback), 1);
- });
- tests_queue.push(callback);
- if (opts["jobs"] > 0 && tests_queue.length >= opts["jobs"]) {
- await Promise.race(tests_queue);
+
+ let new_results;
+ for (let it = 0; it < NB_RETRY && files.length > 0; ++it) {
+ new_results = createEmptyResults();
+ await runTests(opts, framework_options, files, new_results, status_bar, it + 1 >= NB_RETRY);
+ Array.prototype.push.apply(results.successful, new_results.successful);
+ // We generate the new list of files with the previously failing tests.
+ files = Array.prototype.concat(new_results.failed, new_results.errored);
+ if (files.length > originalFilesLen / 2) {
+ // If we have too many failing tests, it's very likely not flaky failures anymore so
+ // no need to retry.
+ break;
}
}
- if (tests_queue.length > 0) {
- await Promise.all(tests_queue);
- }
+
status_bar.finish();
+ Array.prototype.push.apply(results.failed, new_results.failed);
+ Array.prototype.push.apply(results.errored, new_results.errored);
+
// We don't need this listener anymore.
process.removeListener("exit", exitHandling);
});
}
- if (failed) {
+ if (results.failed.length > 0 || results.errored.length > 0) {
process.exit(1);
}
}
extern crate rustc_session;
extern crate rustc_span;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
rewrite_unary_prefix(context, prefix, &*mt.ty, shape)
}
- ast::TyKind::Rptr(ref lifetime, ref mt) => {
+ ast::TyKind::Ref(ref lifetime, ref mt) => {
let mut_str = format_mutability(mt.mutbl);
let mut_len = mut_str.len();
let mut result = String::with_capacity(128);
) -> bool {
match ty.kind {
ast::TyKind::Tup(..) => context.use_block_indent() && len == 1,
- ast::TyKind::Rptr(_, ref mutty) | ast::TyKind::Ptr(ref mutty) => {
+ ast::TyKind::Ref(_, ref mutty) | ast::TyKind::Ptr(ref mutty) => {
can_be_overflowed_type(context, &*mutty.ty, len)
}
_ => false,
category,
span,
&format!("`{}`", name),
+ "function",
),
(
ref name,
lazy_static = "1"
walkdir = "2"
ignore = "0.4.18"
+semver = "1.0.14"
+termcolor = "1.1.3"
[[bin]]
name = "rust-tidy"
("im-rc", "MPL-2.0+"), // cargo
("sized-chunks", "MPL-2.0+"), // cargo via im-rc
("bitmaps", "MPL-2.0+"), // cargo via im-rc
+ ("fiat-crypto", "MIT OR Apache-2.0 OR BSD-1-Clause"), // cargo via pasetors
+ ("subtle", "BSD-3-Clause"), // cargo via pasetors
("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot
("snap", "BSD-3-Clause"), // rustc
("fluent-langneg", "Apache-2.0"), // rustc (fluent translations)
"autocfg",
"bitflags",
"block-buffer",
+ "bumpalo", // Included in Cargo's dep graph but only activated on wasm32-*-unknown.
"cc",
"cfg-if",
"chalk-derive",
"itertools",
"itoa",
"jobserver",
+ "js-sys", // Included in Cargo's dep graph but only activated on wasm32-*-unknown.
"lazy_static",
"libc",
"libloading",
"rand",
"rand_chacha",
"rand_core",
- "rand_hc",
"rand_xorshift",
"rand_xoshiro",
"redox_syscall",
"stable_deref_trait",
"stacker",
"static_assertions",
+ "subtle", // dependency of cargo (via pasetors)
"syn",
"synstructure",
"tempfile",
"valuable",
"version_check",
"wasi",
+ // vvv Included in Cargo's dep graph but only activated on wasm32-*-unknown.
+ "wasm-bindgen",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-macro-support",
+ "wasm-bindgen-shared",
+ // ^^^ Included in Cargo's dep graph but only activated on wasm32-*-unknown.
"winapi",
"winapi-i686-pc-windows-gnu",
"winapi-util",
--- /dev/null
+//! Tidy check to ensure error codes are properly documented and tested.
+//!
+//! Overview of check:
+//!
+//! 1. We create a list of error codes used by the compiler. Error codes are extracted from `compiler/rustc_error_codes/src/error_codes.rs`.
+//!
+//! 2. We check that the error code has a long-form explanation in `compiler/rustc_error_codes/src/error_codes/`.
+//! - The explanation is expected to contain a `doctest` that fails with the correct error code. (`EXEMPT_FROM_DOCTEST` *currently* bypasses this check)
+//! - Note that other stylistic conventions for markdown files are checked in the `style.rs` tidy check.
+//!
+//! 3. We check that the error code has a UI test in `src/test/ui/error-codes/`.
+//! - We ensure that there is both a `Exxxx.rs` file and a corresponding `Exxxx.stderr` file.
+//! - We also ensure that the error code is used in the tests.
+//! - *Currently*, it is possible to opt-out of this check with the `EXEMPTED_FROM_TEST` constant.
+//!
+//! 4. We check that the error code is actually emitted by the compiler.
+//! - This is done by searching `compiler/` with a regex.
+
+use std::{ffi::OsStr, fs, path::Path};
+
+use regex::Regex;
+
+use crate::walk::{filter_dirs, walk, walk_many};
+
+const ERROR_CODES_PATH: &str = "compiler/rustc_error_codes/src/error_codes.rs";
+const ERROR_DOCS_PATH: &str = "compiler/rustc_error_codes/src/error_codes/";
+const ERROR_TESTS_PATH: &str = "src/test/ui/error-codes/";
+
+// Error codes that (for some reason) can't have a doctest in their explanation. Error codes are still expected to provide a code example, even if untested.
+const IGNORE_DOCTEST_CHECK: &[&str] =
+ &["E0208", "E0464", "E0570", "E0601", "E0602", "E0640", "E0717"];
+
+// Error codes that don't yet have a UI test. This list will eventually be removed.
+const IGNORE_UI_TEST_CHECK: &[&str] = &[
+ "E0461", "E0465", "E0476", "E0490", "E0514", "E0523", "E0554", "E0640", "E0717", "E0729",
+ "E0789",
+];
+
+macro_rules! verbose_print {
+ ($verbose:expr, $($fmt:tt)*) => {
+ if $verbose {
+ println!("{}", format_args!($($fmt)*));
+ }
+ };
+}
+
+pub fn check(root_path: &Path, search_paths: &[&Path], verbose: bool, bad: &mut bool) {
+ let mut errors = Vec::new();
+
+ // Stage 1: create list
+ let error_codes = extract_error_codes(root_path, &mut errors, verbose);
+ println!("Found {} error codes", error_codes.len());
+ println!("Highest error code: `{}`", error_codes.iter().max().unwrap());
+
+ // Stage 2: check list has docs
+ let no_longer_emitted = check_error_codes_docs(root_path, &error_codes, &mut errors, verbose);
+
+ // Stage 3: check list has UI tests
+ check_error_codes_tests(root_path, &error_codes, &mut errors, verbose, &no_longer_emitted);
+
+ // Stage 4: check list is emitted by compiler
+ check_error_codes_used(search_paths, &error_codes, &mut errors, &no_longer_emitted, verbose);
+
+ // Print any errors.
+ for error in errors {
+ tidy_error!(bad, "{}", error);
+ }
+}
+
+/// Stage 1: Parses a list of error codes from `error_codes.rs`.
+fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>, verbose: bool) -> Vec<String> {
+ let path = root_path.join(Path::new(ERROR_CODES_PATH));
+ let file =
+ fs::read_to_string(&path).unwrap_or_else(|e| panic!("failed to read `{path:?}`: {e}"));
+
+ let mut error_codes = Vec::new();
+ let mut reached_undocumented_codes = false;
+
+ for line in file.lines() {
+ let line = line.trim();
+
+ if !reached_undocumented_codes && line.starts_with('E') {
+ let split_line = line.split_once(':');
+
+ // Extract the error code from the line, emitting a fatal error if it is not in a correct format.
+ let err_code = if let Some(err_code) = split_line {
+ err_code.0.to_owned()
+ } else {
+ errors.push(format!(
+ "Expected a line with the format `Exxxx: include_str!(\"..\")`, but got \"{}\" \
+ without a `:` delimiter",
+ line,
+ ));
+ continue;
+ };
+
+ // If this is a duplicate of another error code, emit a fatal error.
+ if error_codes.contains(&err_code) {
+ errors.push(format!("Found duplicate error code: `{}`", err_code));
+ continue;
+ }
+
+ // Ensure that the line references the correct markdown file.
+ let expected_filename = format!(" include_str!(\"./error_codes/{}.md\"),", err_code);
+ if expected_filename != split_line.unwrap().1 {
+ errors.push(format!(
+ "Error code `{}` expected to reference docs with `{}` but instead found `{}` in \
+ `compiler/rustc_error_codes/src/error_codes.rs`",
+ err_code,
+ expected_filename,
+ split_line.unwrap().1,
+ ));
+ continue;
+ }
+
+ error_codes.push(err_code);
+ } else if reached_undocumented_codes && line.starts_with('E') {
+ let err_code = match line.split_once(',') {
+ None => line,
+ Some((err_code, _)) => err_code,
+ }
+ .to_string();
+
+ verbose_print!(verbose, "warning: Error code `{}` is undocumented.", err_code);
+
+ if error_codes.contains(&err_code) {
+ errors.push(format!("Found duplicate error code: `{}`", err_code));
+ }
+
+ error_codes.push(err_code);
+ } else if line == ";" {
+ // Once we reach the undocumented error codes, adapt to different syntax.
+ reached_undocumented_codes = true;
+ }
+ }
+
+ error_codes
+}
+
+/// Stage 2: Checks that long-form error code explanations exist and have doctests.
+fn check_error_codes_docs(
+ root_path: &Path,
+ error_codes: &[String],
+ errors: &mut Vec<String>,
+ verbose: bool,
+) -> Vec<String> {
+ let docs_path = root_path.join(Path::new(ERROR_DOCS_PATH));
+
+ let mut no_longer_emitted_codes = Vec::new();
+
+ walk(&docs_path, &mut |_| false, &mut |entry, contents| {
+ let path = entry.path();
+
+ // Error if the file isn't markdown.
+ if path.extension() != Some(OsStr::new("md")) {
+ errors.push(format!(
+ "Found unexpected non-markdown file in error code docs directory: {}",
+ path.display()
+ ));
+ return;
+ }
+
+ // Make sure that the file is referenced in `error_codes.rs`
+ let filename = path.file_name().unwrap().to_str().unwrap().split_once('.');
+ let err_code = filename.unwrap().0; // `unwrap` is ok because we know the filename is in the correct format.
+
+ if error_codes.iter().all(|e| e != err_code) {
+ errors.push(format!(
+ "Found valid file `{}` in error code docs directory without corresponding \
+ entry in `error_code.rs`",
+ path.display()
+ ));
+ return;
+ }
+
+ let (found_code_example, found_proper_doctest, emit_ignore_warning, no_longer_emitted) =
+ check_explanation_has_doctest(&contents, &err_code);
+
+ if emit_ignore_warning {
+ verbose_print!(
+ verbose,
+ "warning: Error code `{err_code}` uses the ignore header. This should not be used, add the error code to the \
+ `IGNORE_DOCTEST_CHECK` constant instead."
+ );
+ }
+
+ if no_longer_emitted {
+ no_longer_emitted_codes.push(err_code.to_owned());
+ }
+
+ if !found_code_example {
+ verbose_print!(
+ verbose,
+ "warning: Error code `{err_code}` doesn't have a code example, all error codes are expected to have one \
+ (even if untested)."
+ );
+ return;
+ }
+
+ let test_ignored = IGNORE_DOCTEST_CHECK.contains(&&err_code);
+
+ // Check that the explanation has a doctest, and if it shouldn't, that it doesn't
+ if !found_proper_doctest && !test_ignored {
+ errors.push(format!(
+ "`{}` doesn't use its own error code in compile_fail example",
+ path.display(),
+ ));
+ } else if found_proper_doctest && test_ignored {
+ errors.push(format!(
+ "`{}` has a compile_fail doctest with its own error code, it shouldn't \
+ be listed in `IGNORE_DOCTEST_CHECK`",
+ path.display(),
+ ));
+ }
+ });
+
+ no_longer_emitted_codes
+}
+
+/// This function returns a tuple indicating whether the provided explanation:
+/// a) has a code example, tested or not.
+/// b) has a valid doctest
+fn check_explanation_has_doctest(explanation: &str, err_code: &str) -> (bool, bool, bool, bool) {
+ let mut found_code_example = false;
+ let mut found_proper_doctest = false;
+
+ let mut emit_ignore_warning = false;
+ let mut no_longer_emitted = false;
+
+ for line in explanation.lines() {
+ let line = line.trim();
+
+ if line.starts_with("```") {
+ found_code_example = true;
+
+ // Check for the `rustdoc` doctest headers.
+ if line.contains("compile_fail") && line.contains(err_code) {
+ found_proper_doctest = true;
+ }
+
+ if line.contains("ignore") {
+ emit_ignore_warning = true;
+ found_proper_doctest = true;
+ }
+ } else if line
+ .starts_with("#### Note: this error code is no longer emitted by the compiler")
+ {
+ no_longer_emitted = true;
+ found_code_example = true;
+ found_proper_doctest = true;
+ }
+ }
+
+ (found_code_example, found_proper_doctest, emit_ignore_warning, no_longer_emitted)
+}
+
+// Stage 3: Checks that each error code has a UI test in the correct directory
+fn check_error_codes_tests(
+ root_path: &Path,
+ error_codes: &[String],
+ errors: &mut Vec<String>,
+ verbose: bool,
+ no_longer_emitted: &[String],
+) {
+ let tests_path = root_path.join(Path::new(ERROR_TESTS_PATH));
+
+ for code in error_codes {
+ let test_path = tests_path.join(format!("{}.stderr", code));
+
+ if !test_path.exists() && !IGNORE_UI_TEST_CHECK.contains(&code.as_str()) {
+ verbose_print!(
+ verbose,
+ "warning: Error code `{code}` needs to have at least one UI test in the `src/test/ui/error-codes/` directory`!"
+ );
+ continue;
+ }
+ if IGNORE_UI_TEST_CHECK.contains(&code.as_str()) {
+ if test_path.exists() {
+ errors.push(format!(
+ "Error code `{code}` has a UI test in `src/test/ui/error-codes/{code}.rs`, it shouldn't be listed in `EXEMPTED_FROM_TEST`!"
+ ));
+ }
+ continue;
+ }
+
+ let file = match fs::read_to_string(&test_path) {
+ Ok(file) => file,
+ Err(err) => {
+ verbose_print!(
+ verbose,
+ "warning: Failed to read UI test file (`{}`) for `{code}` but the file exists. The test is assumed to work:\n{err}",
+ test_path.display()
+ );
+ continue;
+ }
+ };
+
+ if no_longer_emitted.contains(code) {
+ // UI tests *can't* contain error codes that are no longer emitted.
+ continue;
+ }
+
+ let mut found_code = false;
+
+ for line in file.lines() {
+ let s = line.trim();
+ // Assuming the line starts with `error[E`, we can substring the error code out.
+ if s.starts_with("error[E") {
+ if &s[6..11] == code {
+ found_code = true;
+ break;
+ }
+ };
+ }
+
+ if !found_code {
+ verbose_print!(
+ verbose,
+ "warning: Error code {code}`` has a UI test file, but doesn't contain its own error code!"
+ );
+ }
+ }
+}
+
+/// Stage 4: Search `compiler/` and ensure that every error code is actually used by the compiler and that no undocumented error codes exist.
+fn check_error_codes_used(
+ search_paths: &[&Path],
+ error_codes: &[String],
+ errors: &mut Vec<String>,
+ no_longer_emitted: &[String],
+ verbose: bool,
+) {
+ // We want error codes which match the following cases:
+ //
+ // * foo(a, E0111, a)
+ // * foo(a, E0111)
+ // * foo(E0111, a)
+ // * #[error = "E0111"]
+ let regex = Regex::new(r#"[(,"\s](E\d{4})[,)"]"#).unwrap();
+
+ let mut found_codes = Vec::new();
+
+ walk_many(search_paths, &mut filter_dirs, &mut |entry, contents| {
+ let path = entry.path();
+
+ // Return early if we aren't looking at a source file.
+ if path.extension() != Some(OsStr::new("rs")) {
+ return;
+ }
+
+ for line in contents.lines() {
+ // We want to avoid parsing error codes in comments.
+ if line.trim_start().starts_with("//") {
+ continue;
+ }
+
+ for cap in regex.captures_iter(line) {
+ if let Some(error_code) = cap.get(1) {
+ let error_code = error_code.as_str().to_owned();
+
+ if !error_codes.contains(&error_code) {
+ // This error code isn't properly defined, we must error.
+ errors.push(format!("Error code `{}` is used in the compiler but not defined and documented in `compiler/rustc_error_codes/src/error_codes.rs`.", error_code));
+ continue;
+ }
+
+ // This error code can now be marked as used.
+ found_codes.push(error_code);
+ }
+ }
+ }
+ });
+
+ for code in error_codes {
+ if !found_codes.contains(code) && !no_longer_emitted.contains(code) {
+ errors.push(format!("Error code `{code}` exists, but is not emitted by the compiler!"))
+ }
+
+ if found_codes.contains(code) && no_longer_emitted.contains(code) {
+ verbose_print!(
+ verbose,
+ "warning: Error code `{code}` is used when it's marked as \"no longer emitted\""
+ );
+ }
+ }
+}
+++ /dev/null
-//! Checks that all error codes have at least one test to prevent having error
-//! codes that are silently not thrown by the compiler anymore.
-
-use crate::walk::{filter_dirs, walk};
-use std::collections::{HashMap, HashSet};
-use std::ffi::OsStr;
-use std::fs::read_to_string;
-use std::path::Path;
-
-use regex::Regex;
-
-// A few of those error codes can't be tested but all the others can and *should* be tested!
-const EXEMPTED_FROM_TEST: &[&str] = &[
- "E0313", "E0461", "E0465", "E0476", "E0490", "E0514", "E0519", "E0523", "E0554", "E0640",
- "E0717", "E0729", "E0789",
-];
-
-// Some error codes don't have any tests apparently...
-const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0464", "E0570", "E0601", "E0602", "E0729"];
-
-// If the file path contains any of these, we don't want to try to extract error codes from it.
-//
-// We need to declare each path in the windows version (with backslash).
-const PATHS_TO_IGNORE_FOR_EXTRACTION: &[&str] =
- &["src/test/", "src\\test\\", "src/doc/", "src\\doc\\", "src/tools/", "src\\tools\\"];
-
-#[derive(Default, Debug)]
-struct ErrorCodeStatus {
- has_test: bool,
- has_explanation: bool,
- is_used: bool,
-}
-
-fn check_error_code_explanation(
- f: &str,
- error_codes: &mut HashMap<String, ErrorCodeStatus>,
- err_code: String,
-) -> bool {
- let mut invalid_compile_fail_format = false;
- let mut found_error_code = false;
-
- for line in f.lines() {
- let s = line.trim();
- if s.starts_with("```") {
- if s.contains("compile_fail") && s.contains('E') {
- if !found_error_code {
- error_codes.get_mut(&err_code).map(|x| x.has_test = true);
- found_error_code = true;
- }
- } else if s.contains("compile-fail") {
- invalid_compile_fail_format = true;
- }
- } else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
- if !found_error_code {
- error_codes.get_mut(&err_code).map(|x| x.has_test = true);
- found_error_code = true;
- }
- }
- }
- invalid_compile_fail_format
-}
-
-fn check_if_error_code_is_test_in_explanation(f: &str, err_code: &str) -> bool {
- let mut ignore_found = false;
-
- for line in f.lines() {
- let s = line.trim();
- if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
- return true;
- }
- if s.starts_with("```") {
- if s.contains("compile_fail") && s.contains(err_code) {
- return true;
- } else if s.contains("ignore") {
- // It's very likely that we can't actually make it fail compilation...
- ignore_found = true;
- }
- }
- }
- ignore_found
-}
-
-macro_rules! some_or_continue {
- ($e:expr) => {
- match $e {
- Some(e) => e,
- None => continue,
- }
- };
-}
-
-fn extract_error_codes(
- f: &str,
- error_codes: &mut HashMap<String, ErrorCodeStatus>,
- path: &Path,
- errors: &mut Vec<String>,
-) {
- let mut reached_no_explanation = false;
-
- for line in f.lines() {
- let s = line.trim();
- if !reached_no_explanation && s.starts_with('E') && s.contains("include_str!(\"") {
- let err_code = s
- .split_once(':')
- .expect(
- format!(
- "Expected a line with the format `E0xxx: include_str!(\"..\")`, but got {} \
- without a `:` delimiter",
- s,
- )
- .as_str(),
- )
- .0
- .to_owned();
- error_codes.entry(err_code.clone()).or_default().has_explanation = true;
-
- // Now we extract the tests from the markdown file!
- let md_file_name = match s.split_once("include_str!(\"") {
- None => continue,
- Some((_, md)) => match md.split_once("\")") {
- None => continue,
- Some((file_name, _)) => file_name,
- },
- };
- let path = some_or_continue!(path.parent())
- .join(md_file_name)
- .canonicalize()
- .expect("failed to canonicalize error explanation file path");
- match read_to_string(&path) {
- Ok(content) => {
- let has_test = check_if_error_code_is_test_in_explanation(&content, &err_code);
- if !has_test && !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
- errors.push(format!(
- "`{}` doesn't use its own error code in compile_fail example",
- path.display(),
- ));
- } else if has_test && IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
- errors.push(format!(
- "`{}` has a compile_fail example with its own error code, it shouldn't \
- be listed in IGNORE_EXPLANATION_CHECK!",
- path.display(),
- ));
- }
- if check_error_code_explanation(&content, error_codes, err_code) {
- errors.push(format!(
- "`{}` uses invalid tag `compile-fail` instead of `compile_fail`",
- path.display(),
- ));
- }
- }
- Err(e) => {
- eprintln!("Couldn't read `{}`: {}", path.display(), e);
- }
- }
- } else if reached_no_explanation && s.starts_with('E') {
- let err_code = match s.split_once(',') {
- None => s,
- Some((err_code, _)) => err_code,
- }
- .to_string();
- if !error_codes.contains_key(&err_code) {
- // this check should *never* fail!
- error_codes.insert(err_code, ErrorCodeStatus::default());
- }
- } else if s == ";" {
- reached_no_explanation = true;
- }
- }
-}
-
-fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap<String, ErrorCodeStatus>) {
- for line in f.lines() {
- let s = line.trim();
- if s.starts_with("error[E") || s.starts_with("warning[E") {
- let err_code = match s.split_once(']') {
- None => continue,
- Some((err_code, _)) => match err_code.split_once('[') {
- None => continue,
- Some((_, err_code)) => err_code,
- },
- };
- error_codes.entry(err_code.to_owned()).or_default().has_test = true;
- }
- }
-}
-
-fn extract_error_codes_from_source(
- f: &str,
- error_codes: &mut HashMap<String, ErrorCodeStatus>,
- regex: &Regex,
-) {
- for line in f.lines() {
- if line.trim_start().starts_with("//") {
- continue;
- }
- for cap in regex.captures_iter(line) {
- if let Some(error_code) = cap.get(1) {
- error_codes.entry(error_code.as_str().to_owned()).or_default().is_used = true;
- }
- }
- }
-}
-
-pub fn check(paths: &[&Path], bad: &mut bool) {
- let mut errors = Vec::new();
- let mut found_explanations = 0;
- let mut found_tests = 0;
- let mut error_codes: HashMap<String, ErrorCodeStatus> = HashMap::new();
- let mut explanations: HashSet<String> = HashSet::new();
- // We want error codes which match the following cases:
- //
- // * foo(a, E0111, a)
- // * foo(a, E0111)
- // * foo(E0111, a)
- // * #[error = "E0111"]
- let regex = Regex::new(r#"[(,"\s](E\d{4})[,)"]"#).unwrap();
-
- println!("Checking which error codes lack tests...");
-
- for path in paths {
- walk(path, &mut filter_dirs, &mut |entry, contents| {
- let file_name = entry.file_name();
- let entry_path = entry.path();
-
- if file_name == "error_codes.rs" {
- extract_error_codes(contents, &mut error_codes, entry.path(), &mut errors);
- found_explanations += 1;
- } else if entry_path.extension() == Some(OsStr::new("stderr")) {
- extract_error_codes_from_tests(contents, &mut error_codes);
- found_tests += 1;
- } else if entry_path.extension() == Some(OsStr::new("rs")) {
- let path = entry.path().to_string_lossy();
- if PATHS_TO_IGNORE_FOR_EXTRACTION.iter().all(|c| !path.contains(c)) {
- extract_error_codes_from_source(contents, &mut error_codes, ®ex);
- }
- } else if entry_path
- .parent()
- .and_then(|p| p.file_name())
- .map(|p| p == "error_codes")
- .unwrap_or(false)
- && entry_path.extension() == Some(OsStr::new("md"))
- {
- explanations.insert(file_name.to_str().unwrap().replace(".md", ""));
- }
- });
- }
- if found_explanations == 0 {
- eprintln!("No error code explanation was tested!");
- *bad = true;
- }
- if found_tests == 0 {
- eprintln!("No error code was found in compilation errors!");
- *bad = true;
- }
- if explanations.is_empty() {
- eprintln!("No error code explanation was found!");
- *bad = true;
- }
- if errors.is_empty() {
- println!("Found {} error codes", error_codes.len());
-
- for (err_code, error_status) in &error_codes {
- if !error_status.has_test && !EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
- errors.push(format!("Error code {err_code} needs to have at least one UI test!"));
- } else if error_status.has_test && EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
- errors.push(format!(
- "Error code {} has a UI test, it shouldn't be listed into EXEMPTED_FROM_TEST!",
- err_code
- ));
- }
- if !error_status.is_used && !error_status.has_explanation {
- errors.push(format!(
- "Error code {} isn't used and doesn't have an error explanation, it should be \
- commented in error_codes.rs file",
- err_code
- ));
- }
- }
- }
- if errors.is_empty() {
- // Checking if local constants need to be cleaned.
- for err_code in EXEMPTED_FROM_TEST {
- match error_codes.get(err_code.to_owned()) {
- Some(status) => {
- if status.has_test {
- errors.push(format!(
- "{} error code has a test and therefore should be \
- removed from the `EXEMPTED_FROM_TEST` constant",
- err_code
- ));
- }
- }
- None => errors.push(format!(
- "{} error code isn't used anymore and therefore should be removed \
- from `EXEMPTED_FROM_TEST` constant",
- err_code
- )),
- }
- }
- }
- if errors.is_empty() {
- for explanation in explanations {
- if !error_codes.contains_key(&explanation) {
- errors.push(format!(
- "{} error code explanation should be listed in `error_codes.rs`",
- explanation
- ));
- }
- }
- }
- errors.sort();
- for err in &errors {
- eprintln!("{err}");
- }
- println!("Found {} error(s) in error codes", errors.len());
- if !errors.is_empty() {
- *bad = true;
- }
- println!("Done!");
-}
+++ /dev/null
-//! Tidy check to verify the validity of long error diagnostic codes.
-//!
-//! This ensures that error codes are used at most once and also prints out some
-//! statistics about the error codes.
-
-use crate::walk::{filter_dirs, walk};
-use std::collections::HashMap;
-use std::path::Path;
-
-pub fn check(path: &Path, bad: &mut bool) {
- let mut map: HashMap<_, Vec<_>> = HashMap::new();
- walk(
- path,
- &mut |path| filter_dirs(path) || path.ends_with("src/test"),
- &mut |entry, contents| {
- let file = entry.path();
- let filename = file.file_name().unwrap().to_string_lossy();
- if filename != "error_codes.rs" {
- return;
- }
-
- // In the `register_long_diagnostics!` macro, entries look like this:
- //
- // ```
- // EXXXX: r##"
- // <Long diagnostic message>
- // "##,
- // ```
- //
- // and these long messages often have error codes themselves inside
- // them, but we don't want to report duplicates in these cases. This
- // variable keeps track of whether we're currently inside one of these
- // long diagnostic messages.
- let mut inside_long_diag = false;
- for (num, line) in contents.lines().enumerate() {
- if inside_long_diag {
- inside_long_diag = !line.contains("\"##");
- continue;
- }
-
- let mut search = line;
- while let Some(i) = search.find('E') {
- search = &search[i + 1..];
- let code = if search.len() > 4 { search[..4].parse::<u32>() } else { continue };
- let code = match code {
- Ok(n) => n,
- Err(..) => continue,
- };
- map.entry(code).or_default().push((file.to_owned(), num + 1, line.to_owned()));
- break;
- }
-
- inside_long_diag = line.contains("r##\"");
- }
- },
- );
-
- let mut max = 0;
- for (&code, entries) in map.iter() {
- if code > max {
- max = code;
- }
- if entries.len() == 1 {
- continue;
- }
-
- tidy_error!(bad, "duplicate error code: {}", code);
- for &(ref file, line_num, ref line) in entries.iter() {
- tidy_error!(bad, "{}:{}: {}", file.display(), line_num, line);
- }
- }
-
- if !*bad {
- println!("* {} error codes", map.len());
- println!("* highest error code: E{:04}", max);
- }
-}
#[test]
fn test_try_from_single() {
- assert_eq!("1.32.0".parse(), Ok(Version { parts: [1, 32, 0] }));
- assert_eq!("1.0.0".parse(), Ok(Version { parts: [1, 0, 0] }));
+ assert_eq!("1.32.0".parse(), Ok(Version::Explicit { parts: [1, 32, 0] }));
+ assert_eq!("1.0.0".parse(), Ok(Version::Explicit { parts: [1, 0, 0] }));
}
#[test]
//! This library contains the tidy lints and exposes it
//! to be used by tools.
+use std::fmt::Display;
+
+use termcolor::WriteColor;
+
/// A helper macro to `unwrap` a result except also print out details like:
///
/// * The expression that failed
}
macro_rules! tidy_error {
- ($bad:expr, $fmt:expr) => ({
- *$bad = true;
- eprint!("tidy error: ");
- eprintln!($fmt);
- });
- ($bad:expr, $fmt:expr, $($arg:tt)*) => ({
- *$bad = true;
- eprint!("tidy error: ");
- eprintln!($fmt, $($arg)*);
+ ($bad:expr, $($fmt:tt)*) => ({
+ $crate::tidy_error($bad, format_args!($($fmt)*)).expect("failed to output error");
});
}
+fn tidy_error(bad: &mut bool, args: impl Display) -> std::io::Result<()> {
+ use std::io::Write;
+ use termcolor::{Color, ColorChoice, ColorSpec, StandardStream};
+
+ *bad = true;
+
+ let mut stderr = StandardStream::stdout(ColorChoice::Auto);
+ stderr.set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
+
+ write!(&mut stderr, "tidy error")?;
+ stderr.set_color(&ColorSpec::new())?;
+
+ writeln!(&mut stderr, ": {args}")?;
+ Ok(())
+}
+
pub mod alphabetical;
pub mod bins;
pub mod debug_artifacts;
pub mod deps;
pub mod edition;
-pub mod error_codes_check;
-pub mod errors;
+pub mod error_codes;
pub mod extdeps;
pub mod features;
pub mod mir_opt_tests;
pub mod unit_tests;
pub mod unstable_book;
pub mod walk;
+pub mod x_version;
let src_path = root_path.join("src");
let library_path = root_path.join("library");
let compiler_path = root_path.join("compiler");
+ let librustdoc_path = src_path.join("librustdoc");
let args: Vec<String> = env::args().skip(1).collect();
let handle = s.spawn(|| {
let mut flag = false;
- $p::check($($args),* , &mut flag);
+ $p::check($($args, )* &mut flag);
if (flag) {
bad.store(true, Ordering::Relaxed);
}
check!(mir_opt_tests, &src_path, bless);
// Checks that only make sense for the compiler.
- check!(errors, &compiler_path);
- check!(error_codes_check, &[&src_path, &compiler_path]);
+ check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
// Checks that only make sense for the std libs.
check!(pal, &library_path);
check!(alphabetical, &compiler_path);
check!(alphabetical, &library_path);
+ check!(x_version, &root_path, &cargo);
+
let collected = {
drain_handles(&mut handles);
//!
//! A number of these checks can be opted-out of with various directives of the form:
//! `// ignore-tidy-CHECK-NAME`.
+// ignore-tidy-dbg
use crate::walk::{filter_dirs, walk};
use regex::{Regex, RegexSet};
/// displayed on the console with --example.
const ERROR_CODE_COLS: usize = 80;
const COLS: usize = 100;
+const GOML_COLS: usize = 120;
const LINES: usize = 3000;
3735927486, 3735932941, 4027431614, 4276992702,
];
+const INTERNAL_COMPILER_DOCS_LINE: &str = "#### This error code is internal to the compiler and will not be emitted with normal Rust code.";
+
/// Parser states for `line_is_url`.
#[derive(Clone, Copy, PartialEq)]
#[allow(non_camel_case_types)]
"ftl" => true,
// non-error code markdown is allowed to be any length
"md" if !is_error_code => true,
+ // HACK(Ezrashaw): there is no way to split a markdown header over multiple lines
+ "md" if line == INTERNAL_COMPILER_DOCS_LINE => true,
_ => line_is_url(is_error_code, max_columns, line) || should_ignore(line),
}
}
walk(path, &mut skip, &mut |entry, contents| {
let file = entry.path();
let filename = file.file_name().unwrap().to_string_lossy();
- let extensions = [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h", ".md", ".css", ".ftl"];
+ let extensions =
+ [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h", ".md", ".css", ".ftl", ".goml"];
if extensions.iter().all(|e| !filename.ends_with(e)) || filename.starts_with(".#") {
return;
}
let extension = file.extension().unwrap().to_string_lossy();
let is_error_code = extension == "md" && is_in(file, "src", "error_codes");
+ let is_goml_code = extension == "goml";
- let max_columns = if is_error_code { ERROR_CODE_COLS } else { COLS };
+ let max_columns = if is_error_code {
+ ERROR_CODE_COLS
+ } else if is_goml_code {
+ GOML_COLS
+ } else {
+ COLS
+ };
let can_contain = contents.contains("// ignore-tidy-")
|| contents.contains("# ignore-tidy-")
let mut skip_leading_newlines =
contains_ignore_directive(can_contain, &contents, "leading-newlines");
let mut skip_copyright = contains_ignore_directive(can_contain, &contents, "copyright");
+ let mut skip_dbg = contains_ignore_directive(can_contain, &contents, "dbg");
let mut leading_new_lines = false;
let mut trailing_new_lines = 0;
let mut lines = 0;
let mut err = |msg: &str| {
tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
};
+
+ if trimmed.contains("dbg!")
+ && !trimmed.starts_with("//")
+ && !file
+ .ancestors()
+ .any(|a| a.ends_with("src/test") || a.ends_with("library/alloc/tests"))
+ && filename != "tests.rs"
+ {
+ suppressible_tidy_err!(
+ err,
+ skip_dbg,
+ "`dbg!` macro is intended as a debugging tool. It should not be in version control."
+ )
+ }
+
if !under_rustfmt
&& line.chars().count() > max_columns
&& !long_line_is_ok(&extension, is_error_code, max_columns, line)
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
const ROOT_ENTRY_LIMIT: usize = 939;
-const ISSUES_ENTRY_LIMIT: usize = 2020;
+const ISSUES_ENTRY_LIMIT: usize = 1998;
fn check_entries(path: &Path, bad: &mut bool) {
for dir in Walk::new(&path.join("test/ui")) {
--- /dev/null
+use semver::Version;
+use std::io::ErrorKind;
+use std::path::Path;
+use std::process::{Command, Stdio};
+
+pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
+ let result = Command::new("x").arg("--wrapper-version").stdout(Stdio::piped()).spawn();
+ // This runs the command inside a temporary directory.
+ // This allows us to compare output of result to see if `--wrapper-version` is not a recognized argument to x.
+ let temp_result = Command::new("x")
+ .arg("--wrapper-version")
+ .current_dir(std::env::temp_dir())
+ .stdout(Stdio::piped())
+ .spawn();
+
+ let (child, temp_child) = match (result, temp_result) {
+ (Ok(child), Ok(temp_child)) => (child, temp_child),
+ (Err(e), _) | (_, Err(e)) => match e.kind() {
+ ErrorKind::NotFound => return,
+ _ => return tidy_error!(bad, "failed to run `x`: {}", e),
+ },
+ };
+
+ let output = child.wait_with_output().unwrap();
+ let temp_output = temp_child.wait_with_output().unwrap();
+
+ if output != temp_output {
+ return tidy_error!(
+ bad,
+ "Current version of x does not support the `--wrapper-version` argument\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+ );
+ }
+
+ if output.status.success() {
+ let version = String::from_utf8_lossy(&output.stdout);
+ let version = Version::parse(version.trim_end()).unwrap();
+
+ if let Some(expected) = get_x_wrapper_version(root, cargo) {
+ if version < expected {
+ return tidy_error!(
+ bad,
+ "Current version of x is {version}, but the latest version is {expected}\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+ );
+ }
+ } else {
+ return tidy_error!(
+ bad,
+ "Unable to parse the latest version of `x` at `src/tools/x/Cargo.toml`"
+ );
+ }
+ } else {
+ return tidy_error!(bad, "failed to check version of `x`: {}", output.status);
+ }
+}
+
+// Parse latest version out of `x` Cargo.toml
+fn get_x_wrapper_version(root: &Path, cargo: &Path) -> Option<Version> {
+ let mut cmd = cargo_metadata::MetadataCommand::new();
+ cmd.cargo_path(cargo)
+ .manifest_path(root.join("src/tools/x/Cargo.toml"))
+ .no_deps()
+ .features(cargo_metadata::CargoOpt::AllFeatures);
+ let mut metadata = t!(cmd.exec());
+ metadata.packages.pop().map(|x| x.version)
+}
}
fn main() {
+ match env::args().skip(1).next().as_deref() {
+ Some("--wrapper-version") => {
+ let version = env!("CARGO_PKG_VERSION");
+ println!("{}", version);
+ return;
+ }
+ _ => {}
+ }
let current = match env::current_dir() {
Ok(dir) => dir,
Err(err) => {
"compiler-team-contributors",
]
libs = [
+ "@cuviper",
"@joshtriplett",
"@Mark-Simulacrum",
"@m-ou-se",
rustdoc = [
"@jsha",
"@GuillaumeGomez",
- "@CraftSpider",
"@notriddle",
]
docs = [
return Get-Command $app -ErrorAction SilentlyContinue -CommandType Application
}
+function Invoke-Application($application, $arguments) {
+ $process = Start-Process -NoNewWindow -PassThru $application $arguments
+ $process.WaitForExit()
+ Exit $process.ExitCode
+}
+
foreach ($python in "py", "python3", "python", "python2") {
# NOTE: this only tests that the command exists in PATH, not that it's actually
# executable. The latter is not possible in a portable way, see
# Use python3, not python2
$xpy_args = @("-3") + $xpy_args
}
- $process = Start-Process -NoNewWindow -Wait -PassThru $python $xpy_args
- Exit $process.ExitCode
+ Invoke-Application $python $xpy_args
}
}
$found = (Get-Application "python*" | Where-Object {$_.name -match '^python[2-3]\.[0-9]+(\.exe)?$'})
if (($null -ne $found) -and ($found.Length -ge 1)) {
$python = $found[0]
- $process = Start-Process -NoNewWindow -Wait -PassThru $python $xpy_args
- Exit $process.ExitCode
+ Invoke-Application $python $xpy_args
}
Write-Error "${PSCommandPath}: error: did not find python installed"