Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Léo Lanteri Thauvin <leseulartichaut@gmail.com> <38361244+LeSeulArtichaut@users.noreply.github.com>
Léo Testard <leo.testard@gmail.com>
+Lily Ballard <lily@ballards.net> <kevin@sb.org>
Lindsey Kuper <lindsey@composition.al> <lindsey@rockstargirl.org>
Lindsey Kuper <lindsey@composition.al> <lkuper@mozilla.com>
Luke Metz <luke.metz@students.olin.edu>
Nick Platt <platt.nicholas@gmail.com>
Nicole Mazzuca <npmazzuca@gmail.com>
Nif Ward <nif.ward@gmail.com>
-Nika Layzell <michael@thelayzells.com>
+Nika Layzell <nika@thelayzells.com> <michael@thelayzells.com>
Oliver Middleton <olliemail27@gmail.com> <ollie27@users.noreply.github.com>
Oliver Scherer <oliver.schneider@kit.edu> <git-spam-no-reply9815368754983@oli-obk.de>
Oliver Scherer <oliver.schneider@kit.edu> <git-spam9815368754983@oli-obk.de>
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
dependencies = [
"hermit-abi",
"libc",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"serde_json",
"time",
"toml",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
[[package]]
name = "bytes"
-version = "0.5.6"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
+checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
[[package]]
name = "bytesize"
"unicode-xid",
"url 2.2.2",
"walkdir",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
version = "0.1.0"
dependencies = [
"cargo-credential",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"jobserver",
"libc",
"log",
- "miow 0.3.7",
+ "miow",
"same-file",
"shell-escape",
"tempfile",
"walkdir",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"num-integer",
"num-traits",
"time",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
dependencies = [
"atty",
"lazy_static",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"glob",
"lazy_static",
"libc",
- "miow 0.3.7",
+ "miow",
"regex",
"rustfix 0.6.0",
"serde",
"tracing-subscriber",
"unified-diff",
"walkdir",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"lazy_static",
"libc",
"log",
- "miow 0.3.7",
+ "miow",
"regex",
"rustfix 0.5.1",
"serde",
"serde_json",
"tempfile",
"tester",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"commoncrypto",
"hex 0.3.2",
"openssl",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"openssl-sys",
"schannel",
"socket2",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"openssl-sys",
"pkg-config",
"vcpkg",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
dependencies = [
"libc",
"redox_users",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
dependencies = [
"libc",
"redox_users",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"cfg-if 1.0.0",
"libc",
"redox_syscall",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d79238883cf0307100b90aba4a755d8051a3182305dfe7f649a1e9dc0517006f"
-[[package]]
-name = "fuchsia-zircon"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
-dependencies = [
- "bitflags",
- "fuchsia-zircon-sys",
-]
-
-[[package]]
-name = "fuchsia-zircon-sys"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
-
[[package]]
name = "futf"
version = "0.1.4"
"futures-sink",
"futures-task",
"memchr",
- "pin-project-lite 0.2.4",
+ "pin-project-lite",
"pin-utils",
"proc-macro-hack",
"proc-macro-nested",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
dependencies = [
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"remove_dir_all",
"tar",
"walkdir",
- "winapi 0.3.9",
+ "winapi",
"xz2",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485"
-[[package]]
-name = "iovec"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
-dependencies = [
- "libc",
-]
-
[[package]]
name = "itertools"
version = "0.8.2"
[[package]]
name = "jsonrpc-client-transports"
-version = "17.0.0"
+version = "18.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15b6c6ad01c7354d60de493148c30ac8a82b759e22ae678c8705e9b8e0c566a4"
+checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a"
dependencies = [
"derive_more",
"futures 0.3.12",
[[package]]
name = "jsonrpc-core"
-version = "17.0.0"
+version = "18.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07569945133257ff557eb37b015497104cea61a2c9edaf126c1cbd6e8332397f"
+checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb"
dependencies = [
"futures 0.3.12",
+ "futures-executor",
+ "futures-util",
"log",
"serde",
"serde_derive",
[[package]]
name = "jsonrpc-core-client"
-version = "17.0.0"
+version = "18.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ac9d56dc729912796637c30f475bbf834594607b27740dfea6e5fa7ba40d1f1"
+checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0"
dependencies = [
"futures 0.3.12",
"jsonrpc-client-transports",
[[package]]
name = "jsonrpc-derive"
-version = "17.0.0"
+version = "18.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b68ba7e76e5c7796cfa4d2a30e83986550c34404c6d40551c902ca6f7bd4a137"
+checksum = "5b939a78fa820cdfcb7ee7484466746a7377760970f6f9c6fe19f9edcc8a38d2"
dependencies = [
"proc-macro-crate",
"proc-macro2",
[[package]]
name = "jsonrpc-ipc-server"
-version = "17.0.1"
+version = "18.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c4cd89e5ea7e7f0884e828fc35bb83591a371b92439675eae28efa66c24a97"
+checksum = "382bb0206323ca7cda3dcd7e245cea86d37d02457a02a975e3378fb149a48845"
dependencies = [
"futures 0.3.12",
"jsonrpc-core",
[[package]]
name = "jsonrpc-pubsub"
-version = "17.0.0"
+version = "18.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c48dbebce7a9c88ab272a4db7d6478aa4c6d9596e6c086366e89efc4e9ed89e"
+checksum = "240f87695e6c6f62fb37f05c02c04953cf68d6408b8c1c89de85c7a0125b1011"
dependencies = [
"futures 0.3.12",
"jsonrpc-core",
[[package]]
name = "jsonrpc-server-utils"
-version = "17.0.0"
+version = "18.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4207cce738bf713a82525065b750a008f28351324f438f56b33d698ada95bb4"
+checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4"
dependencies = [
"bytes",
"futures 0.3.12",
"lazy_static",
"log",
"tokio",
+ "tokio-stream",
"tokio-util",
"unicase",
]
-[[package]]
-name = "kernel32-sys"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
-dependencies = [
- "winapi 0.2.8",
- "winapi-build",
-]
-
[[package]]
name = "lazy_static"
version = "1.4.0"
[[package]]
name = "lsp-codec"
-version = "0.2.0"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d33c83e320715a1e7e0466a53db2238becb2e5c446deff5506abc81aeacc5ec4"
+checksum = "aa939d0b62476a5a19fb7fcb423a5c6ce8c7e09b851d37531e2fe3e0e6d9d257"
dependencies = [
"bytes",
"serde_json",
[[package]]
name = "mio"
-version = "0.6.22"
+version = "0.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
+checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16"
dependencies = [
- "cfg-if 0.1.10",
- "fuchsia-zircon",
- "fuchsia-zircon-sys",
- "iovec",
- "kernel32-sys",
"libc",
"log",
- "miow 0.2.2",
- "net2",
- "slab",
- "winapi 0.2.8",
-]
-
-[[package]]
-name = "mio-named-pipes"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656"
-dependencies = [
- "log",
- "mio",
- "miow 0.3.7",
- "winapi 0.3.9",
-]
-
-[[package]]
-name = "mio-uds"
-version = "0.6.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
-dependencies = [
- "iovec",
- "libc",
- "mio",
-]
-
-[[package]]
-name = "miow"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
-dependencies = [
- "kernel32-sys",
- "net2",
- "winapi 0.2.8",
- "ws2_32-sys",
+ "miow",
+ "ntapi",
+ "winapi",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
dependencies = [
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"smallvec",
]
-[[package]]
-name = "net2"
-version = "0.2.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7cf75f38f16cb05ea017784dc6dbfd354f76c223dba37701734c4f5a9337d02"
-dependencies = [
- "cfg-if 0.1.10",
- "libc",
- "winapi 0.3.9",
-]
-
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
+[[package]]
+name = "ntapi"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
+dependencies = [
+ "winapi",
+]
+
[[package]]
name = "num-integer"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c283bf0114efea9e42f1a60edea9859e8c47528eae09d01df4b29c1e489cc48"
dependencies = [
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
checksum = "4ea3ebcd72a54701f56345f16785a6d3ac2df7e986d273eb4395c0b01db17952"
dependencies = [
"bstr",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
dependencies = [
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
[[package]]
name = "parity-tokio-ipc"
-version = "0.8.0"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd7f6c69d7687501b2205fe51ade1d7b8797bb3aa141fe5bf13dd78c0483bc89"
+checksum = "9981e32fb75e004cc148f5fb70342f393830e0a4aa62e3cc93b50976218d42b6"
dependencies = [
"futures 0.3.12",
"libc",
"log",
- "mio-named-pipes",
- "miow 0.3.7",
"rand 0.7.3",
"tokio",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"libc",
"redox_syscall",
"smallvec",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"siphasher",
]
-[[package]]
-name = "pin-project-lite"
-version = "0.1.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b"
-
[[package]]
name = "pin-project-lite"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"serde_json",
"tempfile",
"tokio",
+ "tokio-stream",
"tokio-util",
"toml",
"url 2.2.2",
"stacker",
"tempfile",
"tracing",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"termize",
"tracing",
"unicode-width",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"smallvec",
"syn",
"url 2.2.2",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"stacker",
"tempfile",
"tracing",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"tracing",
"tracing-subscriber",
"tracing-tree",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"termize",
"tracing",
"unicode-width",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"smallvec",
"tempfile",
"tracing",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"smallvec",
"snap",
"tracing",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
dependencies = [
"lazy_static",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2"
dependencies = [
"libc",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"cfg-if 0.1.10",
"libc",
"psm",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
"rand 0.8.3",
"redox_syscall",
"remove_dir_all",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5"
dependencies = [
"dirs",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
dependencies = [
"dirs-next",
"rustversion",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
checksum = "1706be6b564323ce7092f5f7e6b118a14c8ef7ed0e69c8c5329c914a9f101295"
dependencies = [
"libc",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
dependencies = [
"libc",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
[[package]]
name = "tokio"
-version = "0.2.24"
+version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "099837d3464c16a808060bb3f02263b412f6fafcb5d01c533d309985fbeebe48"
+checksum = "c2602b8af3767c285202012822834005f596c811042315fa7e9f5b12b2a43207"
dependencies = [
+ "autocfg",
"bytes",
- "futures-core",
- "iovec",
- "lazy_static",
"libc",
"memchr",
"mio",
- "mio-named-pipes",
- "mio-uds",
"num_cpus",
- "pin-project-lite 0.1.11",
+ "once_cell",
+ "pin-project-lite",
"signal-hook-registry",
- "slab",
- "tokio-macros",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
-name = "tokio-macros"
-version = "0.2.6"
+name = "tokio-stream"
+version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a"
+checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f"
dependencies = [
- "proc-macro2",
- "quote",
- "syn",
+ "futures-core",
+ "pin-project-lite",
+ "tokio",
]
[[package]]
name = "tokio-util"
-version = "0.3.1"
+version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499"
+checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"log",
- "pin-project-lite 0.1.11",
+ "pin-project-lite",
"tokio",
]
checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f"
dependencies = [
"cfg-if 1.0.0",
- "pin-project-lite 0.2.4",
+ "pin-project-lite",
"tracing-attributes",
"tracing-core",
]
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
dependencies = [
"same-file",
- "winapi 0.3.9",
+ "winapi",
"winapi-util",
]
"rustc-std-workspace-core",
]
-[[package]]
-name = "winapi"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
-
[[package]]
name = "winapi"
version = "0.3.9"
"winapi-x86_64-pc-windows-gnu",
]
-[[package]]
-name = "winapi-build"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
-
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-[[package]]
-name = "ws2_32-sys"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
-dependencies = [
- "winapi 0.2.8",
- "winapi-build",
-]
-
[[package]]
name = "xattr"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1"
dependencies = [
- "winapi 0.3.9",
+ "winapi",
]
exclude = [
"build",
"compiler/rustc_codegen_cranelift",
+ "src/test/rustdoc-gui",
# HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`.
"obj",
# The `x` binary is a thin wrapper that calls `x.py`, which initializes
+Version 1.54.0 (2021-07-29)
+============================
+
+Language
+-----------------------
+
+- [You can now use macros for values in built-in attribute macros.][83366]
+ While a seemingly minor addition on its own, this enables a lot of
+ powerful functionality when combined correctly. Most notably you can
+ now include external documentation in your crate by writing the following.
+ ```rust
+ #![doc = include_str!("README.md")]
+ ```
+ You can also use this to include auto-generated modules:
+ ```rust
+ #[path = concat!(env!("OUT_DIR"), "/generated.rs")]
+ mod generated;
+ ```
+
+- [You can now cast between unsized slice types (and types which contain
+ unsized slices) in `const fn`.][85078]
+- [You can now use multiple generic lifetimes with `impl Trait` where the
+ lifetimes don't explicitly outlive another.][84701] In code this means
+ that you can now have `impl Trait<'a, 'b>` where as before you could
+ only have `impl Trait<'a, 'b> where 'b: 'a`.
+
+Compiler
+-----------------------
+
+- [Rustc will now search for custom JSON targets in
+ `/lib/rustlib/<target-triple>/target.json` where `/` is the "sysroot"
+ directory.][83800] You can find your sysroot directory by running
+ `rustc --print sysroot`.
+- [Added `wasm` as a `target_family` for WebAssembly platforms.][84072]
+- [You can now use `#[target_feature]` on safe functions when targeting
+ WebAssembly platforms.][84988]
+- [Improved debugger output for enums on Windows MSVC platforms.][85292]
+- [Added tier 3\* support for `bpfel-unknown-none`
+ and `bpfeb-unknown-none`.][79608]
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+ information on Rust's tiered platform support.
+
+Libraries
+-----------------------
+
+- [`panic::panic_any` will now `#[track_caller]`.][85745]
+- [Added `OutOfMemory` as a variant of `io::ErrorKind`.][84744]
+- [ `proc_macro::Literal` now implements `FromStr`.][84717]
+- [The implementations of vendor intrinsics in core::arch have been
+ significantly refactored.][83278] The main user-visible changes are
+ a 50% reduction in the size of libcore.rlib and stricter validation
+ of constant operands passed to intrinsics. The latter is technically
+ a breaking change, but allows Rust to more closely match the C vendor
+ intrinsics API.
+
+Stabilized APIs
+---------------
+
+- [`BTreeMap::into_keys`]
+- [`BTreeMap::into_values`]
+- [`HashMap::into_keys`]
+- [`HashMap::into_values`]
+- [`arch::wasm32`]
+- [`VecDeque::binary_search`]
+- [`VecDeque::binary_search_by`]
+- [`VecDeque::binary_search_by_key`]
+- [`VecDeque::partition_point`]
+
+Cargo
+-----
+
+- [Added the `--prune <spec>` option to `cargo-tree` to remove a package from
+ the dependency graph.][cargo/9520]
+- [Added the `--depth` option to `cargo-tree` to print only to a certain depth
+ in the tree ][cargo/9499]
+- [Added the `no-proc-macro` value to `cargo-tree --edges` to hide procedural
+ macro dependencies.][cargo/9488]
+- [A new environment variable named `CARGO_TARGET_TMPDIR` is available.][cargo/9375]
+ This variable points to a directory that integration tests and benches
+ can use as a "scratchpad" for testing filesystem operations.
+
+Compatibility Notes
+-------------------
+- [Mixing Option and Result via `?` is no longer permitted in closures for inferred types.][86831]
+- [Previously unsound code is no longer permitted where different constructors in branches
+ could require different lifetimes.][85574]
+- As previously mentioned the [`std::arch` instrinsics now uses stricter const checking][83278]
+ than before and may reject some previously accepted code.
+- [`i128` multiplication on Cortex M0+ platforms currently unconditionally causes overflow
+ when compiled with `codegen-units = 1`.][86063]
+
+[85574]: https://github.com/rust-lang/rust/issues/85574
+[86831]: https://github.com/rust-lang/rust/issues/86831
+[86063]: https://github.com/rust-lang/rust/issues/86063
+[86831]: https://github.com/rust-lang/rust/issues/86831
+[79608]: https://github.com/rust-lang/rust/pull/79608
+[84988]: https://github.com/rust-lang/rust/pull/84988
+[84701]: https://github.com/rust-lang/rust/pull/84701
+[84072]: https://github.com/rust-lang/rust/pull/84072
+[85745]: https://github.com/rust-lang/rust/pull/85745
+[84744]: https://github.com/rust-lang/rust/pull/84744
+[85078]: https://github.com/rust-lang/rust/pull/85078
+[84717]: https://github.com/rust-lang/rust/pull/84717
+[83800]: https://github.com/rust-lang/rust/pull/83800
+[83366]: https://github.com/rust-lang/rust/pull/83366
+[83278]: https://github.com/rust-lang/rust/pull/83278
+[85292]: https://github.com/rust-lang/rust/pull/85292
+[cargo/9520]: https://github.com/rust-lang/cargo/pull/9520
+[cargo/9499]: https://github.com/rust-lang/cargo/pull/9499
+[cargo/9488]: https://github.com/rust-lang/cargo/pull/9488
+[cargo/9375]: https://github.com/rust-lang/cargo/pull/9375
+[`BTreeMap::into_keys`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.into_keys
+[`BTreeMap::into_values`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.into_values
+[`HashMap::into_keys`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.into_keys
+[`HashMap::into_values`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.into_values
+[`arch::wasm32`]: https://doc.rust-lang.org/core/arch/wasm32/index.html
+[`VecDeque::binary_search`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.binary_search
+[`VecDeque::binary_search_by`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.binary_search_by
+
+[`VecDeque::binary_search_by_key`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.binary_search_by_key
+
+[`VecDeque::partition_point`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.partition_point
+
Version 1.53.0 (2021-06-17)
============================
- [`leading_zeros`, and `trailing_zeros` are now available on all
`NonZero` integer types.][84082]
- [`{f32, f64}::from_str` now parse and print special values
- (`NaN`, `-0`) according to IEEE RFC 754.][78618]
+ (`NaN`, `-0`) according to IEEE 754.][78618]
- [You can now index into slices using `(Bound<usize>, Bound<usize>)`.][77704]
- [Add the `BITS` associated constant to all numeric types.][82565]
- [You can now use `#[repr(transparent)]` on univariant `enum`s.][68122] Meaning
that you can create an enum that has the exact layout and ABI of the type
it contains.
-- [You can now use outer attribute procedural macros on inline modules.][64273]
+- [You can now use outer attribute procedural macros on inline modules.][64273]
- [There are some *syntax-only* changes:][67131]
- `default` is syntactically allowed before items in `trait` definitions.
- Items in `impl`s (i.e. `const`s, `type`s, and `fn`s) may syntactically
self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
AssocCtxt::Trait => {
let hir_item = lctx.lower_trait_item(item);
- let id = hir_item.trait_item_id();
- lctx.trait_items.insert(id, hir_item);
- lctx.modules.entry(lctx.current_module).or_default().trait_items.insert(id);
+ lctx.insert_trait_item(hir_item);
}
AssocCtxt::Impl => {
let hir_item = lctx.lower_impl_item(item);
- let id = hir_item.impl_item_id();
- lctx.impl_items.insert(id, hir_item);
- lctx.modules.entry(lctx.current_module).or_default().impl_items.insert(id);
+ lctx.insert_impl_item(hir_item);
}
});
self.lctx.allocate_hir_id_counter(item.id);
self.lctx.with_hir_id_owner(item.id, |lctx| {
let hir_item = lctx.lower_foreign_item(item);
- let id = hir_item.foreign_item_id();
- lctx.foreign_items.insert(id, hir_item);
- lctx.modules.entry(lctx.current_module).or_default().foreign_items.insert(id);
+ lctx.insert_foreign_item(hir_item);
});
visit::walk_foreign_item(self, item);
) -> T {
let old_len = self.in_scope_lifetimes.len();
- let parent_generics = match self.items.get(&parent_hir_id).unwrap().kind {
+ let parent_generics = match self.owners[parent_hir_id.def_id].unwrap().expect_item().kind {
hir::ItemKind::Impl(hir::Impl { ref generics, .. })
| hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
_ => &[],
let hir_id = self.lower_node_id(i.id);
self.lower_attrs(hir_id, &i.attrs);
let body = P(self.lower_mac_args(body));
- self.exported_macros.push(hir::MacroDef {
+ self.insert_macro_def(hir::MacroDef {
ident,
vis,
def_id: hir_id.expect_owner(),
itctx: ImplTraitContext<'_, 'hir>,
) -> GenericsCtor<'hir> {
// Collect `?Trait` bounds in where clause and move them to parameter definitions.
- // FIXME: this could probably be done with less rightward drift. It also looks like two
- // control paths where `report_error` is called are the only paths that advance to after the
- // match statement, so the error reporting could probably just be moved there.
let mut add_bounds: NodeMap<Vec<_>> = Default::default();
for pred in &generics.where_clause.predicates {
if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
'next_bound: for bound in &bound_pred.bounds {
if let GenericBound::Trait(_, TraitBoundModifier::Maybe) = *bound {
- let report_error = |this: &mut Self| {
- this.diagnostic().span_err(
- bound_pred.bounded_ty.span,
- "`?Trait` bounds are only permitted at the \
- point where a type parameter is declared",
- );
- };
// Check if the where clause type is a plain type parameter.
- match bound_pred.bounded_ty.kind {
- TyKind::Path(None, ref path)
- if path.segments.len() == 1
- && bound_pred.bound_generic_params.is_empty() =>
+ match self
+ .resolver
+ .get_partial_res(bound_pred.bounded_ty.id)
+ .map(|d| (d.base_res(), d.unresolved_segments()))
+ {
+ Some((Res::Def(DefKind::TyParam, def_id), 0))
+ if bound_pred.bound_generic_params.is_empty() =>
{
- if let Some(Res::Def(DefKind::TyParam, def_id)) = self
- .resolver
- .get_partial_res(bound_pred.bounded_ty.id)
- .map(|d| d.base_res())
- {
- if let Some(def_id) = def_id.as_local() {
- for param in &generics.params {
- if let GenericParamKind::Type { .. } = param.kind {
- if def_id == self.resolver.local_def_id(param.id) {
- add_bounds
- .entry(param.id)
- .or_default()
- .push(bound.clone());
- continue 'next_bound;
- }
- }
- }
+ for param in &generics.params {
+ if def_id == self.resolver.local_def_id(param.id).to_def_id() {
+ add_bounds.entry(param.id).or_default().push(bound.clone());
+ continue 'next_bound;
}
}
- report_error(self)
}
- _ => report_error(self),
+ _ => {}
}
+ self.diagnostic().span_err(
+ bound_pred.bounded_ty.span,
+ "`?Trait` bounds are only permitted at the \
+ point where a type parameter is declared",
+ );
}
}
}
arena: &'hir Arena<'hir>,
/// The items being lowered are collected here.
- items: BTreeMap<hir::ItemId, hir::Item<'hir>>,
-
- trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem<'hir>>,
- impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem<'hir>>,
- foreign_items: BTreeMap<hir::ForeignItemId, hir::ForeignItem<'hir>>,
+ owners: IndexVec<LocalDefId, Option<hir::OwnerNode<'hir>>>,
bodies: BTreeMap<hir::BodyId, hir::Body<'hir>>,
- exported_macros: Vec<hir::MacroDef<'hir>>,
non_exported_macro_attrs: Vec<ast::Attribute>,
trait_impls: BTreeMap<DefId, Vec<LocalDefId>>,
resolver,
nt_to_tokenstream,
arena,
- items: BTreeMap::new(),
- trait_items: BTreeMap::new(),
- impl_items: BTreeMap::new(),
- foreign_items: BTreeMap::new(),
+ owners: IndexVec::default(),
bodies: BTreeMap::new(),
trait_impls: BTreeMap::new(),
modules: BTreeMap::new(),
attrs: BTreeMap::default(),
- exported_macros: Vec::new(),
non_exported_macro_attrs: Vec::new(),
catch_scopes: Vec::new(),
loop_scopes: Vec::new(),
visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c);
visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c);
- let module = self.lower_mod(&c.items, c.span);
+ let module = self.arena.alloc(self.lower_mod(&c.items, c.span));
self.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
+ self.owners.ensure_contains_elem(CRATE_DEF_ID, || None);
+ self.owners[CRATE_DEF_ID] = Some(hir::OwnerNode::Crate(module));
+
let body_ids = body_ids(&self.bodies);
let proc_macros =
c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id].unwrap()).collect();
}
let krate = hir::Crate {
- item: module,
- exported_macros: self.arena.alloc_from_iter(self.exported_macros),
non_exported_macro_attrs: self.arena.alloc_from_iter(self.non_exported_macro_attrs),
- items: self.items,
- trait_items: self.trait_items,
- impl_items: self.impl_items,
- foreign_items: self.foreign_items,
+ owners: self.owners,
bodies: self.bodies,
body_ids,
trait_impls: self.trait_impls,
}
fn insert_item(&mut self, item: hir::Item<'hir>) -> hir::ItemId {
- let id = hir::ItemId { def_id: item.def_id };
- self.items.insert(id, item);
+ let id = item.item_id();
+ let item = self.arena.alloc(item);
+ self.owners.ensure_contains_elem(id.def_id, || None);
+ self.owners[id.def_id] = Some(hir::OwnerNode::Item(item));
self.modules.entry(self.current_module).or_default().items.insert(id);
id
}
+ fn insert_foreign_item(&mut self, item: hir::ForeignItem<'hir>) -> hir::ForeignItemId {
+ let id = item.foreign_item_id();
+ let item = self.arena.alloc(item);
+ self.owners.ensure_contains_elem(id.def_id, || None);
+ self.owners[id.def_id] = Some(hir::OwnerNode::ForeignItem(item));
+ self.modules.entry(self.current_module).or_default().foreign_items.insert(id);
+ id
+ }
+
+ fn insert_impl_item(&mut self, item: hir::ImplItem<'hir>) -> hir::ImplItemId {
+ let id = item.impl_item_id();
+ let item = self.arena.alloc(item);
+ self.owners.ensure_contains_elem(id.def_id, || None);
+ self.owners[id.def_id] = Some(hir::OwnerNode::ImplItem(item));
+ self.modules.entry(self.current_module).or_default().impl_items.insert(id);
+ id
+ }
+
+ fn insert_trait_item(&mut self, item: hir::TraitItem<'hir>) -> hir::TraitItemId {
+ let id = item.trait_item_id();
+ let item = self.arena.alloc(item);
+ self.owners.ensure_contains_elem(id.def_id, || None);
+ self.owners[id.def_id] = Some(hir::OwnerNode::TraitItem(item));
+ self.modules.entry(self.current_module).or_default().trait_items.insert(id);
+ id
+ }
+
+ fn insert_macro_def(&mut self, item: hir::MacroDef<'hir>) {
+ let def_id = item.def_id;
+ let item = self.arena.alloc(item);
+ self.owners.ensure_contains_elem(def_id, || None);
+ self.owners[def_id] = Some(hir::OwnerNode::MacroDef(item));
+ }
+
fn allocate_hir_id_counter(&mut self, owner: NodeId) -> hir::HirId {
// Set up the counter if needed.
self.item_local_id_counters.entry(owner).or_insert(0);
//!
//! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
-#![feature(bindings_after_at)]
+#![cfg_attr(bootstrap, feature(bindings_after_at))]
#![feature(iter_is_partitioned)]
#![feature(box_patterns)]
#![recursion_limit = "256"]
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(allow_internal_unstable)]
#![feature(array_windows)]
+#![feature(associated_type_bounds)]
+#![feature(auto_traits)]
+#![feature(bool_to_option)]
+#![feature(const_panic)]
#![feature(control_flow_enum)]
+#![feature(core_intrinsics)]
+#![feature(extend_one)]
+#![feature(hash_raw_entry)]
#![feature(in_band_lifetimes)]
+#![feature(iter_map_while)]
+#![feature(maybe_uninit_uninit_array)]
#![feature(min_specialization)]
-#![feature(auto_traits)]
+#![feature(min_type_alias_impl_trait)]
+#![feature(new_uninit)]
#![feature(nll)]
-#![feature(allow_internal_unstable)]
-#![feature(hash_raw_entry)]
-#![feature(core_intrinsics)]
+#![feature(once_cell)]
#![feature(test)]
-#![feature(associated_type_bounds)]
#![feature(thread_id_value)]
-#![feature(extend_one)]
-#![feature(const_panic)]
-#![feature(new_uninit)]
-#![feature(once_cell)]
-#![feature(maybe_uninit_uninit_array)]
#![allow(rustc::default_hash_types)]
#![deny(unaligned_references)]
use std::sync::Arc;
use std::time::{Duration, Instant};
-use measureme::{EventId, EventIdBuilder, Profiler, SerializableString, StringId};
+pub use measureme::EventId;
+use measureme::{EventIdBuilder, Profiler, SerializableString, StringId};
use parking_lot::RwLock;
bitflags::bitflags! {
struct EventFilter: u32 {
- const GENERIC_ACTIVITIES = 1 << 0;
- const QUERY_PROVIDERS = 1 << 1;
- const QUERY_CACHE_HITS = 1 << 2;
- const QUERY_BLOCKED = 1 << 3;
- const INCR_CACHE_LOADS = 1 << 4;
+ const GENERIC_ACTIVITIES = 1 << 0;
+ const QUERY_PROVIDERS = 1 << 1;
+ const QUERY_CACHE_HITS = 1 << 2;
+ const QUERY_BLOCKED = 1 << 3;
+ const INCR_CACHE_LOADS = 1 << 4;
- const QUERY_KEYS = 1 << 5;
- const FUNCTION_ARGS = 1 << 6;
- const LLVM = 1 << 7;
+ const QUERY_KEYS = 1 << 5;
+ const FUNCTION_ARGS = 1 << 6;
+ const LLVM = 1 << 7;
+ const INCR_RESULT_HASHING = 1 << 8;
const DEFAULT = Self::GENERIC_ACTIVITIES.bits |
Self::QUERY_PROVIDERS.bits |
Self::QUERY_BLOCKED.bits |
- Self::INCR_CACHE_LOADS.bits;
+ Self::INCR_CACHE_LOADS.bits |
+ Self::INCR_RESULT_HASHING.bits;
const ARGS = Self::QUERY_KEYS.bits | Self::FUNCTION_ARGS.bits;
}
}
-// keep this in sync with the `-Z self-profile-events` help message in librustc_session/options.rs
+// keep this in sync with the `-Z self-profile-events` help message in rustc_session/options.rs
const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[
("none", EventFilter::empty()),
("all", EventFilter::all()),
("function-args", EventFilter::FUNCTION_ARGS),
("args", EventFilter::ARGS),
("llvm", EventFilter::LLVM),
+ ("incr-result-hashing", EventFilter::INCR_RESULT_HASHING),
];
/// Something that uniquely identifies a query invocation.
})
}
+ /// Start profiling with some event filter for a given event. Profiling continues until the
+ /// TimingGuard returned from this call is dropped.
+ #[inline(always)]
+ pub fn generic_activity_with_event_id(&self, event_id: EventId) -> TimingGuard<'_> {
+ self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| {
+ TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id)
+ })
+ }
+
/// Start profiling a generic activity. Profiling continues until the
/// TimingGuard returned from this call is dropped.
#[inline(always)]
})
}
+ /// Start profiling how long it takes to hash query results for incremental compilation.
+ /// Profiling continues until the TimingGuard returned from this call is dropped.
+ #[inline(always)]
+ pub fn incr_result_hashing(&self) -> TimingGuard<'_> {
+ self.exec(EventFilter::INCR_RESULT_HASHING, |profiler| {
+ TimingGuard::start(
+ profiler,
+ profiler.incremental_result_hashing_event_kind,
+ EventId::INVALID,
+ )
+ })
+ }
+
#[inline(always)]
fn instant_query_event(
&self,
}
}
+ /// Gets a `StringId` for the given string. This method makes sure that
+ /// any strings going through it will only be allocated once in the
+ /// profiling data.
+ /// Returns `None` if the self-profiling is not enabled.
+ pub fn get_or_alloc_cached_string(&self, s: &str) -> Option<StringId> {
+ self.profiler.as_ref().map(|p| p.get_or_alloc_cached_string(s))
+ }
+
#[inline]
pub fn enabled(&self) -> bool {
self.profiler.is_some()
query_event_kind: StringId,
generic_activity_event_kind: StringId,
incremental_load_result_event_kind: StringId,
+ incremental_result_hashing_event_kind: StringId,
query_blocked_event_kind: StringId,
query_cache_hit_event_kind: StringId,
}
let query_event_kind = profiler.alloc_string("Query");
let generic_activity_event_kind = profiler.alloc_string("GenericActivity");
let incremental_load_result_event_kind = profiler.alloc_string("IncrementalLoadResult");
+ let incremental_result_hashing_event_kind =
+ profiler.alloc_string("IncrementalResultHashing");
let query_blocked_event_kind = profiler.alloc_string("QueryBlocked");
let query_cache_hit_event_kind = profiler.alloc_string("QueryCacheHit");
query_event_kind,
generic_activity_event_kind,
incremental_load_result_event_kind,
+ incremental_result_hashing_event_kind,
query_blocked_event_kind,
query_cache_hit_event_kind,
})
//! A variant of `SortedMap` that preserves insertion order.
-use std::borrow::Borrow;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
///
/// If there are multiple items that are equivalent to `key`, they will be yielded in
/// insertion order.
- pub fn get_by_key<Q: 'a>(&'a self, key: &Q) -> impl 'a + Iterator<Item = &'a V>
- where
- Q: Ord + ?Sized,
- K: Borrow<Q>,
- {
+ pub fn get_by_key(&'a self, key: K) -> impl 'a + Iterator<Item = &'a V> {
self.get_by_key_enumerated(key).map(|(_, v)| v)
}
///
/// If there are multiple items that are equivalent to `key`, they will be yielded in
/// insertion order.
- pub fn get_by_key_enumerated<Q>(&self, key: &Q) -> impl '_ + Iterator<Item = (I, &V)>
- where
- Q: Ord + ?Sized,
- K: Borrow<Q>,
- {
- match self.binary_search_idx(key) {
- Err(_) => self.idxs_to_items_enumerated(&[]),
-
- Ok(idx) => {
- let start = self.idx_sorted_by_item_key[..idx]
- .partition_point(|&i| self.items[i].0.borrow() != key);
- let end = idx
- + self.idx_sorted_by_item_key[idx..]
- .partition_point(|&i| self.items[i].0.borrow() == key);
- self.idxs_to_items_enumerated(&self.idx_sorted_by_item_key[start..end])
- }
- }
- }
-
- fn binary_search_idx<Q>(&self, key: &Q) -> Result<usize, usize>
- where
- Q: Ord + ?Sized,
- K: Borrow<Q>,
- {
- self.idx_sorted_by_item_key.binary_search_by(|&idx| self.items[idx].0.borrow().cmp(key))
- }
-
- fn idxs_to_items_enumerated(&'a self, idxs: &'a [I]) -> impl 'a + Iterator<Item = (I, &'a V)> {
- idxs.iter().map(move |&idx| (idx, &self.items[idx].1))
+ pub fn get_by_key_enumerated(&'a self, key: K) -> impl '_ + Iterator<Item = (I, &V)> {
+ let lower_bound = self.idx_sorted_by_item_key.partition_point(|&i| self.items[i].0 < key);
+ self.idx_sorted_by_item_key[lower_bound..].iter().map_while(move |&i| {
+ let (k, v) = &self.items[i];
+ (k == &key).then_some((i, v))
+ })
}
}
}
// `get_by_key` works.
- assert_eq!(set.get_by_key(&3).copied().collect::<Vec<_>>(), vec![0]);
- assert!(set.get_by_key(&4).next().is_none());
+ assert_eq!(set.get_by_key(3).copied().collect::<Vec<_>>(), vec![0]);
+ assert!(set.get_by_key(4).next().is_none());
// `get_by_key` returns items in insertion order.
- let twos: Vec<_> = set.get_by_key_enumerated(&2).collect();
+ let twos: Vec<_> = set.get_by_key_enumerated(2).collect();
let idxs: Vec<usize> = twos.iter().map(|(i, _)| *i).collect();
let values: Vec<usize> = twos.iter().map(|(_, &v)| v).collect();
use std::borrow::Borrow;
+use std::fmt::Debug;
use std::iter::FromIterator;
-use std::slice::{Iter, IterMut};
+use std::slice::Iter;
use std::vec::IntoIter;
use crate::stable_hasher::{HashStable, StableHasher};
impl<K, V> VecMap<K, V>
where
- K: PartialEq,
+ K: Debug + PartialEq,
+ V: Debug,
{
pub fn new() -> Self {
VecMap(Default::default())
self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1)
}
- /// Returns the value corresponding to the supplied predicate filter.
+ /// Returns the any value corresponding to the supplied predicate filter.
///
/// The supplied predicate will be applied to each (key, value) pair and it will return a
/// reference to the values where the predicate returns `true`.
- pub fn get_by(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> {
+ pub fn any_value_matching(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> {
self.0.iter().find(|kv| predicate(kv)).map(|elem| &elem.1)
}
+ /// Returns the value corresponding to the supplied predicate filter. It crashes if there's
+ /// more than one matching element.
+ ///
+ /// The supplied predicate will be applied to each (key, value) pair and it will return a
+ /// reference to the value where the predicate returns `true`.
+ pub fn get_value_matching(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> {
+ let mut filter = self.0.iter().filter(|kv| predicate(kv));
+ let (_, value) = filter.next()?;
+ // This should return just one element, otherwise it's a bug
+ assert!(
+ filter.next().is_none(),
+ "Collection {:?} should have just one matching element",
+ self
+ );
+ Some(value)
+ }
+
/// Returns `true` if the map contains a value for the specified key.
///
/// The key may be any borrowed form of the map's key type,
self.into_iter()
}
- pub fn iter_mut(&mut self) -> IterMut<'_, (K, V)> {
+ pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
self.into_iter()
}
+
+ pub fn retain(&mut self, f: impl Fn(&(K, V)) -> bool) {
+ self.0.retain(f)
+ }
}
impl<K, V> Default for VecMap<K, V> {
}
impl<'a, K, V> IntoIterator for &'a mut VecMap<K, V> {
- type Item = &'a mut (K, V);
- type IntoIter = IterMut<'a, (K, V)>;
+ type Item = (&'a K, &'a mut V);
+ type IntoIter = impl Iterator<Item = Self::Item>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
- self.0.iter_mut()
+ self.0.iter_mut().map(|(k, v)| (&*k, v))
}
}
}
}
-impl<K: PartialEq, V> Extend<(K, V)> for VecMap<K, V> {
+impl<K: PartialEq + Debug, V: Debug> Extend<(K, V)> for VecMap<K, V> {
fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
for (k, v) in iter {
self.insert(k, v);
use crate::expand::{self, AstFragment, Invocation};
use crate::module::DirOwnership;
+use rustc_ast::attr::MarkedAttrs;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Nonterminal};
use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
pub prior_type_ascription: Option<(Span, bool)>,
/// Some parent node that is close to this macro call
pub lint_node_id: NodeId,
+ pub is_trailing_mac: bool,
}
type OnExternModLoaded<'a> =
///
/// `Ident` is the module name.
pub(super) extern_mod_loaded: OnExternModLoaded<'a>,
+ /// When we 'expand' an inert attribute, we leave it
+ /// in the AST, but insert it here so that we know
+ /// not to expand it again.
+ pub(super) expanded_inert_attrs: MarkedAttrs,
}
impl<'a> ExtCtxt<'a> {
dir_ownership: DirOwnership::Owned { relative: None },
prior_type_ascription: None,
lint_node_id: ast::CRATE_NODE_ID,
+ is_trailing_mac: false,
},
force_mode: false,
expansions: FxHashMap::default(),
+ expanded_inert_attrs: MarkedAttrs::new(),
}
}
use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{AstLike, Block, Inline, ItemKind, Local, MacArgs};
+use rustc_ast::{AstLike, Block, Inline, ItemKind, Local, MacArgs, MacCall};
use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
use rustc_ast_pretty::pprust;
AttemptLocalParseRecovery, ForceCollect, Parser, RecoverColon, RecoverComma,
};
use rustc_parse::validate_attr;
-use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS;
+use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::{feature_err, ParseSess};
use rustc_session::Limit;
}
}
SyntaxExtensionKind::NonMacroAttr { mark_used } => {
- self.cx.sess.mark_attr_known(&attr);
+ self.cx.expanded_inert_attrs.mark(&attr);
if *mark_used {
self.cx.sess.mark_attr_used(&attr);
}
item.visit_attrs(|attrs| {
attr = attrs
.iter()
- .position(|a| !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a))
+ .position(|a| !self.cx.expanded_inert_attrs.is_marked(a) && !is_builtin_attr(a))
.map(|attr_pos| {
let attr = attrs.remove(attr_pos);
let following_derives = attrs[attr_pos..]
// Detect use of feature-gated or invalid attributes on macro invocations
// since they will not be detected after macro expansion.
- fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
+ fn check_attributes(&mut self, attrs: &[ast::Attribute], call: &MacCall) {
let features = self.cx.ecfg.features.unwrap();
let mut attrs = attrs.iter().peekable();
let mut span: Option<Span> = None;
continue;
}
- if attr.doc_str().is_some() {
+ if attr.is_doc_comment() {
self.cx.sess.parse_sess.buffer_lint_with_diagnostic(
&UNUSED_DOC_COMMENTS,
current_span,
- ast::CRATE_NODE_ID,
+ self.cx.current_expansion.lint_node_id,
"unused doc comment",
BuiltinLintDiagnostics::UnusedDocComment(attr.span),
);
+ } else if rustc_attr::is_builtin_attr(attr) {
+ let attr_name = attr.ident().unwrap().name;
+ // `#[cfg]` and `#[cfg_attr]` are special - they are
+ // eagerly evaluated.
+ if attr_name != sym::cfg && attr_name != sym::cfg_attr {
+ self.cx.sess.parse_sess.buffer_lint_with_diagnostic(
+ &UNUSED_ATTRIBUTES,
+ attr.span,
+ self.cx.current_expansion.lint_node_id,
+ &format!("unused attribute `{}`", attr_name),
+ BuiltinLintDiagnostics::UnusedBuiltinAttribute {
+ attr_name,
+ macro_name: pprust::path_to_string(&call.path),
+ invoc_span: call.path.span,
+ },
+ );
+ }
}
}
}
}
if let ast::ExprKind::MacCall(mac) = expr.kind {
- self.check_attributes(&expr.attrs);
+ self.check_attributes(&expr.attrs, &mac);
self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner()
} else {
assign_id!(self, &mut expr.id, || {
}
if let ast::ExprKind::MacCall(mac) = expr.kind {
- self.check_attributes(&expr.attrs);
+ self.check_attributes(&expr.attrs, &mac);
self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr)
.make_opt_expr()
.map(|expr| expr.into_inner())
if let StmtKind::MacCall(mac) = stmt.kind {
let MacCallStmt { mac, style, attrs, tokens: _ } = mac.into_inner();
- self.check_attributes(&attrs);
+ self.check_attributes(&attrs, &mac);
let mut placeholder =
self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts).make_stmts();
return placeholder;
}
+ // The only way that we can end up with a `MacCall` expression statement,
+ // (as opposed to a `StmtKind::MacCall`) is if we have a macro as the
+ // traiing expression in a block (e.g. `fn foo() { my_macro!() }`).
+ // Record this information, so that we can report a more specific
+ // `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed.
+ // See #78991 for an investigation of treating macros in this position
+ // as statements, rather than expressions, during parsing.
+ if let StmtKind::Expr(expr) = &stmt.kind {
+ if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) {
+ self.cx.current_expansion.is_trailing_mac = true;
+ }
+ }
+
// The placeholder expander gives ids to statements, so we avoid folding the id here.
// We don't use `assign_id!` - it will be called when we visit statement's contents
// (e.g. an expression, item, or local)
let ast::Stmt { id, kind, span } = stmt;
- noop_flat_map_stmt_kind(kind, self)
+ let res = noop_flat_map_stmt_kind(kind, self)
.into_iter()
.map(|kind| ast::Stmt { id, kind, span })
- .collect()
+ .collect();
+
+ self.cx.current_expansion.is_trailing_mac = false;
+ res
}
fn visit_block(&mut self, block: &mut P<Block>) {
let span = item.span;
match item.kind {
- ast::ItemKind::MacCall(..) => {
+ ast::ItemKind::MacCall(ref mac) => {
+ self.check_attributes(&attrs, &mac);
item.attrs = attrs;
- self.check_attributes(&item.attrs);
item.and_then(|item| match item.kind {
ItemKind::MacCall(mac) => {
self.collect_bang(mac, span, AstFragmentKind::Items).make_items()
}
match item.kind {
- ast::AssocItemKind::MacCall(..) => {
- self.check_attributes(&item.attrs);
+ ast::AssocItemKind::MacCall(ref mac) => {
+ self.check_attributes(&item.attrs, &mac);
item.and_then(|item| match item.kind {
ast::AssocItemKind::MacCall(mac) => self
.collect_bang(mac, item.span, AstFragmentKind::TraitItems)
}
match item.kind {
- ast::AssocItemKind::MacCall(..) => {
- self.check_attributes(&item.attrs);
+ ast::AssocItemKind::MacCall(ref mac) => {
+ self.check_attributes(&item.attrs, &mac);
item.and_then(|item| match item.kind {
ast::AssocItemKind::MacCall(mac) => self
.collect_bang(mac, item.span, AstFragmentKind::ImplItems)
}
match foreign_item.kind {
- ast::ForeignItemKind::MacCall(..) => {
- self.check_attributes(&foreign_item.attrs);
+ ast::ForeignItemKind::MacCall(ref mac) => {
+ self.check_attributes(&foreign_item.attrs, &mac);
foreign_item.and_then(|item| match item.kind {
ast::ForeignItemKind::MacCall(mac) => self
.collect_bang(mac, item.span, AstFragmentKind::ForeignItems)
/// The ident of the macro we're parsing
macro_ident: Ident,
lint_node_id: NodeId,
+ is_trailing_mac: bool,
arm_span: Span,
}
impl<'a> ParserAnyMacro<'a> {
crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
- let ParserAnyMacro { site_span, macro_ident, ref mut parser, lint_node_id, arm_span } =
- *self;
+ let ParserAnyMacro {
+ site_span,
+ macro_ident,
+ ref mut parser,
+ lint_node_id,
+ arm_span,
+ is_trailing_mac,
+ } = *self;
let snapshot = &mut parser.clone();
let fragment = match parse_ast_fragment(parser, kind) {
Ok(f) => f,
// `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`,
// but `m!()` is allowed in expression positions (cf. issue #34706).
if kind == AstFragmentKind::Expr && parser.token == token::Semi {
- parser.sess.buffer_lint(
+ parser.sess.buffer_lint_with_diagnostic(
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
parser.token.span,
lint_node_id,
"trailing semicolon in macro used in expression position",
+ BuiltinLintDiagnostics::TrailingMacro(is_trailing_mac, macro_ident),
);
parser.bump();
}
site_span: sp,
macro_ident: name,
lint_node_id: cx.current_expansion.lint_node_id,
+ is_trailing_mac: cx.current_expansion.is_trailing_mac,
arm_span,
});
}
(accepted, const_fn_unsize, "1.54.0", Some(64992), None),
/// Allows `impl Trait` with multiple unrelated lifetimes.
(accepted, member_constraints, "1.54.0", Some(61997), None),
+ /// Allows bindings in the subpattern of a binding pattern.
+ /// For example, you can write `x @ Some(y)`.
+ (accepted, bindings_after_at, "1.54.0", Some(65490), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features
/// Allows using `&mut` in constant functions.
(active, const_mut_refs, "1.41.0", Some(57349), None),
- /// Allows bindings in the subpattern of a binding pattern.
- /// For example, you can write `x @ Some(y)`.
- (active, bindings_after_at, "1.41.0", Some(65490), None),
-
/// Allows `impl const Trait for T` syntax.
(active, const_trait_impl, "1.42.0", Some(67792), None),
rustc_attr!(TEST, rustc_dump_program_clauses, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_dump_env_program_clauses, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_object_lifetime_default, AssumedUsed, template!(Word)),
+ rustc_attr!(TEST, rustc_dump_vtable, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)),
gated!(
omit_gdb_pretty_printer_section, AssumedUsed, template!(Word),
[] fn_decl: rustc_hir::FnDecl<$tcx>,
[] foreign_item: rustc_hir::ForeignItem<$tcx>,
[few] foreign_item_ref: rustc_hir::ForeignItemRef<$tcx>,
+ [] impl_item: rustc_hir::ImplItem<$tcx>,
[] impl_item_ref: rustc_hir::ImplItemRef<$tcx>,
+ [] item: rustc_hir::Item<$tcx>,
[few] inline_asm: rustc_hir::InlineAsm<$tcx>,
[few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>,
[] local: rustc_hir::Local<$tcx>,
[few] macro_def: rustc_hir::MacroDef<$tcx>,
+ [few] mod_: rustc_hir::Mod<$tcx>,
[] param: rustc_hir::Param<$tcx>,
[] pat: rustc_hir::Pat<$tcx>,
[] path: rustc_hir::Path<$tcx>,
[] qpath: rustc_hir::QPath<$tcx>,
[] stmt: rustc_hir::Stmt<$tcx>,
[] field_def: rustc_hir::FieldDef<$tcx>,
+ [] trait_item: rustc_hir::TraitItem<$tcx>,
[] trait_item_ref: rustc_hir::TraitItemRef,
[] ty: rustc_hir::Ty<$tcx>,
[] type_binding: rustc_hir::TypeBinding<$tcx>,
// ignore-tidy-filelength
use crate::def::{CtorKind, DefKind, Res};
-use crate::def_id::DefId;
+use crate::def_id::{DefId, CRATE_DEF_ID};
crate use crate::hir_id::{HirId, ItemLocalId};
use crate::{itemlikevisit, LangItem};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
+use rustc_index::vec::IndexVec;
use rustc_macros::HashStable_Generic;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
#[derive(Debug)]
pub struct Crate<'hir> {
- pub item: Mod<'hir>,
- pub exported_macros: &'hir [MacroDef<'hir>],
// Attributes from non-exported macros, kept only for collecting the library feature list.
pub non_exported_macro_attrs: &'hir [Attribute],
- // N.B., we use a `BTreeMap` here so that `visit_all_items` iterates
- // over the ids in increasing order. In principle it should not
- // matter what order we visit things in, but in *practice* it
- // does, because it can affect the order in which errors are
- // detected, which in turn can make UI tests yield
- // slightly different results.
- pub items: BTreeMap<ItemId, Item<'hir>>,
-
- pub trait_items: BTreeMap<TraitItemId, TraitItem<'hir>>,
- pub impl_items: BTreeMap<ImplItemId, ImplItem<'hir>>,
- pub foreign_items: BTreeMap<ForeignItemId, ForeignItem<'hir>>,
+ pub owners: IndexVec<LocalDefId, Option<OwnerNode<'hir>>>,
pub bodies: BTreeMap<BodyId, Body<'hir>>,
pub trait_impls: BTreeMap<DefId, Vec<LocalDefId>>,
}
impl Crate<'hir> {
- pub fn item(&self, id: ItemId) -> &Item<'hir> {
- &self.items[&id]
+ pub fn module(&self) -> &'hir Mod<'hir> {
+ if let Some(OwnerNode::Crate(m)) = self.owners[CRATE_DEF_ID] { m } else { panic!() }
}
- pub fn trait_item(&self, id: TraitItemId) -> &TraitItem<'hir> {
- &self.trait_items[&id]
+ pub fn item(&self, id: ItemId) -> &'hir Item<'hir> {
+ self.owners[id.def_id].as_ref().unwrap().expect_item()
}
- pub fn impl_item(&self, id: ImplItemId) -> &ImplItem<'hir> {
- &self.impl_items[&id]
+ pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
+ self.owners[id.def_id].as_ref().unwrap().expect_trait_item()
}
- pub fn foreign_item(&self, id: ForeignItemId) -> &ForeignItem<'hir> {
- &self.foreign_items[&id]
+ pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
+ self.owners[id.def_id].as_ref().unwrap().expect_impl_item()
+ }
+
+ pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
+ self.owners[id.def_id].as_ref().unwrap().expect_foreign_item()
}
pub fn body(&self, id: BodyId) -> &Body<'hir> {
where
V: itemlikevisit::ItemLikeVisitor<'hir>,
{
- for item in self.items.values() {
- visitor.visit_item(item);
- }
-
- for trait_item in self.trait_items.values() {
- visitor.visit_trait_item(trait_item);
- }
-
- for impl_item in self.impl_items.values() {
- visitor.visit_impl_item(impl_item);
- }
-
- for foreign_item in self.foreign_items.values() {
- visitor.visit_foreign_item(foreign_item);
+ for owner in self.owners.iter().filter_map(Option::as_ref) {
+ match owner {
+ OwnerNode::Item(item) => visitor.visit_item(item),
+ OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
+ OwnerNode::ImplItem(item) => visitor.visit_impl_item(item),
+ OwnerNode::TraitItem(item) => visitor.visit_trait_item(item),
+ OwnerNode::MacroDef(_) | OwnerNode::Crate(_) => {}
+ }
}
}
where
V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send,
{
- parallel!(
- {
- par_for_each_in(&self.items, |(_, item)| {
- visitor.visit_item(item);
- });
- },
- {
- par_for_each_in(&self.trait_items, |(_, trait_item)| {
- visitor.visit_trait_item(trait_item);
- });
- },
- {
- par_for_each_in(&self.impl_items, |(_, impl_item)| {
- visitor.visit_impl_item(impl_item);
- });
- },
- {
- par_for_each_in(&self.foreign_items, |(_, foreign_item)| {
- visitor.visit_foreign_item(foreign_item);
- });
- }
- );
+ par_for_each_in(&self.owners.raw, |owner| match owner {
+ Some(OwnerNode::Item(item)) => visitor.visit_item(item),
+ Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item),
+ Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item),
+ Some(OwnerNode::TraitItem(item)) => visitor.visit_trait_item(item),
+ Some(OwnerNode::MacroDef(_)) | Some(OwnerNode::Crate(_)) | None => {}
+ })
+ }
+
+ pub fn items<'hir>(&'hir self) -> impl Iterator<Item = &'hir Item<'hir>> + 'hir {
+ self.owners.iter().filter_map(|owner| match owner {
+ Some(OwnerNode::Item(item)) => Some(*item),
+ _ => None,
+ })
+ }
+
+ pub fn exported_macros<'hir>(&'hir self) -> impl Iterator<Item = &'hir MacroDef<'hir>> + 'hir {
+ self.owners.iter().filter_map(|owner| match owner {
+ Some(OwnerNode::MacroDef(macro_def)) => Some(*macro_def),
+ _ => None,
+ })
}
}
/// These are usually found nested inside types (e.g., array lengths)
/// or expressions (e.g., repeat counts), and also used to define
/// explicit discriminant values for enum variants.
+///
+/// You can check if this anon const is a default in a const param
+/// `const N: usize = { ... }` with `tcx.hir().opt_const_param_default_param_hir_id(..)`
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
pub struct AnonConst {
pub hir_id: HirId,
pub import_ids: SmallVec<[LocalDefId; 1]>,
}
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
+pub enum OwnerNode<'hir> {
+ Item(&'hir Item<'hir>),
+ ForeignItem(&'hir ForeignItem<'hir>),
+ TraitItem(&'hir TraitItem<'hir>),
+ ImplItem(&'hir ImplItem<'hir>),
+ MacroDef(&'hir MacroDef<'hir>),
+ Crate(&'hir Mod<'hir>),
+}
+
+impl<'hir> OwnerNode<'hir> {
+ pub fn ident(&self) -> Option<Ident> {
+ match self {
+ OwnerNode::Item(Item { ident, .. })
+ | OwnerNode::ForeignItem(ForeignItem { ident, .. })
+ | OwnerNode::ImplItem(ImplItem { ident, .. })
+ | OwnerNode::TraitItem(TraitItem { ident, .. })
+ | OwnerNode::MacroDef(MacroDef { ident, .. }) => Some(*ident),
+ OwnerNode::Crate(..) => None,
+ }
+ }
+
+ pub fn span(&self) -> Span {
+ match self {
+ OwnerNode::Item(Item { span, .. })
+ | OwnerNode::ForeignItem(ForeignItem { span, .. })
+ | OwnerNode::ImplItem(ImplItem { span, .. })
+ | OwnerNode::TraitItem(TraitItem { span, .. })
+ | OwnerNode::MacroDef(MacroDef { span, .. })
+ | OwnerNode::Crate(Mod { inner: span, .. }) => *span,
+ }
+ }
+
+ pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> {
+ match self {
+ OwnerNode::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
+ | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
+ | OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl),
+ OwnerNode::ForeignItem(ForeignItem {
+ kind: ForeignItemKind::Fn(fn_decl, _, _),
+ ..
+ }) => Some(fn_decl),
+ _ => None,
+ }
+ }
+
+ pub fn body_id(&self) -> Option<BodyId> {
+ match self {
+ OwnerNode::TraitItem(TraitItem {
+ kind: TraitItemKind::Fn(_, TraitFn::Provided(body_id)),
+ ..
+ })
+ | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })
+ | OwnerNode::Item(Item { kind: ItemKind::Fn(.., body_id), .. }) => Some(*body_id),
+ _ => None,
+ }
+ }
+
+ pub fn generics(&self) -> Option<&'hir Generics<'hir>> {
+ match self {
+ OwnerNode::TraitItem(TraitItem { generics, .. })
+ | OwnerNode::ImplItem(ImplItem { generics, .. }) => Some(generics),
+ OwnerNode::Item(item) => item.kind.generics(),
+ _ => None,
+ }
+ }
+
+ pub fn def_id(self) -> LocalDefId {
+ match self {
+ OwnerNode::Item(Item { def_id, .. })
+ | OwnerNode::TraitItem(TraitItem { def_id, .. })
+ | OwnerNode::ImplItem(ImplItem { def_id, .. })
+ | OwnerNode::ForeignItem(ForeignItem { def_id, .. })
+ | OwnerNode::MacroDef(MacroDef { def_id, .. }) => *def_id,
+ OwnerNode::Crate(..) => crate::CRATE_HIR_ID.owner,
+ }
+ }
+
+ pub fn expect_item(self) -> &'hir Item<'hir> {
+ match self {
+ OwnerNode::Item(n) => n,
+ _ => panic!(),
+ }
+ }
+
+ pub fn expect_foreign_item(self) -> &'hir ForeignItem<'hir> {
+ match self {
+ OwnerNode::ForeignItem(n) => n,
+ _ => panic!(),
+ }
+ }
+
+ pub fn expect_impl_item(self) -> &'hir ImplItem<'hir> {
+ match self {
+ OwnerNode::ImplItem(n) => n,
+ _ => panic!(),
+ }
+ }
+
+ pub fn expect_trait_item(self) -> &'hir TraitItem<'hir> {
+ match self {
+ OwnerNode::TraitItem(n) => n,
+ _ => panic!(),
+ }
+ }
+
+ pub fn expect_macro_def(self) -> &'hir MacroDef<'hir> {
+ match self {
+ OwnerNode::MacroDef(n) => n,
+ _ => panic!(),
+ }
+ }
+}
+
+impl<'hir> Into<OwnerNode<'hir>> for &'hir Item<'hir> {
+ fn into(self) -> OwnerNode<'hir> {
+ OwnerNode::Item(self)
+ }
+}
+
+impl<'hir> Into<OwnerNode<'hir>> for &'hir ForeignItem<'hir> {
+ fn into(self) -> OwnerNode<'hir> {
+ OwnerNode::ForeignItem(self)
+ }
+}
+
+impl<'hir> Into<OwnerNode<'hir>> for &'hir ImplItem<'hir> {
+ fn into(self) -> OwnerNode<'hir> {
+ OwnerNode::ImplItem(self)
+ }
+}
+
+impl<'hir> Into<OwnerNode<'hir>> for &'hir TraitItem<'hir> {
+ fn into(self) -> OwnerNode<'hir> {
+ OwnerNode::TraitItem(self)
+ }
+}
+
+impl<'hir> Into<OwnerNode<'hir>> for &'hir MacroDef<'hir> {
+ fn into(self) -> OwnerNode<'hir> {
+ OwnerNode::MacroDef(self)
+ }
+}
+
+impl<'hir> Into<Node<'hir>> for OwnerNode<'hir> {
+ fn into(self) -> Node<'hir> {
+ match self {
+ OwnerNode::Item(n) => Node::Item(n),
+ OwnerNode::ForeignItem(n) => Node::ForeignItem(n),
+ OwnerNode::ImplItem(n) => Node::ImplItem(n),
+ OwnerNode::TraitItem(n) => Node::TraitItem(n),
+ OwnerNode::MacroDef(n) => Node::MacroDef(n),
+ OwnerNode::Crate(n) => Node::Crate(n),
+ }
+ }
+}
+
#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum Node<'hir> {
Param(&'hir Param<'hir>),
_ => Constness::NotConst,
}
}
+
+ pub fn as_owner(self) -> Option<OwnerNode<'hir>> {
+ match self {
+ Node::Item(i) => Some(OwnerNode::Item(i)),
+ Node::ForeignItem(i) => Some(OwnerNode::ForeignItem(i)),
+ Node::TraitItem(i) => Some(OwnerNode::TraitItem(i)),
+ Node::ImplItem(i) => Some(OwnerNode::ImplItem(i)),
+ Node::MacroDef(i) => Some(OwnerNode::MacroDef(i)),
+ Node::Crate(i) => Some(OwnerNode::Crate(i)),
+ _ => None,
+ }
+ }
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
/// Walks the contents of a crate. See also `Crate::visit_all_items`.
pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate<'v>) {
- visitor.visit_mod(&krate.item, krate.item.inner, CRATE_HIR_ID);
- walk_list!(visitor, visit_macro_def, krate.exported_macros);
+ let top_mod = krate.module();
+ visitor.visit_mod(top_mod, top_mod.inner, CRATE_HIR_ID);
+ walk_list!(visitor, visit_macro_def, krate.exported_macros());
for (&id, attrs) in krate.attrs.iter() {
for a in *attrs {
visitor.visit_attribute(id, a)
// When printing the AST, we sometimes need to inject `#[no_std]` here.
// Since you can't compile the HIR, it's not necessary.
- s.print_mod(&krate.item, s.attrs(hir::CRATE_HIR_ID));
+ s.print_mod(&krate.module(), s.attrs(hir::CRATE_HIR_ID));
s.print_remaining_comments();
s.s.eof()
}
)
}
- /// A hacky variant of `canonicalize_query` that does not
- /// canonicalize `'static`. Unfortunately, the existing leak
- /// check treats `'static` differently in some cases (see also
- /// #33684), so if we are performing an operation that may need to
- /// prove "leak-check" related things, we leave `'static`
- /// alone.
- ///
- /// `'static` is also special cased when winnowing candidates when
- /// selecting implementation candidates, so we also have to leave `'static`
- /// alone for queries that do selection.
- //
- // FIXME(#48536): once the above issues are resolved, we can remove this
- // and just use `canonicalize_query`.
- pub fn canonicalize_hr_query_hack<V>(
+ /// A variant of `canonicalize_query` that does not
+ /// canonicalize `'static`. This is useful when
+ /// the query implementation can perform more efficient
+ /// handling of `'static` regions (e.g. trait evaluation).
+ pub fn canonicalize_query_keep_static<V>(
&self,
value: V,
query_state: &mut OriginalQueryValues<'tcx>,
let get_lifetimes = |sig| {
use rustc_hir::def::Namespace;
let mut s = String::new();
- let (_, (sig, reg)) = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS)
+ let (_, sig, reg) = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS)
.name_all_regions(sig)
.unwrap();
let lts: Vec<String> = reg.into_iter().map(|(_, kind)| kind.to_string()).collect();
const_freshen_count: u32,
ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
const_freshen_map: FxHashMap<ty::InferConst<'tcx>, &'tcx ty::Const<'tcx>>,
+ keep_static: bool,
}
impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeFreshener<'a, 'tcx> {
+ pub fn new(infcx: &'a InferCtxt<'a, 'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> {
TypeFreshener {
infcx,
ty_freshen_count: 0,
const_freshen_count: 0,
ty_freshen_map: Default::default(),
const_freshen_map: Default::default(),
+ keep_static,
}
}
r
}
- ty::ReStatic
- | ty::ReEarlyBound(..)
+ ty::ReEarlyBound(..)
| ty::ReFree(_)
| ty::ReVar(_)
| ty::RePlaceholder(..)
// replace all free regions with 'erased
self.tcx().lifetimes.re_erased
}
+ ty::ReStatic => {
+ if self.keep_static {
+ r
+ } else {
+ self.tcx().lifetimes.re_erased
+ }
+ }
}
}
let sub = var_data.normalize(self.tcx(), verify.region);
let verify_kind_ty = verify.kind.to_ty(self.tcx());
+ let verify_kind_ty = var_data.normalize(self.tcx(), verify_kind_ty);
if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
continue;
}
}
pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
- freshen::TypeFreshener::new(self)
+ freshen::TypeFreshener::new(self, false)
+ }
+
+ /// Like `freshener`, but does not replace `'static` regions.
+ pub fn freshener_keep_static<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
+ freshen::TypeFreshener::new(self, true)
}
pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumeric {
tcx.reuse_or_mk_predicate(pred, new)
}
-struct PredicateSet<'tcx> {
+pub struct PredicateSet<'tcx> {
tcx: TyCtxt<'tcx>,
set: FxHashSet<ty::Predicate<'tcx>>,
}
impl PredicateSet<'tcx> {
- fn new(tcx: TyCtxt<'tcx>) -> Self {
+ pub fn new(tcx: TyCtxt<'tcx>) -> Self {
Self { tcx, set: Default::default() }
}
- fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool {
+ pub fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool {
// We have to be careful here because we want
//
// for<'a> Foo<&'a i32>
tracked!(merge_functions, Some(MergeFunctions::Disabled));
tracked!(mir_emit_retag, true);
tracked!(mir_opt_level, Some(4));
+ tracked!(move_size_limit, Some(4096));
tracked!(mutable_noalias, Some(true));
tracked!(new_llvm_pass_manager, Some(true));
tracked!(no_generate_arange_section, true);
}
fn check_crate(&mut self, cx: &LateContext<'_>, krate: &hir::Crate<'_>) {
- self.check_missing_docs_attrs(cx, hir::CRATE_HIR_ID, krate.item.inner, "the", "crate");
+ self.check_missing_docs_attrs(cx, hir::CRATE_HIR_ID, krate.module().inner, "the", "crate");
- for macro_def in krate.exported_macros {
+ for macro_def in krate.exported_macros() {
// Non exported macros should be skipped, since `missing_docs` only
// applies to externally visible items.
if !cx.access_levels.is_exported(macro_def.hir_id()) {
match level {
Level::Allow => "-A",
Level::Warn => "-W",
- Level::ForceWarn => "--force-warns",
+ Level::ForceWarn => "--force-warn",
Level::Deny => "-D",
Level::Forbid => "-F",
},
Applicability::MachineApplicable,
);
}
+ BuiltinLintDiagnostics::UnusedBuiltinAttribute {
+ attr_name,
+ macro_name,
+ invoc_span
+ } => {
+ db.span_note(
+ invoc_span,
+ &format!("the built-in attribute `{attr_name}` will be ignored, since it's applied to the macro invocation `{macro_name}`")
+ );
+ }
+ BuiltinLintDiagnostics::TrailingMacro(is_trailing, name) => {
+ if is_trailing {
+ db.note("macro invocations at the end of a block are treated as expressions");
+ db.note(&format!("to ignore the value produced by the macro, add a semicolon after the invocation of `{name}`"));
+ }
+ }
}
// Rewrap `db`, and pass control to the user.
decorate(LintDiagnosticBuilder::new(db));
let mut builder = LintLevelMapBuilder { levels, tcx, store };
let krate = tcx.hir().krate();
- builder.levels.id_to_set.reserve(krate.exported_macros.len() + 1);
+ builder.levels.id_to_set.reserve(krate.owners.len() + 1);
let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), &store, true);
builder.levels.register_id(hir::CRATE_HIR_ID);
- for macro_def in krate.exported_macros {
+ for macro_def in krate.exported_macros() {
builder.levels.register_id(macro_def.hir_id());
}
intravisit::walk_crate(&mut builder, krate);
#![feature(box_syntax)]
#![feature(box_patterns)]
#![feature(crate_visibility_modifier)]
+#![feature(format_args_capture)]
#![feature(iter_order_by)]
#![feature(iter_zip)]
#![feature(never_type)]
match self {
Level::Allow => "allow",
Level::Warn => "warn",
- Level::ForceWarn => "force-warns",
+ Level::ForceWarn => "force-warn",
Level::Deny => "deny",
Level::Forbid => "forbid",
}
DeprecatedMacro(Option<Symbol>, Span),
MissingAbi(Span, Abi),
UnusedDocComment(Span),
+ UnusedBuiltinAttribute { attr_name: Symbol, macro_name: String, invoc_span: Span },
PatternsInFnsWithoutBody(Span, Ident),
LegacyDeriveHelpers(Span),
ExternDepSpec(String, ExternDepSpec),
ProcMacroBackCompat(String),
OrPatternsBackCompat(Span, String),
ReservedPrefix(Span),
+ TrailingMacro(bool, Ident),
}
/// Lints that are buffered up early on in the `Session` before the
locator.triple
));
}
- if missing_core && std::env::var("RUSTUP_HOME").is_ok() {
+ // NOTE: this suggests using rustup, even though the user may not have it installed.
+ // That's because they could choose to install it; or this may give them a hint which
+ // target they need to install from their distro.
+ if missing_core {
err.help(&format!(
"consider downloading the target with `rustup target add {}`",
locator.triple
current_crate
));
}
- if sess.is_nightly_build() && std::env::var("CARGO").is_ok() {
+ if sess.is_nightly_build() {
err.help("consider building the standard library from source with `cargo build -Zbuild-std`");
}
} else if Some(crate_name)
fn encode_info_for_items(&mut self) {
let krate = self.tcx.hir().krate();
- self.encode_info_for_mod(CRATE_DEF_ID, &krate.item);
+ self.encode_info_for_mod(CRATE_DEF_ID, krate.module());
// Proc-macro crates only export proc-macro items, which are looked
// up using `proc_macro_data`
}
krate.visit_all_item_likes(&mut self.as_deep_visitor());
- for macro_def in krate.exported_macros {
+ for macro_def in krate.exported_macros() {
self.visit_macro_def(macro_def);
}
}
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::def_id::CRATE_DEF_INDEX;
+use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_hir::definitions;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::*;
arena: &'hir Arena<'hir>,
krate: &'hir Crate<'hir>,
definitions: &'a definitions::Definitions,
- mut hcx: StableHashingContext<'a>,
+ hcx: StableHashingContext<'a>,
) -> NodeCollector<'a, 'hir> {
- let hash = {
- let Crate {
- ref item,
- // These fields are handled separately:
- exported_macros: _,
- non_exported_macro_attrs: _,
- items: _,
- trait_items: _,
- impl_items: _,
- foreign_items: _,
- bodies: _,
- trait_impls: _,
- body_ids: _,
- modules: _,
- proc_macros: _,
- trait_map: _,
- attrs: _,
- } = *krate;
-
- hash_body(&mut hcx, item)
- };
-
let mut collector = NodeCollector {
arena,
krate,
source_map: sess.source_map(),
parent_node: hir::CRATE_HIR_ID,
- current_dep_node_owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
+ current_dep_node_owner: CRATE_DEF_ID,
definitions,
hcx,
map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()),
parenting: FxHashMap::default(),
};
- collector.insert_entry(
- hir::CRATE_HIR_ID,
- Entry { parent: hir::CRATE_HIR_ID, node: Node::Crate(&krate.item) },
- hash,
- );
+ collector.insert_owner(CRATE_DEF_ID, OwnerNode::Crate(krate.module()));
collector
}
IndexedHir { map: self.map, parenting: self.parenting }
}
- fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>, hash: Fingerprint) {
- let i = id.local_id.as_u32() as usize;
-
- let arena = self.arena;
+ fn insert_owner(&mut self, owner: LocalDefId, node: OwnerNode<'hir>) {
+ let hash = hash_body(&mut self.hcx, node);
- let data = &mut self.map[id.owner];
-
- if i == 0 {
- debug_assert!(data.is_none());
- *data = Some(arena.alloc(OwnerNodes {
- hash,
- nodes: IndexVec::new(),
- bodies: FxHashMap::default(),
- }));
-
- let dk_parent = self.definitions.def_key(id.owner).parent;
- if let Some(dk_parent) = dk_parent {
- let dk_parent = LocalDefId { local_def_index: dk_parent };
- let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent);
- if dk_parent.owner != entry.parent.owner {
- panic!(
- "Different parents for {:?} => dk_parent={:?} actual={:?}",
- id.owner, dk_parent, entry.parent,
- )
- }
+ let mut nodes = IndexVec::new();
+ nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: node.into() }));
- debug_assert_eq!(self.parenting.get(&id.owner), Some(&entry.parent));
- }
- } else {
- debug_assert_eq!(entry.parent.owner, id.owner);
- }
-
- let data = data.as_mut().unwrap();
-
- insert_vec_map(
- &mut data.nodes,
- id.local_id,
- ParentedNode { parent: entry.parent.local_id, node: entry.node },
- );
+ debug_assert!(self.map[owner].is_none());
+ self.map[owner] =
+ Some(self.arena.alloc(OwnerNodes { hash, nodes, bodies: FxHashMap::default() }));
}
fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
- self.insert_with_hash(span, hir_id, node, Fingerprint::ZERO)
- }
-
- fn insert_with_hash(&mut self, span: Span, hir_id: HirId, node: Node<'hir>, hash: Fingerprint) {
- let entry = Entry { parent: self.parent_node, node };
+ debug_assert_eq!(self.current_dep_node_owner, hir_id.owner);
+ debug_assert_ne!(hir_id.local_id.as_u32(), 0);
// Make sure that the DepNode of some node coincides with the HirId
// owner of that node.
}
}
- self.insert_entry(hir_id, entry, hash);
+ let nodes = self.map[hir_id.owner].as_mut().unwrap();
+
+ debug_assert_eq!(self.parent_node.owner, self.current_dep_node_owner);
+ insert_vec_map(
+ &mut nodes.nodes,
+ hir_id.local_id,
+ ParentedNode { parent: self.parent_node.local_id, node: node },
+ );
}
fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) {
self.parent_node = parent_node;
}
- fn with_dep_node_owner<
- T: for<'b> HashStable<StableHashingContext<'b>>,
- F: FnOnce(&mut Self, Fingerprint),
- >(
- &mut self,
- dep_node_owner: LocalDefId,
- item_like: &T,
- f: F,
- ) {
+ fn with_dep_node_owner(&mut self, dep_node_owner: LocalDefId, f: impl FnOnce(&mut Self)) {
let prev_owner = self.current_dep_node_owner;
- let hash = hash_body(&mut self.hcx, item_like);
+ let prev_parent = self.parent_node;
self.current_dep_node_owner = dep_node_owner;
- f(self, hash);
+ self.parent_node = HirId::make_owner(dep_node_owner);
+ f(self);
self.current_dep_node_owner = prev_owner;
+ self.parent_node = prev_parent;
}
fn insert_nested(&mut self, item: LocalDefId) {
fn visit_item(&mut self, i: &'hir Item<'hir>) {
debug!("visit_item: {:?}", i);
- self.with_dep_node_owner(i.def_id, i, |this, hash| {
- let hir_id = i.hir_id();
- this.insert_with_hash(i.span, hir_id, Node::Item(i), hash);
- this.with_parent(hir_id, |this| {
- if let ItemKind::Struct(ref struct_def, _) = i.kind {
- // If this is a tuple or unit-like struct, register the constructor.
- if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
- this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
- }
+ self.insert_owner(i.def_id, OwnerNode::Item(i));
+ self.with_dep_node_owner(i.def_id, |this| {
+ if let ItemKind::Struct(ref struct_def, _) = i.kind {
+ // If this is a tuple or unit-like struct, register the constructor.
+ if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
+ this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
}
- intravisit::walk_item(this, i);
- });
+ }
+ intravisit::walk_item(this, i);
});
}
fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
- self.with_dep_node_owner(fi.def_id, fi, |this, hash| {
- this.insert_with_hash(fi.span, fi.hir_id(), Node::ForeignItem(fi), hash);
-
- this.with_parent(fi.hir_id(), |this| {
- intravisit::walk_foreign_item(this, fi);
- });
+ self.insert_owner(fi.def_id, OwnerNode::ForeignItem(fi));
+ self.with_dep_node_owner(fi.def_id, |this| {
+ intravisit::walk_foreign_item(this, fi);
});
}
}
fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) {
- self.with_parent(param, |this| intravisit::walk_const_param_default(this, ct))
+ self.with_parent(param, |this| {
+ intravisit::walk_const_param_default(this, ct);
+ })
}
fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
- self.with_dep_node_owner(ti.def_id, ti, |this, hash| {
- this.insert_with_hash(ti.span, ti.hir_id(), Node::TraitItem(ti), hash);
-
- this.with_parent(ti.hir_id(), |this| {
- intravisit::walk_trait_item(this, ti);
- });
+ self.insert_owner(ti.def_id, OwnerNode::TraitItem(ti));
+ self.with_dep_node_owner(ti.def_id, |this| {
+ intravisit::walk_trait_item(this, ti);
});
}
fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
- self.with_dep_node_owner(ii.def_id, ii, |this, hash| {
- this.insert_with_hash(ii.span, ii.hir_id(), Node::ImplItem(ii), hash);
-
- this.with_parent(ii.hir_id(), |this| {
- intravisit::walk_impl_item(this, ii);
- });
+ self.insert_owner(ii.def_id, OwnerNode::ImplItem(ii));
+ self.with_dep_node_owner(ii.def_id, |this| {
+ intravisit::walk_impl_item(this, ii);
});
}
fn visit_local(&mut self, l: &'hir Local<'hir>) {
self.insert(l.span, l.hir_id, Node::Local(l));
- self.with_parent(l.hir_id, |this| intravisit::walk_local(this, l))
+ self.with_parent(l.hir_id, |this| {
+ intravisit::walk_local(this, l);
+ })
}
fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) {
let parent = def_key.parent.map_or(hir::CRATE_HIR_ID, |local_def_index| {
self.definitions.local_def_id_to_hir_id(LocalDefId { local_def_index })
});
+ self.insert_owner(macro_def.def_id, OwnerNode::MacroDef(macro_def));
self.with_parent(parent, |this| {
this.insert_nested(macro_def.def_id);
- this.with_dep_node_owner(macro_def.def_id, macro_def, |this, hash| {
- this.insert_with_hash(
- macro_def.span,
- macro_def.hir_id(),
- Node::MacroDef(macro_def),
- hash,
- );
- })
});
}
use self::collector::NodeCollector;
-use crate::hir::{AttributeMap, IndexedHir};
+use crate::hir::{AttributeMap, IndexedHir, Owner};
use crate::ty::TyCtxt;
use rustc_ast as ast;
use rustc_data_structures::fingerprint::Fingerprint;
Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
| Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. })
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, _), .. }) => Some(&sig.decl),
- Node::Expr(Expr { kind: ExprKind::Closure(_, fn_decl, ..), .. }) => Some(fn_decl),
+ Node::Expr(Expr { kind: ExprKind::Closure(_, fn_decl, ..), .. })
+ | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, ..), .. }) => {
+ Some(fn_decl)
+ }
_ => None,
}
}
}
impl<'hir> Iterator for ParentOwnerIterator<'_, 'hir> {
- type Item = (HirId, Node<'hir>);
+ type Item = (HirId, OwnerNode<'hir>);
fn next(&mut self) -> Option<Self::Item> {
if self.current_id.local_id.index() != 0 {
self.current_id.local_id = ItemLocalId::new(0);
- if let Some(node) = self.map.find(self.current_id) {
- return Some((self.current_id, node));
+ if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
+ return Some((self.current_id, node.node));
}
}
if self.current_id == CRATE_HIR_ID {
self.current_id = HirId::make_owner(parent_id);
// If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
- if let Some(node) = self.map.find(self.current_id) {
- return Some((self.current_id, node));
+ if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
+ return Some((self.current_id, node.node));
}
}
}
pub fn find(&self, id: HirId) -> Option<Node<'hir>> {
if id.local_id == ItemLocalId::from_u32(0) {
let owner = self.tcx.hir_owner(id.owner)?;
- Some(owner.node)
+ Some(owner.node.into())
} else {
let owner = self.tcx.hir_owner_nodes(id.owner)?;
let node = owner.nodes[id.local_id].as_ref()?;
}
pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
- self.get_if_local(id).and_then(|node| match &node {
- Node::ImplItem(impl_item) => Some(&impl_item.generics),
- Node::TraitItem(trait_item) => Some(&trait_item.generics),
- Node::Item(Item {
+ let id = id.as_local()?;
+ let node = self.tcx.hir_owner(id)?;
+ match node.node {
+ OwnerNode::ImplItem(impl_item) => Some(&impl_item.generics),
+ OwnerNode::TraitItem(trait_item) => Some(&trait_item.generics),
+ OwnerNode::Item(Item {
kind:
ItemKind::Fn(_, generics, _)
| ItemKind::TyAlias(_, generics)
..
}) => Some(generics),
_ => None,
- })
+ }
}
pub fn item(&self, id: ItemId) -> &'hir Item<'hir> {
- match self.find(id.hir_id()).unwrap() {
- Node::Item(item) => item,
- _ => bug!(),
- }
+ self.tcx.hir_owner(id.def_id).unwrap().node.expect_item()
}
pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
- match self.find(id.hir_id()).unwrap() {
- Node::TraitItem(item) => item,
- _ => bug!(),
- }
+ self.tcx.hir_owner(id.def_id).unwrap().node.expect_trait_item()
}
pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
- match self.find(id.hir_id()).unwrap() {
- Node::ImplItem(item) => item,
- _ => bug!(),
- }
+ self.tcx.hir_owner(id.def_id).unwrap().node.expect_impl_item()
}
pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
- match self.find(id.hir_id()).unwrap() {
- Node::ForeignItem(item) => item,
- _ => bug!(),
- }
+ self.tcx.hir_owner(id.def_id).unwrap().node.expect_foreign_item()
}
pub fn body(&self, id: BodyId) -> &'hir Body<'hir> {
}
pub fn get_module(&self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
- let hir_id = self.local_def_id_to_hir_id(module);
- match self.get(hir_id) {
- Node::Item(&Item { span, kind: ItemKind::Mod(ref m), .. }) => (m, span, hir_id),
- Node::Crate(item) => (&item, item.inner, hir_id),
+ let hir_id = HirId::make_owner(module);
+ match self.tcx.hir_owner(module).map(|o| o.node) {
+ Some(OwnerNode::Item(&Item { span, kind: ItemKind::Mod(ref m), .. })) => {
+ (m, span, hir_id)
+ }
+ Some(OwnerNode::Crate(item)) => (item, item.inner, hir_id),
node => panic!("not a module: {:?}", node),
}
}
where
V: Visitor<'hir>,
{
- for id in self.krate().exported_macros {
- visitor.visit_macro_def(self.expect_macro_def(id.hir_id()));
+ for macro_def in self.krate().exported_macros() {
+ visitor.visit_macro_def(macro_def);
}
}
/// in the HIR which is recorded by the map and is an item, either an item
/// in a module, trait, or impl.
pub fn get_parent_item(&self, hir_id: HirId) -> HirId {
- for (hir_id, node) in self.parent_owner_iter(hir_id) {
- if let Node::Crate(_)
- | Node::Item(_)
- | Node::ForeignItem(_)
- | Node::TraitItem(_)
- | Node::ImplItem(_) = node
- {
- return hir_id;
- }
+ if let Some((hir_id, _node)) = self.parent_owner_iter(hir_id).next() {
+ // A MacroDef does not have children.
+ debug_assert!(!matches!(_node, OwnerNode::MacroDef(_)));
+ hir_id
+ } else {
+ CRATE_HIR_ID
}
- CRATE_HIR_ID
}
/// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
/// module parent is in this map.
pub(super) fn get_module_parent_node(&self, hir_id: HirId) -> HirId {
for (hir_id, node) in self.parent_owner_iter(hir_id) {
- if let Node::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
+ if let OwnerNode::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
return hir_id;
}
}
pub fn get_foreign_abi(&self, hir_id: HirId) -> Abi {
let parent = self.get_parent_item(hir_id);
- if let Some(node) = self.find(parent) {
- if let Node::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node {
+ if let Some(node) = self.tcx.hir_owner(self.local_def_id(parent)) {
+ if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node.node
+ {
return *abi;
}
}
}
pub fn expect_item(&self, id: HirId) -> &'hir Item<'hir> {
- match self.find(id) {
- Some(Node::Item(item)) => item,
+ match self.tcx.hir_owner(id.expect_owner()) {
+ Some(Owner { node: OwnerNode::Item(item) }) => item,
_ => bug!("expected item, found {}", self.node_to_string(id)),
}
}
pub fn expect_impl_item(&self, id: HirId) -> &'hir ImplItem<'hir> {
- match self.find(id) {
- Some(Node::ImplItem(item)) => item,
+ match self.tcx.hir_owner(id.expect_owner()) {
+ Some(Owner { node: OwnerNode::ImplItem(item) }) => item,
_ => bug!("expected impl item, found {}", self.node_to_string(id)),
}
}
pub fn expect_trait_item(&self, id: HirId) -> &'hir TraitItem<'hir> {
- match self.find(id) {
- Some(Node::TraitItem(item)) => item,
+ match self.tcx.hir_owner(id.expect_owner()) {
+ Some(Owner { node: OwnerNode::TraitItem(item) }) => item,
_ => bug!("expected trait item, found {}", self.node_to_string(id)),
}
}
}
pub fn expect_foreign_item(&self, id: HirId) -> &'hir ForeignItem<'hir> {
- match self.find(id) {
- Some(Node::ForeignItem(item)) => item,
+ match self.tcx.hir_owner(id.expect_owner()) {
+ Some(Owner { node: OwnerNode::ForeignItem(item) }) => item,
_ => bug!("expected foreign item, found {}", self.node_to_string(id)),
}
}
pub fn expect_macro_def(&self, id: HirId) -> &'hir MacroDef<'hir> {
- match self.find(id) {
- Some(Node::MacroDef(macro_def)) => macro_def,
+ match self.tcx.hir_owner(id.expect_owner()) {
+ Some(Owner { node: OwnerNode::MacroDef(macro_def) }) => macro_def,
_ => bug!("expected macro def, found {}", self.node_to_string(id)),
}
}
pub fn node_to_string(&self, id: HirId) -> String {
hir_id_to_string(self, id)
}
+
+ /// 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_hir_id(&self, anon_const: HirId) -> Option<HirId> {
+ match self.get(self.get_parent_node(anon_const)) {
+ Node::GenericParam(GenericParam {
+ hir_id: param_id,
+ kind: GenericParamKind::Const { .. },
+ ..
+ }) => Some(*param_id),
+ _ => None,
+ }
+ }
}
impl<'hir> intravisit::Map<'hir> for Map<'hir> {
/// Top-level HIR node for current owner. This only contains the node for which
/// `HirId::local_id == 0`, and excludes bodies.
+///
+/// This struct exists to encapsulate all access to the hir_owner query in this module, and to
+/// implement HashStable without hashing bodies.
#[derive(Copy, Clone, Debug)]
pub struct Owner<'tcx> {
- node: Node<'tcx>,
+ node: OwnerNode<'tcx>,
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id];
providers.hir_owner = |tcx, id| {
let owner = tcx.index_hir(()).map[id].as_ref()?;
- let node = owner.nodes[ItemLocalId::new(0)].as_ref()?.node;
+ let node = owner.nodes[ItemLocalId::new(0)].as_ref().unwrap().node;
+ let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode.
Some(Owner { node })
};
providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].as_deref();
Level::Deny => "-D",
Level::Forbid => "-F",
Level::Allow => "-A",
- Level::ForceWarn => "--force-warns",
+ Level::ForceWarn => "--force-warn",
};
let hyphen_case_lint_name = name.replace("_", "-");
if lint_flag_val.as_str() == name {
pub fn provide(providers: &mut ty::query::Providers) {
providers.limits = |tcx, ()| Limits {
recursion_limit: get_recursion_limit(tcx.hir().krate_attrs(), tcx.sess),
- move_size_limit: get_limit(tcx.hir().krate_attrs(), tcx.sess, sym::move_size_limit, 0),
+ move_size_limit: get_limit(
+ tcx.hir().krate_attrs(),
+ tcx.sess,
+ sym::move_size_limit,
+ tcx.sess.opts.debugging_opts.move_size_limit.unwrap_or(0),
+ ),
type_length_limit: get_limit(
tcx.hir().krate_attrs(),
tcx.sess,
/// span) for an *existing* error. Therefore, it is best-effort, and may never handle
/// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine,
/// because the `ty::Ty`-based wfcheck is always run.
- query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, hir::HirId)) -> Option<traits::ObligationCause<'tcx>> {
+ query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, traits::WellFormedLoc)) -> Option<traits::ObligationCause<'tcx>> {
eval_always
no_hash
desc { "performing HIR wf-checking for predicate {:?} at item {:?}", key.0, key.1 }
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::Constness;
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
/// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y`
OpaqueType,
- /// Well-formed checking. If a `HirId` is provided,
- /// it is used to perform HIR-based wf checking if an error
- /// occurs, in order to generate a more precise error message.
+ /// Well-formed checking. If a `WellFormedLoc` is provided,
+ /// then it will be used to eprform HIR-based wf checking
+ /// after an error occurs, in order to generate a more precise error span.
/// This is purely for diagnostic purposes - it is always
- /// correct to use `MiscObligation` instead
- WellFormed(Option<hir::HirId>),
+ /// correct to use `MiscObligation` instead, or to specify
+ /// `WellFormed(None)`
+ WellFormed(Option<WellFormedLoc>),
/// From `match_impl`. The cause for us having to match an impl, and the DefId we are matching against.
MatchImpl(Lrc<ObligationCauseCode<'tcx>>, DefId),
}
+/// The 'location' at which we try to perform HIR-based wf checking.
+/// This information is used to obtain an `hir::Ty`, which
+/// we can walk in order to obtain precise spans for any
+/// 'nested' types (e.g. `Foo` in `Option<Foo>`).
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
+pub enum WellFormedLoc {
+ /// Use the type of the provided definition.
+ Ty(LocalDefId),
+ /// Use the type of the parameter of the provided function.
+ /// We cannot use `hir::Param`, since the function may
+ /// not have a body (e.g. a trait method definition)
+ Param {
+ /// The function to lookup the parameter in
+ function: LocalDefId,
+ /// The index of the parameter to use.
+ /// Parameters are indexed from 0, with the return type
+ /// being the last 'parameter'
+ param_idx: u16,
+ },
+}
+
impl ObligationCauseCode<'_> {
// Return the base obligation, ignoring derived obligations.
pub fn peel_derives(&self) -> &Self {
&self,
name: Symbol,
) -> impl '_ + Iterator<Item = &ty::AssocItem> {
- self.items.get_by_key(&name).copied()
+ self.items.get_by_key(name).copied()
}
/// Returns an iterator over all associated items with the given name.
// This is the impl for `&'a InternalSubsts<'a>`.
nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>}
-CloneLiftImpls! { for<'tcx> { Constness, } }
+CloneLiftImpls! { for<'tcx> { Constness, traits::WellFormedLoc, } }
pub mod tls {
use super::{ptr_eq, GlobalCtxt, TyCtxt};
assoc_substs,
ty,
msg,
+ false,
) {
return true;
}
assoc_substs,
ty,
msg,
+ false,
);
}
}
) -> bool {
let assoc = self.associated_item(proj_ty.item_def_id);
if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
- self.constrain_associated_type_structured_suggestion(
+ let opaque_local_def_id = def_id.expect_local();
+ let opaque_hir_id = self.hir().local_def_id_to_hir_id(opaque_local_def_id);
+ let opaque_hir_ty = match &self.hir().expect_item(opaque_hir_id).kind {
+ hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
+ _ => bug!("The HirId comes from a `ty::Opaque`"),
+ };
+
+ let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
+
+ self.constrain_generic_bound_associated_type_structured_suggestion(
db,
- self.def_span(def_id),
- &assoc,
- proj_ty.trait_ref_and_own_substs(self).1,
+ &trait_ref,
+ opaque_hir_ty.bounds,
+ assoc,
+ assoc_substs,
ty,
- &msg,
+ msg,
+ true,
)
} else {
false
/// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
/// requirement, provide a structured suggestion to constrain it to a given type `ty`.
+ ///
+ /// `is_bound_surely_present` indicates whether we know the bound we're looking for is
+ /// inside `bounds`. If that's the case then we can consider `bounds` containing only one
+ /// trait bound as the one we're looking for. This can help in cases where the associated
+ /// type is defined on a supertrait of the one present in the bounds.
fn constrain_generic_bound_associated_type_structured_suggestion(
self,
db: &mut DiagnosticBuilder<'_>,
assoc_substs: &[ty::GenericArg<'tcx>],
ty: Ty<'tcx>,
msg: &str,
+ is_bound_surely_present: bool,
) -> bool {
// FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
- bounds.iter().any(|bound| match bound {
- hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => {
- // Relate the type param against `T` in `<A as T>::Foo`.
- ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
- && self.constrain_associated_type_structured_suggestion(
- db,
- ptr.span,
- assoc,
- assoc_substs,
- ty,
- msg,
- )
- }
- _ => false,
- })
+
+ let trait_bounds = bounds.iter().filter_map(|bound| match bound {
+ hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr),
+ _ => None,
+ });
+
+ let matching_trait_bounds = trait_bounds
+ .clone()
+ .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id))
+ .collect::<Vec<_>>();
+
+ let span = match &matching_trait_bounds[..] {
+ &[ptr] => ptr.span,
+ &[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] {
+ &[ptr] => ptr.span,
+ _ => return false,
+ },
+ _ => return false,
+ };
+
+ self.constrain_associated_type_structured_suggestion(db, span, assoc, assoc_substs, ty, msg)
}
/// Given a span corresponding to a bound, provide a structured suggestion to set an
}
}
+/// Folds through bound vars and placeholders, naming them
+struct RegionFolder<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ current_index: ty::DebruijnIndex,
+ region_map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
+ name: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
+}
+
+impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
+ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_binder<T: TypeFoldable<'tcx>>(
+ &mut self,
+ t: ty::Binder<'tcx, T>,
+ ) -> ty::Binder<'tcx, T> {
+ self.current_index.shift_in(1);
+ let t = t.super_fold_with(self);
+ self.current_index.shift_out(1);
+ t
+ }
+
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ match *t.kind() {
+ _ if t.has_vars_bound_at_or_above(self.current_index) || t.has_placeholders() => {
+ return t.super_fold_with(self);
+ }
+ _ => {}
+ }
+ t
+ }
+
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ let name = &mut self.name;
+ let region = match *r {
+ ty::ReLateBound(_, br) => self.region_map.entry(br).or_insert_with(|| name(br)),
+ ty::RePlaceholder(ty::PlaceholderRegion { name: kind, .. }) => {
+ // If this is an anonymous placeholder, don't rename. Otherwise, in some
+ // async fns, we get a `for<'r> Send` bound
+ match kind {
+ ty::BrAnon(_) | ty::BrEnv => r,
+ _ => {
+ // Index doesn't matter, since this is just for naming and these never get bound
+ let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
+ self.region_map.entry(br).or_insert_with(|| name(br))
+ }
+ }
+ }
+ _ => return r,
+ };
+ if let ty::ReLateBound(debruijn1, br) = *region {
+ assert_eq!(debruijn1, ty::INNERMOST);
+ self.tcx.mk_region(ty::ReLateBound(self.current_index, br))
+ } else {
+ region
+ }
+ }
+}
+
// HACK(eddyb) limited to `FmtPrinter` because of `binder_depth`,
// `region_index` and `used_region_names`.
impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
pub fn name_all_regions<T>(
mut self,
value: &ty::Binder<'tcx, T>,
- ) -> Result<(Self, (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)), fmt::Error>
+ ) -> Result<(Self, T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>), fmt::Error>
where
T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>,
{
let mut empty = true;
let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
- write!(
- cx,
- "{}",
- if empty {
- empty = false;
- start
- } else {
- cont
- }
- )
+ let w = if empty {
+ empty = false;
+ start
+ } else {
+ cont
+ };
+ let _ = write!(cx, "{}", w);
+ };
+ let do_continue = |cx: &mut Self, cont: Symbol| {
+ let _ = write!(cx, "{}", cont);
};
define_scoped_cx!(self);
// aren't named. Eventually, we might just want this as the default, but
// this is not *quite* right and changes the ordering of some output
// anyways.
- let new_value = if self.tcx().sess.verbose() {
+ let (new_value, map) = if self.tcx().sess.verbose() {
// anon index + 1 (BrEnv takes 0) -> name
let mut region_map: BTreeMap<u32, Symbol> = BTreeMap::default();
let bound_vars = value.bound_vars();
for var in bound_vars {
match var {
ty::BoundVariableKind::Region(ty::BrNamed(_, name)) => {
- let _ = start_or_continue(&mut self, "for<", ", ");
- let _ = write!(self, "{}", name);
+ start_or_continue(&mut self, "for<", ", ");
+ do_continue(&mut self, name);
}
ty::BoundVariableKind::Region(ty::BrAnon(i)) => {
- let _ = start_or_continue(&mut self, "for<", ", ");
+ start_or_continue(&mut self, "for<", ", ");
let name = loop {
let name = name_by_region_index(region_index);
region_index += 1;
break name;
}
};
- let _ = write!(self, "{}", name);
+ do_continue(&mut self, name);
region_map.insert(i + 1, name);
}
ty::BoundVariableKind::Region(ty::BrEnv) => {
- let _ = start_or_continue(&mut self, "for<", ", ");
+ start_or_continue(&mut self, "for<", ", ");
let name = loop {
let name = name_by_region_index(region_index);
region_index += 1;
break name;
}
};
- let _ = write!(self, "{}", name);
+ do_continue(&mut self, name);
region_map.insert(0, name);
}
_ => continue,
}
}
- start_or_continue(&mut self, "", "> ")?;
+ start_or_continue(&mut self, "", "> ");
self.tcx.replace_late_bound_regions(value.clone(), |br| {
let kind = match br.kind {
))
})
} else {
- let new_value = self.tcx.replace_late_bound_regions(value.clone(), |br| {
- let _ = start_or_continue(&mut self, "for<", ", ");
+ let tcx = self.tcx;
+ let mut name = |br: ty::BoundRegion| {
+ start_or_continue(&mut self, "for<", ", ");
let kind = match br.kind {
ty::BrNamed(_, name) => {
- let _ = write!(self, "{}", name);
+ do_continue(&mut self, name);
br.kind
}
ty::BrAnon(_) | ty::BrEnv => {
break name;
}
};
- let _ = write!(self, "{}", name);
+ do_continue(&mut self, name);
ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
}
};
- self.tcx.mk_region(ty::ReLateBound(
- ty::INNERMOST,
- ty::BoundRegion { var: br.var, kind },
- ))
- });
- start_or_continue(&mut self, "", "> ")?;
- new_value
+ tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
+ };
+ let mut folder = RegionFolder {
+ tcx,
+ current_index: ty::INNERMOST,
+ name: &mut name,
+ region_map: BTreeMap::new(),
+ };
+ let new_value = value.clone().skip_binder().fold_with(&mut folder);
+ let region_map = folder.region_map;
+ start_or_continue(&mut self, "", "> ");
+ (new_value, region_map)
};
self.binder_depth += 1;
self.region_index = region_index;
- Ok((self, new_value))
+ Ok((self, new_value, map))
}
pub fn pretty_in_binder<T>(self, value: &ty::Binder<'tcx, T>) -> Result<Self, fmt::Error>
T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>,
{
let old_region_index = self.region_index;
- let (new, new_value) = self.name_all_regions(value)?;
- let mut inner = new_value.0.print(new)?;
+ let (new, new_value, _) = self.name_all_regions(value)?;
+ let mut inner = new_value.print(new)?;
inner.region_index = old_region_index;
inner.binder_depth -= 1;
Ok(inner)
T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>,
{
let old_region_index = self.region_index;
- let (new, new_value) = self.name_all_regions(value)?;
- let mut inner = f(&new_value.0, new)?;
+ let (new, new_value, _) = self.name_all_regions(value)?;
+ let mut inner = f(&new_value, new)?;
inner.region_index = old_region_index;
inner.binder_depth -= 1;
Ok(inner)
debug!("LateBoundRegionNameCollector::visit_region(r: {:?}, address: {:p})", r, &r);
if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r {
self.used_region_names.insert(name);
+ } else if let ty::RePlaceholder(ty::PlaceholderRegion {
+ name: ty::BrNamed(_, name),
+ ..
+ }) = *r
+ {
+ self.used_region_names.insert(name);
}
r.super_visit_with(self)
}
fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, Namespace, DefId)) {
// Iterate all local crate items no matter where they are defined.
let hir = tcx.hir();
- for item in hir.krate().items.values() {
+ for item in hir.krate().items() {
if item.ident.name.as_str().is_empty() || matches!(item.kind, ItemKind::Use(_, _)) {
continue;
}
use std::convert::TryFrom;
+use std::fmt;
use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar, ScalarMaybeUninit};
-use crate::ty::fold::TypeFoldable;
-use crate::ty::{self, DefId, SubstsRef, Ty, TyCtxt};
+use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
use rustc_ast::Mutability;
-#[derive(Clone, Copy, Debug, PartialEq, HashStable)]
+#[derive(Clone, Copy, PartialEq, HashStable)]
pub enum VtblEntry<'tcx> {
+ /// destructor of this type (used in vtable header)
MetadataDropInPlace,
+ /// layout size of this type (used in vtable header)
MetadataSize,
+ /// layout align of this type (used in vtable header)
MetadataAlign,
+ /// non-dispatchable associated function that is excluded from trait object
Vacant,
- Method(DefId, SubstsRef<'tcx>),
+ /// dispatchable associated function
+ Method(Instance<'tcx>),
+ /// pointer to a separate supertrait vtable, can be used by trait upcasting coercion
+ TraitVPtr(PolyTraitRef<'tcx>),
+}
+
+impl<'tcx> fmt::Debug for VtblEntry<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // We want to call `Display` on `Instance` and `PolyTraitRef`,
+ // so we implement this manually.
+ match self {
+ VtblEntry::MetadataDropInPlace => write!(f, "MetadataDropInPlace"),
+ VtblEntry::MetadataSize => write!(f, "MetadataSize"),
+ VtblEntry::MetadataAlign => write!(f, "MetadataAlign"),
+ VtblEntry::Vacant => write!(f, "Vacant"),
+ VtblEntry::Method(instance) => write!(f, "Method({})", instance),
+ VtblEntry::TraitVPtr(trait_ref) => write!(f, "TraitVPtr({})", trait_ref),
+ }
+ }
}
pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] =
}
drop(vtables_cache);
- // See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674
- assert!(
- !ty.needs_subst() && !poly_trait_ref.map_or(false, |trait_ref| trait_ref.needs_subst())
- );
- let param_env = ty::ParamEnv::reveal_all();
let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
let trait_ref = tcx.erase_regions(trait_ref);
COMMON_VTABLE_ENTRIES
};
- let layout =
- tcx.layout_of(param_env.and(ty)).expect("failed to build vtable representation");
+ let layout = tcx
+ .layout_of(ty::ParamEnv::reveal_all().and(ty))
+ .expect("failed to build vtable representation");
assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
let size = layout.size.bytes();
let align = layout.align.abi.bytes();
VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(),
VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(),
VtblEntry::Vacant => continue,
- VtblEntry::Method(def_id, substs) => {
- // See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674
- assert!(!substs.needs_subst());
-
+ VtblEntry::Method(instance) => {
// Prepare the fn ptr we write into the vtable.
- let instance =
- ty::Instance::resolve_for_vtable(tcx, param_env, *def_id, substs)
- .expect("resolution failed during building vtable representation")
- .polymorphize(tcx);
+ let instance = instance.polymorphize(tcx);
let fn_alloc_id = tcx.create_fn_alloc(instance);
let fn_ptr = Pointer::from(fn_alloc_id);
ScalarMaybeUninit::from_pointer(fn_ptr, &tcx)
}
+ VtblEntry::TraitVPtr(trait_ref) => {
+ let super_trait_ref = trait_ref.map_bound(|trait_ref| {
+ ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
+ });
+ let supertrait_alloc_id = self.vtable_allocation(ty, Some(super_trait_ref));
+ let vptr = Pointer::from(supertrait_alloc_id);
+ ScalarMaybeUninit::from_pointer(vptr, &tcx)
+ }
};
vtable
.write_scalar(&tcx, alloc_range(ptr_size * idx, ptr_size), scalar)
Some(c) if c.is_whitespace() => true,
// e.g. `&mut(x)`
Some('(') => true,
+ // e.g. `&mut{x}`
+ Some('{') => true,
// e.g. `&mutablevar`
_ => false,
}
false
}
};
- if let (true, Some(ws_pos)) =
- (src.starts_with("&'"), src.find(|c: char| -> bool { c.is_whitespace() }))
- {
+ if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) {
let lt_name = &src[1..ws_pos];
let ty = src[ws_pos..].trim_start();
if !is_mutbl(ty) {
};
if let Ok(src) = tcx.sess.source_map().span_to_snippet(highlight_span) {
- if let (true, Some(ws_pos)) =
- (src.starts_with("&'"), src.find(|c: char| -> bool { c.is_whitespace() }))
- {
+ if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) {
let lt_name = &src[1..ws_pos];
let ty = &src[ws_pos..];
return (highlight_span, format!("&{} mut{}", lt_name, ty));
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef, UserSubsts};
+use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
use rustc_middle::ty::{
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness,
LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
},
region_infer::{ClosureRegionRequirementsExt, TypeTest},
- renumber,
type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
universal_regions::{DefiningTy, UniversalRegions},
Upvar,
liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
translate_outlives_facts(&mut cx);
- cx.opaque_type_values
+ let mut opaque_type_values = cx.opaque_type_values;
+
+ for (_, revealed_ty) in &mut opaque_type_values {
+ *revealed_ty = infcx.resolve_vars_if_possible(*revealed_ty);
+ if revealed_ty.has_infer_types_or_consts() {
+ infcx.tcx.sess.delay_span_bug(
+ body.span,
+ &format!("could not resolve {:#?}", revealed_ty.kind()),
+ );
+ *revealed_ty = infcx.tcx.ty_error();
+ }
+ }
+
+ opaque_type_values.retain(|(opaque_type_key, resolved_ty)| {
+ let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() {
+ *def_id == opaque_type_key.def_id
+ } else {
+ false
+ };
+
+ if concrete_is_opaque {
+ // We're using an opaque `impl Trait` type without
+ // 'revealing' it. For example, code like this:
+ //
+ // type Foo = impl Debug;
+ // fn foo1() -> Foo { ... }
+ // fn foo2() -> Foo { foo1() }
+ //
+ // In `foo2`, we're not revealing the type of `Foo` - we're
+ // just treating it as the opaque type.
+ //
+ // When this occurs, we do *not* want to try to equate
+ // the concrete type with the underlying defining type
+ // of the opaque type - this will always fail, since
+ // the defining type of an opaque type is always
+ // some other type (e.g. not itself)
+ // Essentially, none of the normal obligations apply here -
+ // we're just passing around some unknown opaque type,
+ // without actually looking at the underlying type it
+ // gets 'revealed' into
+ debug!(
+ "eq_opaque_type_and_type: non-defining use of {:?}",
+ opaque_type_key.def_id,
+ );
+ }
+ !concrete_is_opaque
+ });
+ opaque_type_values
},
);
return Ok(());
}
- let infcx = self.infcx;
- let tcx = infcx.tcx;
let param_env = self.param_env;
let body = self.body;
let mir_def_id = body.source.def_id().expect_local();
- // the "concrete opaque types" maps
- let concrete_opaque_types = &tcx.typeck(mir_def_id).concrete_opaque_types;
let mut opaque_type_values = VecMap::new();
debug!("eq_opaque_type_and_type: mir_def_id={:?}", mir_def_id);
.eq(output_ty, revealed_ty)?,
);
- // For each opaque type `Foo<T>` inferred by this value, we want to equate
- // the inference variable `?T` with the revealed type that was computed
- // earlier by type check.
for &(opaque_type_key, opaque_decl) in &opaque_type_map {
- let resolved_ty = infcx.resolve_vars_if_possible(opaque_decl.concrete_ty);
- let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() {
- *def_id == opaque_type_key.def_id
- } else {
- false
- };
-
- // The revealed type computed by the earlier phase of type check.
- // In our example, this would be `(U, u32)`. Note that this references
- // the type parameter `U` from the definition of `Foo`.
- let concrete_ty = match concrete_opaque_types
- .get_by(|(key, _)| key.def_id == opaque_type_key.def_id)
- {
- None => {
- if !concrete_is_opaque {
- tcx.sess.delay_span_bug(
- body.span,
- &format!(
- "Non-defining use of {:?} with revealed type",
- opaque_type_key.def_id,
- ),
- );
- }
- continue;
- }
- Some(concrete_ty) => concrete_ty,
- };
- debug!("concrete_ty = {:?}", concrete_ty);
-
- // Apply the substitution, in this case `[U -> T]`, so that the
- // concrete type becomes `Foo<(T, u32)>`
- let subst_opaque_defn_ty = concrete_ty.subst(tcx, opaque_type_key.substs);
-
- // "Renumber" this, meaning that we replace all the regions
- // with fresh inference variables. Not relevant to our example.
- let renumbered_opaque_defn_ty =
- renumber::renumber_regions(infcx, subst_opaque_defn_ty);
-
- debug!(
- "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}",
- concrete_ty, resolved_ty, renumbered_opaque_defn_ty,
- );
-
- if !concrete_is_opaque {
- // Equate the instantiated opaque type `opaque_decl.concrete_ty` (`?T`,
- // in our example) with the renumbered version that we took from
- // the type check results (`Foo<(T, u32)>`).
- obligations.add(
- infcx
- .at(&ObligationCause::dummy(), param_env)
- .eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?,
- );
- opaque_type_values.insert(opaque_type_key, renumbered_opaque_defn_ty);
- } else {
- // We're using an opaque `impl Trait` type without
- // 'revealing' it. For example, code like this:
- //
- // type Foo = impl Debug;
- // fn foo1() -> Foo { ... }
- // fn foo2() -> Foo { foo1() }
- //
- // In `foo2`, we're not revealing the type of `Foo` - we're
- // just treating it as the opaque type.
- //
- // When this occurs, we do *not* want to try to equate
- // the concrete type with the underlying defining type
- // of the opaque type - this will always fail, since
- // the defining type of an opaque type is always
- // some other type (e.g. not itself)
- // Essentially, none of the normal obligations apply here -
- // we're just passing around some unknown opaque type,
- // without actually looking at the underlying type it
- // gets 'revealed' into
- debug!(
- "eq_opaque_type_and_type: non-defining use of {:?}",
- opaque_type_key.def_id,
- );
- }
+ opaque_type_values.insert(opaque_type_key, opaque_decl.concrete_ty);
}
debug!("eq_opaque_type_and_type: equated");
locations,
ConstraintCategory::OpaqueType,
CustomTypeOp::new(
- |_cx| {
+ |infcx| {
infcx.constrain_opaque_type(
opaque_type_key,
&opaque_decl,
Err(ptr) => ptr.into(),
Ok(bits) => {
let addr = u64::try_from(bits).unwrap();
- M::ptr_from_addr(&self, addr)
+ let ptr = M::ptr_from_addr(&self, addr);
+ if addr == 0 {
+ assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId");
+ }
+ ptr
}
}
}
#![feature(in_band_lifetimes)]
#![feature(array_windows)]
#![feature(assert_matches)]
-#![feature(bindings_after_at)]
+#![cfg_attr(bootstrap, feature(bindings_after_at))]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
| VtblEntry::MetadataSize
| VtblEntry::MetadataAlign
| VtblEntry::Vacant => None,
- VtblEntry::Method(def_id, substs) => ty::Instance::resolve_for_vtable(
- tcx,
- ty::ParamEnv::reveal_all(),
- *def_id,
- substs,
- )
- .filter(|instance| should_codegen_locally(tcx, instance)),
+ VtblEntry::TraitVPtr(_) => {
+ // all super trait items already covered, so skip them.
+ None
+ }
+ VtblEntry::Method(instance) => {
+ Some(*instance).filter(|instance| should_codegen_locally(tcx, instance))
+ }
})
.map(|item| create_fn_mono_item(tcx, item, source));
output.extend(methods);
--- /dev/null
+//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
+
+use rustc_errors::{Applicability, Diagnostic, ErrorReported};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, HirId, LangItem};
+use rustc_index::bit_set::BitSet;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
+use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
+use rustc_middle::mir::*;
+use rustc_middle::ty::cast::CastTy;
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
+use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
+use rustc_span::{sym, Span, Symbol};
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+use rustc_trait_selection::traits::{self, SelectionContext, TraitEngine};
+
+use std::mem;
+use std::ops::Deref;
+
+use super::ops::{self, NonConstOp, Status};
+use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
+use super::resolver::FlowSensitiveAnalysis;
+use super::{is_lang_panic_fn, ConstCx, Qualif};
+use crate::const_eval::is_unstable_const_fn;
+use crate::dataflow::impls::MaybeMutBorrowedLocals;
+use crate::dataflow::{self, Analysis};
+
+// We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated
+// through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals`
+// kills locals upon `StorageDead` because a local will never be used after a `StorageDead`.
+type IndirectlyMutableResults<'mir, 'tcx> =
+ dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>;
+
+type QualifResults<'mir, 'tcx, Q> =
+ dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
+
+#[derive(Default)]
+pub struct Qualifs<'mir, 'tcx> {
+ has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
+ needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
+ indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>,
+}
+
+impl Qualifs<'mir, 'tcx> {
+ pub fn indirectly_mutable(
+ &mut self,
+ ccx: &'mir ConstCx<'mir, 'tcx>,
+ local: Local,
+ location: Location,
+ ) -> bool {
+ let indirectly_mutable = self.indirectly_mutable.get_or_insert_with(|| {
+ let ConstCx { tcx, body, param_env, .. } = *ccx;
+
+ // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
+ // allowed in a const.
+ //
+ // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
+ // without breaking stable code?
+ MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env)
+ .unsound_ignore_borrow_on_drop()
+ .into_engine(tcx, &body)
+ .pass_name("const_qualification")
+ .iterate_to_fixpoint()
+ .into_results_cursor(&body)
+ });
+
+ indirectly_mutable.seek_before_primary_effect(location);
+ indirectly_mutable.get().contains(local)
+ }
+
+ /// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
+ ///
+ /// Only updates the cursor if absolutely necessary
+ pub fn needs_drop(
+ &mut self,
+ ccx: &'mir ConstCx<'mir, 'tcx>,
+ local: Local,
+ location: Location,
+ ) -> bool {
+ let ty = ccx.body.local_decls[local].ty;
+ if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
+ return false;
+ }
+
+ let needs_drop = self.needs_drop.get_or_insert_with(|| {
+ let ConstCx { tcx, body, .. } = *ccx;
+
+ FlowSensitiveAnalysis::new(NeedsDrop, ccx)
+ .into_engine(tcx, &body)
+ .iterate_to_fixpoint()
+ .into_results_cursor(&body)
+ });
+
+ needs_drop.seek_before_primary_effect(location);
+ needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+ }
+
+ /// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
+ ///
+ /// Only updates the cursor if absolutely necessary.
+ pub fn has_mut_interior(
+ &mut self,
+ ccx: &'mir ConstCx<'mir, 'tcx>,
+ local: Local,
+ location: Location,
+ ) -> bool {
+ let ty = ccx.body.local_decls[local].ty;
+ if !HasMutInterior::in_any_value_of_ty(ccx, ty) {
+ return false;
+ }
+
+ let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| {
+ let ConstCx { tcx, body, .. } = *ccx;
+
+ FlowSensitiveAnalysis::new(HasMutInterior, ccx)
+ .into_engine(tcx, &body)
+ .iterate_to_fixpoint()
+ .into_results_cursor(&body)
+ });
+
+ has_mut_interior.seek_before_primary_effect(location);
+ has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+ }
+
+ fn in_return_place(
+ &mut self,
+ ccx: &'mir ConstCx<'mir, 'tcx>,
+ error_occured: Option<ErrorReported>,
+ ) -> ConstQualifs {
+ // Find the `Return` terminator if one exists.
+ //
+ // If no `Return` terminator exists, this MIR is divergent. Just return the conservative
+ // qualifs for the return type.
+ let return_block = ccx
+ .body
+ .basic_blocks()
+ .iter_enumerated()
+ .find(|(_, block)| match block.terminator().kind {
+ TerminatorKind::Return => true,
+ _ => false,
+ })
+ .map(|(bb, _)| bb);
+
+ let return_block = match return_block {
+ None => return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), error_occured),
+ Some(bb) => bb,
+ };
+
+ let return_loc = ccx.body.terminator_loc(return_block);
+
+ let custom_eq = match ccx.const_kind() {
+ // We don't care whether a `const fn` returns a value that is not structurally
+ // matchable. Functions calls are opaque and always use type-based qualification, so
+ // this value should never be used.
+ hir::ConstContext::ConstFn => true,
+
+ // If we know that all values of the return type are structurally matchable, there's no
+ // need to run dataflow.
+ _ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false,
+
+ hir::ConstContext::Const | hir::ConstContext::Static(_) => {
+ let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
+ .into_engine(ccx.tcx, &ccx.body)
+ .iterate_to_fixpoint()
+ .into_results_cursor(&ccx.body);
+
+ cursor.seek_after_primary_effect(return_loc);
+ cursor.contains(RETURN_PLACE)
+ }
+ };
+
+ ConstQualifs {
+ needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
+ has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
+ custom_eq,
+ error_occured,
+ }
+ }
+}
+
+pub struct Checker<'mir, 'tcx> {
+ ccx: &'mir ConstCx<'mir, 'tcx>,
+ qualifs: Qualifs<'mir, 'tcx>,
+
+ /// The span of the current statement.
+ span: Span,
+
+ /// A set that stores for each local whether it has a `StorageDead` for it somewhere.
+ local_has_storage_dead: Option<BitSet<Local>>,
+
+ error_emitted: Option<ErrorReported>,
+ secondary_errors: Vec<Diagnostic>,
+}
+
+impl Deref for Checker<'mir, 'tcx> {
+ type Target = ConstCx<'mir, 'tcx>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.ccx
+ }
+}
+
+impl Checker<'mir, 'tcx> {
+ pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
+ Checker {
+ span: ccx.body.span,
+ ccx,
+ qualifs: Default::default(),
+ local_has_storage_dead: None,
+ error_emitted: None,
+ secondary_errors: Vec::new(),
+ }
+ }
+
+ pub fn check_body(&mut self) {
+ let ConstCx { tcx, body, .. } = *self.ccx;
+ let def_id = self.ccx.def_id();
+
+ // `async` functions cannot be `const fn`. This is checked during AST lowering, so there's
+ // no need to emit duplicate errors here.
+ if is_async_fn(self.ccx) || body.generator.is_some() {
+ tcx.sess.delay_span_bug(body.span, "`async` functions cannot be `const fn`");
+ return;
+ }
+
+ // The local type and predicate checks are not free and only relevant for `const fn`s.
+ if self.const_kind() == hir::ConstContext::ConstFn {
+ // Prevent const trait methods from being annotated as `stable`.
+ // FIXME: Do this as part of stability checking.
+ if self.is_const_stable_const_fn() {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) {
+ self.ccx
+ .tcx
+ .sess
+ .struct_span_err(self.span, "trait methods cannot be stable const fn")
+ .emit();
+ }
+ }
+
+ self.check_item_predicates();
+
+ for (idx, local) in body.local_decls.iter_enumerated() {
+ // Handle the return place below.
+ if idx == RETURN_PLACE || local.internal {
+ continue;
+ }
+
+ self.span = local.source_info.span;
+ self.check_local_or_return_ty(local.ty, idx);
+ }
+
+ // impl trait is gone in MIR, so check the return type of a const fn by its signature
+ // instead of the type of the return place.
+ self.span = body.local_decls[RETURN_PLACE].source_info.span;
+ let return_ty = tcx.fn_sig(def_id).output();
+ self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
+ }
+
+ self.visit_body(&body);
+
+ // Ensure that the end result is `Sync` in a non-thread local `static`.
+ let should_check_for_sync = self.const_kind()
+ == hir::ConstContext::Static(hir::Mutability::Not)
+ && !tcx.is_thread_local_static(def_id.to_def_id());
+
+ if should_check_for_sync {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ check_return_ty_is_sync(tcx, &body, hir_id);
+ }
+
+ // If we got through const-checking without emitting any "primary" errors, emit any
+ // "secondary" errors if they occurred.
+ let secondary_errors = mem::take(&mut self.secondary_errors);
+ if self.error_emitted.is_none() {
+ for error in secondary_errors {
+ self.tcx.sess.diagnostic().emit_diagnostic(&error);
+ }
+ } else {
+ assert!(self.tcx.sess.has_errors());
+ }
+ }
+
+ fn local_has_storage_dead(&mut self, local: Local) -> bool {
+ let ccx = self.ccx;
+ self.local_has_storage_dead
+ .get_or_insert_with(|| {
+ struct StorageDeads {
+ locals: BitSet<Local>,
+ }
+ impl Visitor<'tcx> for StorageDeads {
+ fn visit_statement(&mut self, stmt: &Statement<'tcx>, _: Location) {
+ if let StatementKind::StorageDead(l) = stmt.kind {
+ self.locals.insert(l);
+ }
+ }
+ }
+ let mut v = StorageDeads { locals: BitSet::new_empty(ccx.body.local_decls.len()) };
+ v.visit_body(ccx.body);
+ v.locals
+ })
+ .contains(local)
+ }
+
+ pub fn qualifs_in_return_place(&mut self) -> ConstQualifs {
+ self.qualifs.in_return_place(self.ccx, self.error_emitted)
+ }
+
+ /// Emits an error if an expression cannot be evaluated in the current context.
+ pub fn check_op(&mut self, op: impl NonConstOp) {
+ self.check_op_spanned(op, self.span);
+ }
+
+ /// Emits an error at the given `span` if an expression cannot be evaluated in the current
+ /// context.
+ pub fn check_op_spanned<O: NonConstOp>(&mut self, op: O, span: Span) {
+ let gate = match op.status_in_item(self.ccx) {
+ Status::Allowed => return,
+
+ Status::Unstable(gate) if self.tcx.features().enabled(gate) => {
+ let unstable_in_stable = self.ccx.is_const_stable_const_fn()
+ && !super::rustc_allow_const_fn_unstable(
+ self.tcx,
+ self.def_id().to_def_id(),
+ gate,
+ );
+ if unstable_in_stable {
+ emit_unstable_in_stable_error(self.ccx, span, gate);
+ }
+
+ return;
+ }
+
+ Status::Unstable(gate) => Some(gate),
+ Status::Forbidden => None,
+ };
+
+ if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
+ self.tcx.sess.miri_unleashed_feature(span, gate);
+ return;
+ }
+
+ let mut err = op.build_error(self.ccx, span);
+ assert!(err.is_error());
+
+ match op.importance() {
+ ops::DiagnosticImportance::Primary => {
+ self.error_emitted = Some(ErrorReported);
+ err.emit();
+ }
+
+ ops::DiagnosticImportance::Secondary => err.buffer(&mut self.secondary_errors),
+ }
+ }
+
+ fn check_static(&mut self, def_id: DefId, span: Span) {
+ if self.tcx.is_thread_local_static(def_id) {
+ self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef");
+ }
+ self.check_op_spanned(ops::StaticAccess, span)
+ }
+
+ fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) {
+ let kind = self.body.local_kind(local);
+
+ for ty in ty.walk() {
+ let ty = match ty.unpack() {
+ GenericArgKind::Type(ty) => ty,
+
+ // No constraints on lifetimes or constants, except potentially
+ // constants' types, but `walk` will get to them as well.
+ GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue,
+ };
+
+ match *ty.kind() {
+ ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef(kind)),
+ ty::Opaque(..) => self.check_op(ops::ty::ImplTrait),
+ ty::FnPtr(..) => self.check_op(ops::ty::FnPtr(kind)),
+
+ ty::Dynamic(preds, _) => {
+ for pred in preds.iter() {
+ match pred.skip_binder() {
+ ty::ExistentialPredicate::AutoTrait(_)
+ | ty::ExistentialPredicate::Projection(_) => {
+ self.check_op(ops::ty::TraitBound(kind))
+ }
+ ty::ExistentialPredicate::Trait(trait_ref) => {
+ if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() {
+ self.check_op(ops::ty::TraitBound(kind))
+ }
+ }
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+
+ fn check_item_predicates(&mut self) {
+ let ConstCx { tcx, .. } = *self.ccx;
+
+ let mut current = self.def_id().to_def_id();
+ loop {
+ let predicates = tcx.predicates_of(current);
+ for (predicate, _) in predicates.predicates {
+ match predicate.kind().skip_binder() {
+ ty::PredicateKind::RegionOutlives(_)
+ | ty::PredicateKind::TypeOutlives(_)
+ | ty::PredicateKind::WellFormed(_)
+ | ty::PredicateKind::Projection(_)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
+ ty::PredicateKind::ObjectSafe(_) => {
+ bug!("object safe predicate on function: {:#?}", predicate)
+ }
+ ty::PredicateKind::ClosureKind(..) => {
+ bug!("closure kind predicate on function: {:#?}", predicate)
+ }
+ ty::PredicateKind::Subtype(_) => {
+ bug!("subtype predicate on function: {:#?}", predicate)
+ }
+ ty::PredicateKind::Trait(pred, _constness) => {
+ if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
+ continue;
+ }
+ match pred.self_ty().kind() {
+ ty::Param(p) => {
+ let generics = tcx.generics_of(current);
+ let def = generics.type_param(p, tcx);
+ let span = tcx.def_span(def.def_id);
+
+ // These are part of the function signature, so treat them like
+ // arguments when determining importance.
+ let kind = LocalKind::Arg;
+
+ self.check_op_spanned(ops::ty::TraitBound(kind), span);
+ }
+ // other kinds of bounds are either tautologies
+ // or cause errors in other passes
+ _ => continue,
+ }
+ }
+ }
+ }
+ match predicates.parent {
+ Some(parent) => current = parent,
+ None => break,
+ }
+ }
+ }
+
+ fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) {
+ match self.const_kind() {
+ // In a const fn all borrows are transient or point to the places given via
+ // references in the arguments (so we already checked them with
+ // TransientMutBorrow/MutBorrow as appropriate).
+ // The borrow checker guarantees that no new non-transient borrows are created.
+ // NOTE: Once we have heap allocations during CTFE we need to figure out
+ // how to prevent `const fn` to create long-lived allocations that point
+ // to mutable memory.
+ hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)),
+ _ => {
+ // Locals with StorageDead do not live beyond the evaluation and can
+ // thus safely be borrowed without being able to be leaked to the final
+ // value of the constant.
+ if self.local_has_storage_dead(local) {
+ self.check_op(ops::TransientMutBorrow(kind));
+ } else {
+ self.check_op(ops::MutBorrow(kind));
+ }
+ }
+ }
+ }
+}
+
+impl Visitor<'tcx> for Checker<'mir, 'tcx> {
+ fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &BasicBlockData<'tcx>) {
+ trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup);
+
+ // We don't const-check basic blocks on the cleanup path since we never unwind during
+ // const-eval: a panic causes an immediate compile error. In other words, cleanup blocks
+ // are unreachable during const-eval.
+ //
+ // We can't be more conservative (e.g., by const-checking cleanup blocks anyways) because
+ // locals that would never be dropped during normal execution are sometimes dropped during
+ // unwinding, which means backwards-incompatible live-drop errors.
+ if block.is_cleanup {
+ return;
+ }
+
+ self.super_basic_block_data(bb, block);
+ }
+
+ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
+ trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
+
+ // Special-case reborrows to be more like a copy of a reference.
+ match *rvalue {
+ Rvalue::Ref(_, kind, place) => {
+ if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) {
+ let ctx = match kind {
+ BorrowKind::Shared => {
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
+ }
+ BorrowKind::Shallow => {
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
+ }
+ BorrowKind::Unique => {
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow)
+ }
+ BorrowKind::Mut { .. } => {
+ PlaceContext::MutatingUse(MutatingUseContext::Borrow)
+ }
+ };
+ self.visit_local(&reborrowed_place_ref.local, ctx, location);
+ self.visit_projection(reborrowed_place_ref, ctx, location);
+ return;
+ }
+ }
+ Rvalue::AddressOf(mutbl, place) => {
+ if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) {
+ let ctx = match mutbl {
+ Mutability::Not => {
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
+ }
+ Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf),
+ };
+ self.visit_local(&reborrowed_place_ref.local, ctx, location);
+ self.visit_projection(reborrowed_place_ref, ctx, location);
+ return;
+ }
+ }
+ _ => {}
+ }
+
+ self.super_rvalue(rvalue, location);
+
+ match *rvalue {
+ Rvalue::ThreadLocalRef(_) => self.check_op(ops::ThreadLocalAccess),
+
+ Rvalue::Use(_)
+ | Rvalue::Repeat(..)
+ | Rvalue::Discriminant(..)
+ | Rvalue::Len(_)
+ | Rvalue::Aggregate(..) => {}
+
+ Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, ref place)
+ | Rvalue::Ref(_, kind @ BorrowKind::Unique, ref place) => {
+ let ty = place.ty(self.body, self.tcx).ty;
+ let is_allowed = match ty.kind() {
+ // Inside a `static mut`, `&mut [...]` is allowed.
+ ty::Array(..) | ty::Slice(_)
+ if self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut) =>
+ {
+ true
+ }
+
+ // FIXME(ecstaticmorse): We could allow `&mut []` inside a const context given
+ // that this is merely a ZST and it is already eligible for promotion.
+ // This may require an RFC?
+ /*
+ ty::Array(_, len) if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0)
+ => true,
+ */
+ _ => false,
+ };
+
+ if !is_allowed {
+ if let BorrowKind::Mut { .. } = kind {
+ self.check_mut_borrow(place.local, hir::BorrowKind::Ref)
+ } else {
+ self.check_op(ops::CellBorrow);
+ }
+ }
+ }
+
+ Rvalue::AddressOf(Mutability::Mut, ref place) => {
+ self.check_mut_borrow(place.local, hir::BorrowKind::Raw)
+ }
+
+ Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, ref place)
+ | Rvalue::AddressOf(Mutability::Not, ref place) => {
+ let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
+ &self.ccx,
+ &mut |local| self.qualifs.has_mut_interior(self.ccx, local, location),
+ place.as_ref(),
+ );
+
+ if borrowed_place_has_mut_interior {
+ match self.const_kind() {
+ // In a const fn all borrows are transient or point to the places given via
+ // references in the arguments (so we already checked them with
+ // TransientCellBorrow/CellBorrow as appropriate).
+ // The borrow checker guarantees that no new non-transient borrows are created.
+ // NOTE: Once we have heap allocations during CTFE we need to figure out
+ // how to prevent `const fn` to create long-lived allocations that point
+ // to (interior) mutable memory.
+ hir::ConstContext::ConstFn => self.check_op(ops::TransientCellBorrow),
+ _ => {
+ // Locals with StorageDead are definitely not part of the final constant value, and
+ // it is thus inherently safe to permit such locals to have their
+ // address taken as we can't end up with a reference to them in the
+ // final value.
+ // Note: This is only sound if every local that has a `StorageDead` has a
+ // `StorageDead` in every control flow path leading to a `return` terminator.
+ if self.local_has_storage_dead(place.local) {
+ self.check_op(ops::TransientCellBorrow);
+ } else {
+ self.check_op(ops::CellBorrow);
+ }
+ }
+ }
+ }
+ }
+
+ Rvalue::Cast(
+ CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
+ _,
+ _,
+ ) => {}
+
+ Rvalue::Cast(
+ CastKind::Pointer(
+ PointerCast::UnsafeFnPointer
+ | PointerCast::ClosureFnPointer(_)
+ | PointerCast::ReifyFnPointer,
+ ),
+ _,
+ _,
+ ) => self.check_op(ops::FnPtrCast),
+
+ Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
+ // Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur
+ // in the type of any local, which also excludes casts).
+ }
+
+ Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
+ let operand_ty = operand.ty(self.body, self.tcx);
+ let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
+ let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
+
+ if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
+ self.check_op(ops::RawPtrToIntCast);
+ }
+ }
+
+ Rvalue::NullaryOp(NullOp::SizeOf, _) => {}
+ Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation),
+
+ Rvalue::UnaryOp(_, ref operand) => {
+ let ty = operand.ty(self.body, self.tcx);
+ if is_int_bool_or_char(ty) {
+ // Int, bool, and char operations are fine.
+ } else if ty.is_floating_point() {
+ self.check_op(ops::FloatingPointOp);
+ } else {
+ span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty);
+ }
+ }
+
+ Rvalue::BinaryOp(op, box (ref lhs, ref rhs))
+ | Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => {
+ let lhs_ty = lhs.ty(self.body, self.tcx);
+ let rhs_ty = rhs.ty(self.body, self.tcx);
+
+ if is_int_bool_or_char(lhs_ty) && is_int_bool_or_char(rhs_ty) {
+ // Int, bool, and char operations are fine.
+ } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() {
+ assert_eq!(lhs_ty, rhs_ty);
+ assert!(
+ op == BinOp::Eq
+ || op == BinOp::Ne
+ || op == BinOp::Le
+ || op == BinOp::Lt
+ || op == BinOp::Ge
+ || op == BinOp::Gt
+ || op == BinOp::Offset
+ );
+
+ self.check_op(ops::RawPtrComparison);
+ } else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() {
+ self.check_op(ops::FloatingPointOp);
+ } else {
+ span_bug!(
+ self.span,
+ "non-primitive type in `Rvalue::BinaryOp`: {:?} ⚬ {:?}",
+ lhs_ty,
+ rhs_ty
+ );
+ }
+ }
+ }
+ }
+
+ fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
+ self.super_operand(op, location);
+ if let Operand::Constant(c) = op {
+ if let Some(def_id) = c.check_static_ptr(self.tcx) {
+ self.check_static(def_id, self.span);
+ }
+ }
+ }
+ fn visit_projection_elem(
+ &mut self,
+ place_local: Local,
+ proj_base: &[PlaceElem<'tcx>],
+ elem: PlaceElem<'tcx>,
+ context: PlaceContext,
+ location: Location,
+ ) {
+ trace!(
+ "visit_projection_elem: place_local={:?} proj_base={:?} elem={:?} \
+ context={:?} location={:?}",
+ place_local,
+ proj_base,
+ elem,
+ context,
+ location,
+ );
+
+ self.super_projection_elem(place_local, proj_base, elem, context, location);
+
+ match elem {
+ ProjectionElem::Deref => {
+ let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
+ if let ty::RawPtr(_) = base_ty.kind() {
+ if proj_base.is_empty() {
+ let decl = &self.body.local_decls[place_local];
+ if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
+ let span = decl.source_info.span;
+ self.check_static(def_id, span);
+ return;
+ }
+ }
+ self.check_op(ops::RawPtrDeref);
+ }
+
+ if context.is_mutating_use() {
+ self.check_op(ops::MutDeref);
+ }
+ }
+
+ ProjectionElem::ConstantIndex { .. }
+ | ProjectionElem::Downcast(..)
+ | ProjectionElem::Subslice { .. }
+ | ProjectionElem::Field(..)
+ | ProjectionElem::Index(_) => {
+ let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
+ if base_ty.is_union() {
+ self.check_op(ops::UnionAccess);
+ }
+ }
+ }
+ }
+
+ fn visit_source_info(&mut self, source_info: &SourceInfo) {
+ trace!("visit_source_info: source_info={:?}", source_info);
+ self.span = source_info.span;
+ }
+
+ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
+ trace!("visit_statement: statement={:?} location={:?}", statement, location);
+
+ self.super_statement(statement, location);
+
+ match statement.kind {
+ StatementKind::LlvmInlineAsm { .. } => {
+ self.check_op(ops::InlineAsm);
+ }
+
+ StatementKind::Assign(..)
+ | StatementKind::SetDiscriminant { .. }
+ | StatementKind::FakeRead(..)
+ | StatementKind::StorageLive(_)
+ | StatementKind::StorageDead(_)
+ | StatementKind::Retag { .. }
+ | StatementKind::AscribeUserType(..)
+ | StatementKind::Coverage(..)
+ | StatementKind::CopyNonOverlapping(..)
+ | StatementKind::Nop => {}
+ }
+ }
+
+ #[instrument(level = "debug", skip(self))]
+ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+ use rustc_target::spec::abi::Abi::RustIntrinsic;
+
+ self.super_terminator(terminator, location);
+
+ match &terminator.kind {
+ TerminatorKind::Call { func, args, .. } => {
+ let ConstCx { tcx, body, param_env, .. } = *self.ccx;
+ let caller = self.def_id().to_def_id();
+
+ let fn_ty = func.ty(body, tcx);
+
+ let (mut callee, substs) = match *fn_ty.kind() {
+ ty::FnDef(def_id, substs) => (def_id, substs),
+
+ ty::FnPtr(_) => {
+ self.check_op(ops::FnCallIndirect);
+ return;
+ }
+ _ => {
+ span_bug!(terminator.source_info.span, "invalid callee of type {:?}", fn_ty)
+ }
+ };
+
+ // Attempting to call a trait method?
+ if let Some(trait_id) = tcx.trait_of_item(callee) {
+ trace!("attempting to call a trait method");
+ if !self.tcx.features().const_trait_impl {
+ self.check_op(ops::FnCallNonConst);
+ return;
+ }
+
+ let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
+ let obligation = Obligation::new(
+ ObligationCause::dummy(),
+ param_env,
+ Binder::dummy(TraitPredicate { trait_ref }),
+ );
+
+ let implsrc = tcx.infer_ctxt().enter(|infcx| {
+ let mut selcx = SelectionContext::new(&infcx);
+ selcx.select(&obligation).unwrap()
+ });
+
+ // If the method is provided via a where-clause that does not use the `?const`
+ // opt-out, the call is allowed.
+ if let Some(ImplSource::Param(_, hir::Constness::Const)) = implsrc {
+ debug!(
+ "const_trait_impl: provided {:?} via where-clause in {:?}",
+ trait_ref, param_env
+ );
+ return;
+ }
+
+ // Resolve a trait method call to its concrete implementation, which may be in a
+ // `const` trait impl.
+ let instance = Instance::resolve(tcx, param_env, callee, substs);
+ debug!("Resolving ({:?}) -> {:?}", callee, instance);
+ if let Ok(Some(func)) = instance {
+ if let InstanceDef::Item(def) = func.def {
+ callee = def.did;
+ }
+ }
+ }
+
+ // At this point, we are calling a function, `callee`, whose `DefId` is known...
+ if is_lang_panic_fn(tcx, callee) {
+ self.check_op(ops::Panic);
+
+ // const-eval of the `begin_panic` fn assumes the argument is `&str`
+ if Some(callee) == tcx.lang_items().begin_panic_fn() {
+ match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
+ ty::Ref(_, ty, _) if ty.is_str() => (),
+ _ => self.check_op(ops::PanicNonStr),
+ }
+ }
+
+ return;
+ }
+
+ // `async` blocks get lowered to `std::future::from_generator(/* a closure */)`.
+ let is_async_block = Some(callee) == tcx.lang_items().from_generator_fn();
+ if is_async_block {
+ let kind = hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block);
+ self.check_op(ops::Generator(kind));
+ return;
+ }
+
+ let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;
+
+ // HACK: This is to "unstabilize" the `transmute` intrinsic
+ // within const fns. `transmute` is allowed in all other const contexts.
+ // This won't really scale to more intrinsics or functions. Let's allow const
+ // transmutes in const fn before we add more hacks to this.
+ if is_intrinsic && tcx.item_name(callee) == sym::transmute {
+ self.check_op(ops::Transmute);
+ return;
+ }
+
+ if !tcx.is_const_fn_raw(callee) {
+ let mut permitted = false;
+
+ let callee_trait = tcx.trait_of_item(callee);
+ if let Some(trait_id) = callee_trait {
+ if tcx.has_attr(caller, sym::default_method_body_is_const) {
+ // permit call to non-const fn when caller has default_method_body_is_const..
+ if tcx.trait_of_item(caller) == callee_trait {
+ // ..and caller and callee are in the same trait.
+ permitted = true;
+ }
+ }
+ if !permitted {
+ // if trait's impls are all const, permit the call.
+ let mut const_impls = true;
+ tcx.for_each_relevant_impl(trait_id, substs.type_at(0), |imp| {
+ if const_impls {
+ if let hir::Constness::NotConst = tcx.impl_constness(imp) {
+ const_impls = false;
+ }
+ }
+ });
+ if const_impls {
+ permitted = true;
+ }
+ }
+ }
+
+ if !permitted {
+ self.check_op(ops::FnCallNonConst);
+ return;
+ }
+ }
+
+ // If the `const fn` we are trying to call is not const-stable, ensure that we have
+ // the proper feature gate enabled.
+ if let Some(gate) = is_unstable_const_fn(tcx, callee) {
+ trace!(?gate, "calling unstable const fn");
+ if self.span.allows_unstable(gate) {
+ return;
+ }
+
+ // Calling an unstable function *always* requires that the corresponding gate
+ // be enabled, even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`.
+ if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) {
+ self.check_op(ops::FnCallUnstable(callee, Some(gate)));
+ return;
+ }
+
+ // If this crate is not using stability attributes, or the caller is not claiming to be a
+ // stable `const fn`, that is all that is required.
+ if !self.ccx.is_const_stable_const_fn() {
+ trace!("crate not using stability attributes or caller not stably const");
+ return;
+ }
+
+ // Otherwise, we are something const-stable calling a const-unstable fn.
+
+ if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
+ trace!("rustc_allow_const_fn_unstable gate active");
+ return;
+ }
+
+ self.check_op(ops::FnCallUnstable(callee, Some(gate)));
+ return;
+ }
+
+ // FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that
+ // have no `rustc_const_stable` attributes to be const-unstable as well. This
+ // should be fixed later.
+ let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
+ && tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable());
+ if callee_is_unstable_unmarked {
+ trace!("callee_is_unstable_unmarked");
+ // We do not use `const` modifiers for intrinsic "functions", as intrinsics are
+ // `extern` funtions, and these have no way to get marked `const`. So instead we
+ // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
+ if self.ccx.is_const_stable_const_fn() || is_intrinsic {
+ self.check_op(ops::FnCallUnstable(callee, None));
+ return;
+ }
+ }
+ trace!("permitting call");
+ }
+
+ // Forbid all `Drop` terminators unless the place being dropped is a local with no
+ // projections that cannot be `NeedsDrop`.
+ TerminatorKind::Drop { place: dropped_place, .. }
+ | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
+ // If we are checking live drops after drop-elaboration, don't emit duplicate
+ // errors here.
+ if super::post_drop_elaboration::checking_enabled(self.ccx) {
+ return;
+ }
+
+ let mut err_span = self.span;
+
+ // Check to see if the type of this place can ever have a drop impl. If not, this
+ // `Drop` terminator is frivolous.
+ let ty_needs_drop =
+ dropped_place.ty(self.body, self.tcx).ty.needs_drop(self.tcx, self.param_env);
+
+ if !ty_needs_drop {
+ return;
+ }
+
+ let needs_drop = if let Some(local) = dropped_place.as_local() {
+ // Use the span where the local was declared as the span of the drop error.
+ err_span = self.body.local_decls[local].source_info.span;
+ self.qualifs.needs_drop(self.ccx, local, location)
+ } else {
+ true
+ };
+
+ if needs_drop {
+ self.check_op_spanned(
+ ops::LiveDrop { dropped_at: Some(terminator.source_info.span) },
+ err_span,
+ );
+ }
+ }
+
+ TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
+
+ TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
+ self.check_op(ops::Generator(hir::GeneratorKind::Gen))
+ }
+
+ TerminatorKind::Abort => {
+ // Cleanup blocks are skipped for const checking (see `visit_basic_block_data`).
+ span_bug!(self.span, "`Abort` terminator outside of cleanup block")
+ }
+
+ TerminatorKind::Assert { .. }
+ | TerminatorKind::FalseEdge { .. }
+ | TerminatorKind::FalseUnwind { .. }
+ | TerminatorKind::Goto { .. }
+ | TerminatorKind::Resume
+ | TerminatorKind::Return
+ | TerminatorKind::SwitchInt { .. }
+ | TerminatorKind::Unreachable => {}
+ }
+ }
+}
+
+fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) {
+ let ty = body.return_ty();
+ tcx.infer_ctxt().enter(|infcx| {
+ let cause = traits::ObligationCause::new(body.span, hir_id, traits::SharedStatic);
+ let mut fulfillment_cx = traits::FulfillmentContext::new();
+ let sync_def_id = tcx.require_lang_item(LangItem::Sync, Some(body.span));
+ fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause);
+ if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
+ infcx.report_fulfillment_errors(&err, None, false);
+ }
+ });
+}
+
+fn place_as_reborrow(
+ tcx: TyCtxt<'tcx>,
+ body: &Body<'tcx>,
+ place: Place<'tcx>,
+) -> Option<PlaceRef<'tcx>> {
+ match place.as_ref().last_projection() {
+ Some((place_base, ProjectionElem::Deref)) => {
+ // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
+ // that points to the allocation for the static. Don't treat these as reborrows.
+ if body.local_decls[place_base.local].is_ref_to_static() {
+ None
+ } else {
+ // Ensure the type being derefed is a reference and not a raw pointer.
+ // This is sufficient to prevent an access to a `static mut` from being marked as a
+ // reborrow, even if the check above were to disappear.
+ let inner_ty = place_base.ty(body, tcx).ty;
+
+ if let ty::Ref(..) = inner_ty.kind() {
+ return Some(place_base);
+ } else {
+ return None;
+ }
+ }
+ }
+ _ => None,
+ }
+}
+
+fn is_int_bool_or_char(ty: Ty<'_>) -> bool {
+ ty.is_bool() || ty.is_integral() || ty.is_char()
+}
+
+fn is_async_fn(ccx: &ConstCx<'_, '_>) -> bool {
+ ccx.fn_sig().map_or(false, |sig| sig.header.asyncness == hir::IsAsync::Async)
+}
+
+fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) {
+ let attr_span = ccx.fn_sig().map_or(ccx.body.span, |sig| sig.span.shrink_to_lo());
+
+ ccx.tcx
+ .sess
+ .struct_span_err(
+ span,
+ &format!("const-stable function cannot use `#[feature({})]`", gate.as_str()),
+ )
+ .span_suggestion(
+ attr_span,
+ "if it is not part of the public API, make this function unstably const",
+ concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(),
+ Applicability::HasPlaceholders,
+ )
+ .span_suggestion(
+ attr_span,
+ "otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks",
+ format!("#[rustc_allow_const_fn_unstable({})]\n", gate),
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+}
pub use self::qualifs::Qualif;
+pub mod check;
mod ops;
pub mod post_drop_elaboration;
pub mod qualifs;
mod resolver;
-pub mod validation;
/// Information about the item currently being const-checked, as well as a reference to the global
/// context.
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;
+use super::check::Qualifs;
use super::ops::{self, NonConstOp};
use super::qualifs::{NeedsDrop, Qualif};
-use super::validation::Qualifs;
use super::ConstCx;
/// Returns `true` if we should use the more precise live drop checker that runs after drop
+++ /dev/null
-//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
-
-use rustc_errors::{Applicability, Diagnostic, ErrorReported};
-use rustc_hir::def_id::DefId;
-use rustc_hir::{self as hir, HirId, LangItem};
-use rustc_index::bit_set::BitSet;
-use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
-use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::*;
-use rustc_middle::ty::cast::CastTy;
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
-use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
-use rustc_span::{sym, Span, Symbol};
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
-use rustc_trait_selection::traits::{self, SelectionContext, TraitEngine};
-
-use std::mem;
-use std::ops::Deref;
-
-use super::ops::{self, NonConstOp, Status};
-use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
-use super::resolver::FlowSensitiveAnalysis;
-use super::{is_lang_panic_fn, ConstCx, Qualif};
-use crate::const_eval::is_unstable_const_fn;
-use crate::dataflow::impls::MaybeMutBorrowedLocals;
-use crate::dataflow::{self, Analysis};
-
-// We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated
-// through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals`
-// kills locals upon `StorageDead` because a local will never be used after a `StorageDead`.
-type IndirectlyMutableResults<'mir, 'tcx> =
- dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>;
-
-type QualifResults<'mir, 'tcx, Q> =
- dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
-
-#[derive(Default)]
-pub struct Qualifs<'mir, 'tcx> {
- has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
- needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
- indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>,
-}
-
-impl Qualifs<'mir, 'tcx> {
- pub fn indirectly_mutable(
- &mut self,
- ccx: &'mir ConstCx<'mir, 'tcx>,
- local: Local,
- location: Location,
- ) -> bool {
- let indirectly_mutable = self.indirectly_mutable.get_or_insert_with(|| {
- let ConstCx { tcx, body, param_env, .. } = *ccx;
-
- // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
- // allowed in a const.
- //
- // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
- // without breaking stable code?
- MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env)
- .unsound_ignore_borrow_on_drop()
- .into_engine(tcx, &body)
- .pass_name("const_qualification")
- .iterate_to_fixpoint()
- .into_results_cursor(&body)
- });
-
- indirectly_mutable.seek_before_primary_effect(location);
- indirectly_mutable.get().contains(local)
- }
-
- /// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
- ///
- /// Only updates the cursor if absolutely necessary
- pub fn needs_drop(
- &mut self,
- ccx: &'mir ConstCx<'mir, 'tcx>,
- local: Local,
- location: Location,
- ) -> bool {
- let ty = ccx.body.local_decls[local].ty;
- if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
- return false;
- }
-
- let needs_drop = self.needs_drop.get_or_insert_with(|| {
- let ConstCx { tcx, body, .. } = *ccx;
-
- FlowSensitiveAnalysis::new(NeedsDrop, ccx)
- .into_engine(tcx, &body)
- .iterate_to_fixpoint()
- .into_results_cursor(&body)
- });
-
- needs_drop.seek_before_primary_effect(location);
- needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
- }
-
- /// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
- ///
- /// Only updates the cursor if absolutely necessary.
- pub fn has_mut_interior(
- &mut self,
- ccx: &'mir ConstCx<'mir, 'tcx>,
- local: Local,
- location: Location,
- ) -> bool {
- let ty = ccx.body.local_decls[local].ty;
- if !HasMutInterior::in_any_value_of_ty(ccx, ty) {
- return false;
- }
-
- let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| {
- let ConstCx { tcx, body, .. } = *ccx;
-
- FlowSensitiveAnalysis::new(HasMutInterior, ccx)
- .into_engine(tcx, &body)
- .iterate_to_fixpoint()
- .into_results_cursor(&body)
- });
-
- has_mut_interior.seek_before_primary_effect(location);
- has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location)
- }
-
- fn in_return_place(
- &mut self,
- ccx: &'mir ConstCx<'mir, 'tcx>,
- error_occured: Option<ErrorReported>,
- ) -> ConstQualifs {
- // Find the `Return` terminator if one exists.
- //
- // If no `Return` terminator exists, this MIR is divergent. Just return the conservative
- // qualifs for the return type.
- let return_block = ccx
- .body
- .basic_blocks()
- .iter_enumerated()
- .find(|(_, block)| match block.terminator().kind {
- TerminatorKind::Return => true,
- _ => false,
- })
- .map(|(bb, _)| bb);
-
- let return_block = match return_block {
- None => return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), error_occured),
- Some(bb) => bb,
- };
-
- let return_loc = ccx.body.terminator_loc(return_block);
-
- let custom_eq = match ccx.const_kind() {
- // We don't care whether a `const fn` returns a value that is not structurally
- // matchable. Functions calls are opaque and always use type-based qualification, so
- // this value should never be used.
- hir::ConstContext::ConstFn => true,
-
- // If we know that all values of the return type are structurally matchable, there's no
- // need to run dataflow.
- _ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false,
-
- hir::ConstContext::Const | hir::ConstContext::Static(_) => {
- let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
- .into_engine(ccx.tcx, &ccx.body)
- .iterate_to_fixpoint()
- .into_results_cursor(&ccx.body);
-
- cursor.seek_after_primary_effect(return_loc);
- cursor.contains(RETURN_PLACE)
- }
- };
-
- ConstQualifs {
- needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
- has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
- custom_eq,
- error_occured,
- }
- }
-}
-
-pub struct Validator<'mir, 'tcx> {
- ccx: &'mir ConstCx<'mir, 'tcx>,
- qualifs: Qualifs<'mir, 'tcx>,
-
- /// The span of the current statement.
- span: Span,
-
- /// A set that stores for each local whether it has a `StorageDead` for it somewhere.
- local_has_storage_dead: Option<BitSet<Local>>,
-
- error_emitted: Option<ErrorReported>,
- secondary_errors: Vec<Diagnostic>,
-}
-
-impl Deref for Validator<'mir, 'tcx> {
- type Target = ConstCx<'mir, 'tcx>;
-
- fn deref(&self) -> &Self::Target {
- &self.ccx
- }
-}
-
-impl Validator<'mir, 'tcx> {
- pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
- Validator {
- span: ccx.body.span,
- ccx,
- qualifs: Default::default(),
- local_has_storage_dead: None,
- error_emitted: None,
- secondary_errors: Vec::new(),
- }
- }
-
- pub fn check_body(&mut self) {
- let ConstCx { tcx, body, .. } = *self.ccx;
- let def_id = self.ccx.def_id();
-
- // `async` functions cannot be `const fn`. This is checked during AST lowering, so there's
- // no need to emit duplicate errors here.
- if is_async_fn(self.ccx) || body.generator.is_some() {
- tcx.sess.delay_span_bug(body.span, "`async` functions cannot be `const fn`");
- return;
- }
-
- // The local type and predicate checks are not free and only relevant for `const fn`s.
- if self.const_kind() == hir::ConstContext::ConstFn {
- // Prevent const trait methods from being annotated as `stable`.
- // FIXME: Do this as part of stability checking.
- if self.is_const_stable_const_fn() {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) {
- self.ccx
- .tcx
- .sess
- .struct_span_err(self.span, "trait methods cannot be stable const fn")
- .emit();
- }
- }
-
- self.check_item_predicates();
-
- for (idx, local) in body.local_decls.iter_enumerated() {
- // Handle the return place below.
- if idx == RETURN_PLACE || local.internal {
- continue;
- }
-
- self.span = local.source_info.span;
- self.check_local_or_return_ty(local.ty, idx);
- }
-
- // impl trait is gone in MIR, so check the return type of a const fn by its signature
- // instead of the type of the return place.
- self.span = body.local_decls[RETURN_PLACE].source_info.span;
- let return_ty = tcx.fn_sig(def_id).output();
- self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
- }
-
- self.visit_body(&body);
-
- // Ensure that the end result is `Sync` in a non-thread local `static`.
- let should_check_for_sync = self.const_kind()
- == hir::ConstContext::Static(hir::Mutability::Not)
- && !tcx.is_thread_local_static(def_id.to_def_id());
-
- if should_check_for_sync {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- check_return_ty_is_sync(tcx, &body, hir_id);
- }
-
- // If we got through const-checking without emitting any "primary" errors, emit any
- // "secondary" errors if they occurred.
- let secondary_errors = mem::take(&mut self.secondary_errors);
- if self.error_emitted.is_none() {
- for error in secondary_errors {
- self.tcx.sess.diagnostic().emit_diagnostic(&error);
- }
- } else {
- assert!(self.tcx.sess.has_errors());
- }
- }
-
- fn local_has_storage_dead(&mut self, local: Local) -> bool {
- let ccx = self.ccx;
- self.local_has_storage_dead
- .get_or_insert_with(|| {
- struct StorageDeads {
- locals: BitSet<Local>,
- }
- impl Visitor<'tcx> for StorageDeads {
- fn visit_statement(&mut self, stmt: &Statement<'tcx>, _: Location) {
- if let StatementKind::StorageDead(l) = stmt.kind {
- self.locals.insert(l);
- }
- }
- }
- let mut v = StorageDeads { locals: BitSet::new_empty(ccx.body.local_decls.len()) };
- v.visit_body(ccx.body);
- v.locals
- })
- .contains(local)
- }
-
- pub fn qualifs_in_return_place(&mut self) -> ConstQualifs {
- self.qualifs.in_return_place(self.ccx, self.error_emitted)
- }
-
- /// Emits an error if an expression cannot be evaluated in the current context.
- pub fn check_op(&mut self, op: impl NonConstOp) {
- self.check_op_spanned(op, self.span);
- }
-
- /// Emits an error at the given `span` if an expression cannot be evaluated in the current
- /// context.
- pub fn check_op_spanned<O: NonConstOp>(&mut self, op: O, span: Span) {
- let gate = match op.status_in_item(self.ccx) {
- Status::Allowed => return,
-
- Status::Unstable(gate) if self.tcx.features().enabled(gate) => {
- let unstable_in_stable = self.ccx.is_const_stable_const_fn()
- && !super::rustc_allow_const_fn_unstable(
- self.tcx,
- self.def_id().to_def_id(),
- gate,
- );
- if unstable_in_stable {
- emit_unstable_in_stable_error(self.ccx, span, gate);
- }
-
- return;
- }
-
- Status::Unstable(gate) => Some(gate),
- Status::Forbidden => None,
- };
-
- if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
- self.tcx.sess.miri_unleashed_feature(span, gate);
- return;
- }
-
- let mut err = op.build_error(self.ccx, span);
- assert!(err.is_error());
-
- match op.importance() {
- ops::DiagnosticImportance::Primary => {
- self.error_emitted = Some(ErrorReported);
- err.emit();
- }
-
- ops::DiagnosticImportance::Secondary => err.buffer(&mut self.secondary_errors),
- }
- }
-
- fn check_static(&mut self, def_id: DefId, span: Span) {
- if self.tcx.is_thread_local_static(def_id) {
- self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef");
- }
- self.check_op_spanned(ops::StaticAccess, span)
- }
-
- fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) {
- let kind = self.body.local_kind(local);
-
- for ty in ty.walk() {
- let ty = match ty.unpack() {
- GenericArgKind::Type(ty) => ty,
-
- // No constraints on lifetimes or constants, except potentially
- // constants' types, but `walk` will get to them as well.
- GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue,
- };
-
- match *ty.kind() {
- ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef(kind)),
- ty::Opaque(..) => self.check_op(ops::ty::ImplTrait),
- ty::FnPtr(..) => self.check_op(ops::ty::FnPtr(kind)),
-
- ty::Dynamic(preds, _) => {
- for pred in preds.iter() {
- match pred.skip_binder() {
- ty::ExistentialPredicate::AutoTrait(_)
- | ty::ExistentialPredicate::Projection(_) => {
- self.check_op(ops::ty::TraitBound(kind))
- }
- ty::ExistentialPredicate::Trait(trait_ref) => {
- if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() {
- self.check_op(ops::ty::TraitBound(kind))
- }
- }
- }
- }
- }
- _ => {}
- }
- }
- }
-
- fn check_item_predicates(&mut self) {
- let ConstCx { tcx, .. } = *self.ccx;
-
- let mut current = self.def_id().to_def_id();
- loop {
- let predicates = tcx.predicates_of(current);
- for (predicate, _) in predicates.predicates {
- match predicate.kind().skip_binder() {
- ty::PredicateKind::RegionOutlives(_)
- | ty::PredicateKind::TypeOutlives(_)
- | ty::PredicateKind::WellFormed(_)
- | ty::PredicateKind::Projection(_)
- | ty::PredicateKind::ConstEvaluatable(..)
- | ty::PredicateKind::ConstEquate(..)
- | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
- ty::PredicateKind::ObjectSafe(_) => {
- bug!("object safe predicate on function: {:#?}", predicate)
- }
- ty::PredicateKind::ClosureKind(..) => {
- bug!("closure kind predicate on function: {:#?}", predicate)
- }
- ty::PredicateKind::Subtype(_) => {
- bug!("subtype predicate on function: {:#?}", predicate)
- }
- ty::PredicateKind::Trait(pred, _constness) => {
- if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
- continue;
- }
- match pred.self_ty().kind() {
- ty::Param(p) => {
- let generics = tcx.generics_of(current);
- let def = generics.type_param(p, tcx);
- let span = tcx.def_span(def.def_id);
-
- // These are part of the function signature, so treat them like
- // arguments when determining importance.
- let kind = LocalKind::Arg;
-
- self.check_op_spanned(ops::ty::TraitBound(kind), span);
- }
- // other kinds of bounds are either tautologies
- // or cause errors in other passes
- _ => continue,
- }
- }
- }
- }
- match predicates.parent {
- Some(parent) => current = parent,
- None => break,
- }
- }
- }
-
- fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) {
- match self.const_kind() {
- // In a const fn all borrows are transient or point to the places given via
- // references in the arguments (so we already checked them with
- // TransientMutBorrow/MutBorrow as appropriate).
- // The borrow checker guarantees that no new non-transient borrows are created.
- // NOTE: Once we have heap allocations during CTFE we need to figure out
- // how to prevent `const fn` to create long-lived allocations that point
- // to mutable memory.
- hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)),
- _ => {
- // Locals with StorageDead do not live beyond the evaluation and can
- // thus safely be borrowed without being able to be leaked to the final
- // value of the constant.
- if self.local_has_storage_dead(local) {
- self.check_op(ops::TransientMutBorrow(kind));
- } else {
- self.check_op(ops::MutBorrow(kind));
- }
- }
- }
- }
-}
-
-impl Visitor<'tcx> for Validator<'mir, 'tcx> {
- fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &BasicBlockData<'tcx>) {
- trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup);
-
- // We don't const-check basic blocks on the cleanup path since we never unwind during
- // const-eval: a panic causes an immediate compile error. In other words, cleanup blocks
- // are unreachable during const-eval.
- //
- // We can't be more conservative (e.g., by const-checking cleanup blocks anyways) because
- // locals that would never be dropped during normal execution are sometimes dropped during
- // unwinding, which means backwards-incompatible live-drop errors.
- if block.is_cleanup {
- return;
- }
-
- self.super_basic_block_data(bb, block);
- }
-
- fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
- trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
-
- // Special-case reborrows to be more like a copy of a reference.
- match *rvalue {
- Rvalue::Ref(_, kind, place) => {
- if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) {
- let ctx = match kind {
- BorrowKind::Shared => {
- PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
- }
- BorrowKind::Shallow => {
- PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
- }
- BorrowKind::Unique => {
- PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow)
- }
- BorrowKind::Mut { .. } => {
- PlaceContext::MutatingUse(MutatingUseContext::Borrow)
- }
- };
- self.visit_local(&reborrowed_place_ref.local, ctx, location);
- self.visit_projection(reborrowed_place_ref, ctx, location);
- return;
- }
- }
- Rvalue::AddressOf(mutbl, place) => {
- if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) {
- let ctx = match mutbl {
- Mutability::Not => {
- PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
- }
- Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf),
- };
- self.visit_local(&reborrowed_place_ref.local, ctx, location);
- self.visit_projection(reborrowed_place_ref, ctx, location);
- return;
- }
- }
- _ => {}
- }
-
- self.super_rvalue(rvalue, location);
-
- match *rvalue {
- Rvalue::ThreadLocalRef(_) => self.check_op(ops::ThreadLocalAccess),
-
- Rvalue::Use(_)
- | Rvalue::Repeat(..)
- | Rvalue::Discriminant(..)
- | Rvalue::Len(_)
- | Rvalue::Aggregate(..) => {}
-
- Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, ref place)
- | Rvalue::Ref(_, kind @ BorrowKind::Unique, ref place) => {
- let ty = place.ty(self.body, self.tcx).ty;
- let is_allowed = match ty.kind() {
- // Inside a `static mut`, `&mut [...]` is allowed.
- ty::Array(..) | ty::Slice(_)
- if self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut) =>
- {
- true
- }
-
- // FIXME(ecstaticmorse): We could allow `&mut []` inside a const context given
- // that this is merely a ZST and it is already eligible for promotion.
- // This may require an RFC?
- /*
- ty::Array(_, len) if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0)
- => true,
- */
- _ => false,
- };
-
- if !is_allowed {
- if let BorrowKind::Mut { .. } = kind {
- self.check_mut_borrow(place.local, hir::BorrowKind::Ref)
- } else {
- self.check_op(ops::CellBorrow);
- }
- }
- }
-
- Rvalue::AddressOf(Mutability::Mut, ref place) => {
- self.check_mut_borrow(place.local, hir::BorrowKind::Raw)
- }
-
- Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, ref place)
- | Rvalue::AddressOf(Mutability::Not, ref place) => {
- let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
- &self.ccx,
- &mut |local| self.qualifs.has_mut_interior(self.ccx, local, location),
- place.as_ref(),
- );
-
- if borrowed_place_has_mut_interior {
- match self.const_kind() {
- // In a const fn all borrows are transient or point to the places given via
- // references in the arguments (so we already checked them with
- // TransientCellBorrow/CellBorrow as appropriate).
- // The borrow checker guarantees that no new non-transient borrows are created.
- // NOTE: Once we have heap allocations during CTFE we need to figure out
- // how to prevent `const fn` to create long-lived allocations that point
- // to (interior) mutable memory.
- hir::ConstContext::ConstFn => self.check_op(ops::TransientCellBorrow),
- _ => {
- // Locals with StorageDead are definitely not part of the final constant value, and
- // it is thus inherently safe to permit such locals to have their
- // address taken as we can't end up with a reference to them in the
- // final value.
- // Note: This is only sound if every local that has a `StorageDead` has a
- // `StorageDead` in every control flow path leading to a `return` terminator.
- if self.local_has_storage_dead(place.local) {
- self.check_op(ops::TransientCellBorrow);
- } else {
- self.check_op(ops::CellBorrow);
- }
- }
- }
- }
- }
-
- Rvalue::Cast(
- CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
- _,
- _,
- ) => {}
-
- Rvalue::Cast(
- CastKind::Pointer(
- PointerCast::UnsafeFnPointer
- | PointerCast::ClosureFnPointer(_)
- | PointerCast::ReifyFnPointer,
- ),
- _,
- _,
- ) => self.check_op(ops::FnPtrCast),
-
- Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
- // Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur
- // in the type of any local, which also excludes casts).
- }
-
- Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
- let operand_ty = operand.ty(self.body, self.tcx);
- let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
- let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
-
- if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
- self.check_op(ops::RawPtrToIntCast);
- }
- }
-
- Rvalue::NullaryOp(NullOp::SizeOf, _) => {}
- Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation),
-
- Rvalue::UnaryOp(_, ref operand) => {
- let ty = operand.ty(self.body, self.tcx);
- if is_int_bool_or_char(ty) {
- // Int, bool, and char operations are fine.
- } else if ty.is_floating_point() {
- self.check_op(ops::FloatingPointOp);
- } else {
- span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty);
- }
- }
-
- Rvalue::BinaryOp(op, box (ref lhs, ref rhs))
- | Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => {
- let lhs_ty = lhs.ty(self.body, self.tcx);
- let rhs_ty = rhs.ty(self.body, self.tcx);
-
- if is_int_bool_or_char(lhs_ty) && is_int_bool_or_char(rhs_ty) {
- // Int, bool, and char operations are fine.
- } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() {
- assert_eq!(lhs_ty, rhs_ty);
- assert!(
- op == BinOp::Eq
- || op == BinOp::Ne
- || op == BinOp::Le
- || op == BinOp::Lt
- || op == BinOp::Ge
- || op == BinOp::Gt
- || op == BinOp::Offset
- );
-
- self.check_op(ops::RawPtrComparison);
- } else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() {
- self.check_op(ops::FloatingPointOp);
- } else {
- span_bug!(
- self.span,
- "non-primitive type in `Rvalue::BinaryOp`: {:?} ⚬ {:?}",
- lhs_ty,
- rhs_ty
- );
- }
- }
- }
- }
-
- fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
- self.super_operand(op, location);
- if let Operand::Constant(c) = op {
- if let Some(def_id) = c.check_static_ptr(self.tcx) {
- self.check_static(def_id, self.span);
- }
- }
- }
- fn visit_projection_elem(
- &mut self,
- place_local: Local,
- proj_base: &[PlaceElem<'tcx>],
- elem: PlaceElem<'tcx>,
- context: PlaceContext,
- location: Location,
- ) {
- trace!(
- "visit_projection_elem: place_local={:?} proj_base={:?} elem={:?} \
- context={:?} location={:?}",
- place_local,
- proj_base,
- elem,
- context,
- location,
- );
-
- self.super_projection_elem(place_local, proj_base, elem, context, location);
-
- match elem {
- ProjectionElem::Deref => {
- let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
- if let ty::RawPtr(_) = base_ty.kind() {
- if proj_base.is_empty() {
- let decl = &self.body.local_decls[place_local];
- if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
- let span = decl.source_info.span;
- self.check_static(def_id, span);
- return;
- }
- }
- self.check_op(ops::RawPtrDeref);
- }
-
- if context.is_mutating_use() {
- self.check_op(ops::MutDeref);
- }
- }
-
- ProjectionElem::ConstantIndex { .. }
- | ProjectionElem::Downcast(..)
- | ProjectionElem::Subslice { .. }
- | ProjectionElem::Field(..)
- | ProjectionElem::Index(_) => {
- let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
- if base_ty.is_union() {
- self.check_op(ops::UnionAccess);
- }
- }
- }
- }
-
- fn visit_source_info(&mut self, source_info: &SourceInfo) {
- trace!("visit_source_info: source_info={:?}", source_info);
- self.span = source_info.span;
- }
-
- fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
- trace!("visit_statement: statement={:?} location={:?}", statement, location);
-
- self.super_statement(statement, location);
-
- match statement.kind {
- StatementKind::LlvmInlineAsm { .. } => {
- self.check_op(ops::InlineAsm);
- }
-
- StatementKind::Assign(..)
- | StatementKind::SetDiscriminant { .. }
- | StatementKind::FakeRead(..)
- | StatementKind::StorageLive(_)
- | StatementKind::StorageDead(_)
- | StatementKind::Retag { .. }
- | StatementKind::AscribeUserType(..)
- | StatementKind::Coverage(..)
- | StatementKind::CopyNonOverlapping(..)
- | StatementKind::Nop => {}
- }
- }
-
- #[instrument(level = "debug", skip(self))]
- fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
- use rustc_target::spec::abi::Abi::RustIntrinsic;
-
- self.super_terminator(terminator, location);
-
- match &terminator.kind {
- TerminatorKind::Call { func, args, .. } => {
- let ConstCx { tcx, body, param_env, .. } = *self.ccx;
- let caller = self.def_id().to_def_id();
-
- let fn_ty = func.ty(body, tcx);
-
- let (mut callee, substs) = match *fn_ty.kind() {
- ty::FnDef(def_id, substs) => (def_id, substs),
-
- ty::FnPtr(_) => {
- self.check_op(ops::FnCallIndirect);
- return;
- }
- _ => {
- span_bug!(terminator.source_info.span, "invalid callee of type {:?}", fn_ty)
- }
- };
-
- // Attempting to call a trait method?
- if let Some(trait_id) = tcx.trait_of_item(callee) {
- trace!("attempting to call a trait method");
- if !self.tcx.features().const_trait_impl {
- self.check_op(ops::FnCallNonConst);
- return;
- }
-
- let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
- let obligation = Obligation::new(
- ObligationCause::dummy(),
- param_env,
- Binder::dummy(TraitPredicate { trait_ref }),
- );
-
- let implsrc = tcx.infer_ctxt().enter(|infcx| {
- let mut selcx = SelectionContext::new(&infcx);
- selcx.select(&obligation).unwrap()
- });
-
- // If the method is provided via a where-clause that does not use the `?const`
- // opt-out, the call is allowed.
- if let Some(ImplSource::Param(_, hir::Constness::Const)) = implsrc {
- debug!(
- "const_trait_impl: provided {:?} via where-clause in {:?}",
- trait_ref, param_env
- );
- return;
- }
-
- // Resolve a trait method call to its concrete implementation, which may be in a
- // `const` trait impl.
- let instance = Instance::resolve(tcx, param_env, callee, substs);
- debug!("Resolving ({:?}) -> {:?}", callee, instance);
- if let Ok(Some(func)) = instance {
- if let InstanceDef::Item(def) = func.def {
- callee = def.did;
- }
- }
- }
-
- // At this point, we are calling a function, `callee`, whose `DefId` is known...
- if is_lang_panic_fn(tcx, callee) {
- self.check_op(ops::Panic);
-
- // const-eval of the `begin_panic` fn assumes the argument is `&str`
- if Some(callee) == tcx.lang_items().begin_panic_fn() {
- match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
- ty::Ref(_, ty, _) if ty.is_str() => (),
- _ => self.check_op(ops::PanicNonStr),
- }
- }
-
- return;
- }
-
- // `async` blocks get lowered to `std::future::from_generator(/* a closure */)`.
- let is_async_block = Some(callee) == tcx.lang_items().from_generator_fn();
- if is_async_block {
- let kind = hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block);
- self.check_op(ops::Generator(kind));
- return;
- }
-
- let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;
-
- // HACK: This is to "unstabilize" the `transmute` intrinsic
- // within const fns. `transmute` is allowed in all other const contexts.
- // This won't really scale to more intrinsics or functions. Let's allow const
- // transmutes in const fn before we add more hacks to this.
- if is_intrinsic && tcx.item_name(callee) == sym::transmute {
- self.check_op(ops::Transmute);
- return;
- }
-
- if !tcx.is_const_fn_raw(callee) {
- let mut permitted = false;
-
- let callee_trait = tcx.trait_of_item(callee);
- if let Some(trait_id) = callee_trait {
- if tcx.has_attr(caller, sym::default_method_body_is_const) {
- // permit call to non-const fn when caller has default_method_body_is_const..
- if tcx.trait_of_item(caller) == callee_trait {
- // ..and caller and callee are in the same trait.
- permitted = true;
- }
- }
- if !permitted {
- // if trait's impls are all const, permit the call.
- let mut const_impls = true;
- tcx.for_each_relevant_impl(trait_id, substs.type_at(0), |imp| {
- if const_impls {
- if let hir::Constness::NotConst = tcx.impl_constness(imp) {
- const_impls = false;
- }
- }
- });
- if const_impls {
- permitted = true;
- }
- }
- }
-
- if !permitted {
- self.check_op(ops::FnCallNonConst);
- return;
- }
- }
-
- // If the `const fn` we are trying to call is not const-stable, ensure that we have
- // the proper feature gate enabled.
- if let Some(gate) = is_unstable_const_fn(tcx, callee) {
- trace!(?gate, "calling unstable const fn");
- if self.span.allows_unstable(gate) {
- return;
- }
-
- // Calling an unstable function *always* requires that the corresponding gate
- // be enabled, even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`.
- if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) {
- self.check_op(ops::FnCallUnstable(callee, Some(gate)));
- return;
- }
-
- // If this crate is not using stability attributes, or the caller is not claiming to be a
- // stable `const fn`, that is all that is required.
- if !self.ccx.is_const_stable_const_fn() {
- trace!("crate not using stability attributes or caller not stably const");
- return;
- }
-
- // Otherwise, we are something const-stable calling a const-unstable fn.
-
- if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
- trace!("rustc_allow_const_fn_unstable gate active");
- return;
- }
-
- self.check_op(ops::FnCallUnstable(callee, Some(gate)));
- return;
- }
-
- // FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that
- // have no `rustc_const_stable` attributes to be const-unstable as well. This
- // should be fixed later.
- let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
- && tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable());
- if callee_is_unstable_unmarked {
- trace!("callee_is_unstable_unmarked");
- // We do not use `const` modifiers for intrinsic "functions", as intrinsics are
- // `extern` funtions, and these have no way to get marked `const`. So instead we
- // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
- if self.ccx.is_const_stable_const_fn() || is_intrinsic {
- self.check_op(ops::FnCallUnstable(callee, None));
- return;
- }
- }
- trace!("permitting call");
- }
-
- // Forbid all `Drop` terminators unless the place being dropped is a local with no
- // projections that cannot be `NeedsDrop`.
- TerminatorKind::Drop { place: dropped_place, .. }
- | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
- // If we are checking live drops after drop-elaboration, don't emit duplicate
- // errors here.
- if super::post_drop_elaboration::checking_enabled(self.ccx) {
- return;
- }
-
- let mut err_span = self.span;
-
- // Check to see if the type of this place can ever have a drop impl. If not, this
- // `Drop` terminator is frivolous.
- let ty_needs_drop =
- dropped_place.ty(self.body, self.tcx).ty.needs_drop(self.tcx, self.param_env);
-
- if !ty_needs_drop {
- return;
- }
-
- let needs_drop = if let Some(local) = dropped_place.as_local() {
- // Use the span where the local was declared as the span of the drop error.
- err_span = self.body.local_decls[local].source_info.span;
- self.qualifs.needs_drop(self.ccx, local, location)
- } else {
- true
- };
-
- if needs_drop {
- self.check_op_spanned(
- ops::LiveDrop { dropped_at: Some(terminator.source_info.span) },
- err_span,
- );
- }
- }
-
- TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
-
- TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
- self.check_op(ops::Generator(hir::GeneratorKind::Gen))
- }
-
- TerminatorKind::Abort => {
- // Cleanup blocks are skipped for const checking (see `visit_basic_block_data`).
- span_bug!(self.span, "`Abort` terminator outside of cleanup block")
- }
-
- TerminatorKind::Assert { .. }
- | TerminatorKind::FalseEdge { .. }
- | TerminatorKind::FalseUnwind { .. }
- | TerminatorKind::Goto { .. }
- | TerminatorKind::Resume
- | TerminatorKind::Return
- | TerminatorKind::SwitchInt { .. }
- | TerminatorKind::Unreachable => {}
- }
- }
-}
-
-fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) {
- let ty = body.return_ty();
- tcx.infer_ctxt().enter(|infcx| {
- let cause = traits::ObligationCause::new(body.span, hir_id, traits::SharedStatic);
- let mut fulfillment_cx = traits::FulfillmentContext::new();
- let sync_def_id = tcx.require_lang_item(LangItem::Sync, Some(body.span));
- fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause);
- if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(&err, None, false);
- }
- });
-}
-
-fn place_as_reborrow(
- tcx: TyCtxt<'tcx>,
- body: &Body<'tcx>,
- place: Place<'tcx>,
-) -> Option<PlaceRef<'tcx>> {
- match place.as_ref().last_projection() {
- Some((place_base, ProjectionElem::Deref)) => {
- // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
- // that points to the allocation for the static. Don't treat these as reborrows.
- if body.local_decls[place_base.local].is_ref_to_static() {
- None
- } else {
- // Ensure the type being derefed is a reference and not a raw pointer.
- // This is sufficient to prevent an access to a `static mut` from being marked as a
- // reborrow, even if the check above were to disappear.
- let inner_ty = place_base.ty(body, tcx).ty;
-
- if let ty::Ref(..) = inner_ty.kind() {
- return Some(place_base);
- } else {
- return None;
- }
- }
- }
- _ => None,
- }
-}
-
-fn is_int_bool_or_char(ty: Ty<'_>) -> bool {
- ty.is_bool() || ty.is_integral() || ty.is_char()
-}
-
-fn is_async_fn(ccx: &ConstCx<'_, '_>) -> bool {
- ccx.fn_sig().map_or(false, |sig| sig.header.asyncness == hir::IsAsync::Async)
-}
-
-fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) {
- let attr_span = ccx.fn_sig().map_or(ccx.body.span, |sig| sig.span.shrink_to_lo());
-
- ccx.tcx
- .sess
- .struct_span_err(
- span,
- &format!("const-stable function cannot use `#[feature({})]`", gate.as_str()),
- )
- .span_suggestion(
- attr_span,
- "if it is not part of the public API, make this function unstably const",
- concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(),
- Applicability::HasPlaceholders,
- )
- .span_suggestion(
- attr_span,
- "otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks",
- format!("#[rustc_allow_const_fn_unstable({})]\n", gate),
- Applicability::MaybeIncorrect,
- )
- .emit();
-}
pub mod remove_zsts;
pub mod required_consts;
pub mod rustc_peek;
+pub mod separate_const_switch;
pub mod simplify;
pub mod simplify_branches;
pub mod simplify_comparison_integral;
let ccx = check_consts::ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def.did) };
- let mut validator = check_consts::validation::Validator::new(&ccx);
+ let mut validator = check_consts::check::Checker::new(&ccx);
validator.check_body();
// We return the qualifs in the return place for every MIR body, even though it is only used
// inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
&multiple_return_terminators::MultipleReturnTerminators,
&instcombine::InstCombine,
+ &separate_const_switch::SeparateConstSwitch,
&const_prop::ConstProp,
&simplify_branches::SimplifyBranches::new("after-const-prop"),
&early_otherwise_branch::EarlyOtherwiseBranch,
--- /dev/null
+//! A pass that duplicates switch-terminated blocks
+//! into a new copy for each predecessor, provided
+//! the predecessor sets the value being switched
+//! over to a constant.
+//!
+//! The purpose of this pass is to help constant
+//! propagation passes to simplify the switch terminator
+//! of the copied blocks into gotos when some predecessors
+//! statically determine the output of switches.
+//!
+//! ```text
+//! x = 12 --- ---> something
+//! \ / 12
+//! --> switch x
+//! / \ otherwise
+//! x = y --- ---> something else
+//! ```
+//! becomes
+//! ```text
+//! x = 12 ---> switch x ------> something
+//! \ / 12
+//! X
+//! / \ otherwise
+//! x = y ---> switch x ------> something else
+//! ```
+//! so it can hopefully later be turned by another pass into
+//! ```text
+//! x = 12 --------------------> something
+//! / 12
+//! /
+//! / otherwise
+//! x = y ---- switch x ------> something else
+//! ```
+//!
+//! This optimization is meant to cover simple cases
+//! like `?` desugaring. For now, it thus focuses on
+//! simplicity rather than completeness (it notably
+//! sometimes duplicates abusively).
+
+use crate::transform::MirPass;
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+use smallvec::SmallVec;
+
+pub struct SeparateConstSwitch;
+
+impl<'tcx> MirPass<'tcx> for SeparateConstSwitch {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ if tcx.sess.mir_opt_level() < 4 {
+ return;
+ }
+
+ // If execution did something, applying a simplification layer
+ // helps later passes optimize the copy away.
+ if separate_const_switch(body) > 0 {
+ super::simplify::simplify_cfg(tcx, body);
+ }
+ }
+}
+
+/// Returns the amount of blocks that were duplicated
+pub fn separate_const_switch<'tcx>(body: &mut Body<'tcx>) -> usize {
+ let mut new_blocks: SmallVec<[(BasicBlock, BasicBlock); 6]> = SmallVec::new();
+ let predecessors = body.predecessors();
+ 'block_iter: for (block_id, block) in body.basic_blocks().iter_enumerated() {
+ if let TerminatorKind::SwitchInt {
+ discr: Operand::Copy(switch_place) | Operand::Move(switch_place),
+ ..
+ } = block.terminator().kind
+ {
+ // If the block is on an unwind path, do not
+ // apply the optimization as unwind paths
+ // rely on a unique parent invariant
+ if block.is_cleanup {
+ continue 'block_iter;
+ }
+
+ // If the block has fewer than 2 predecessors, ignore it
+ // we could maybe chain blocks that have exactly one
+ // predecessor, but for now we ignore that
+ if predecessors[block_id].len() < 2 {
+ continue 'block_iter;
+ }
+
+ // First, let's find a non-const place
+ // that determines the result of the switch
+ if let Some(switch_place) = find_determining_place(switch_place, block) {
+ // We now have an input place for which it would
+ // be interesting if predecessors assigned it from a const
+
+ let mut predecessors_left = predecessors[block_id].len();
+ 'predec_iter: for predecessor_id in predecessors[block_id].iter().copied() {
+ let predecessor = &body.basic_blocks()[predecessor_id];
+
+ // First we make sure the predecessor jumps
+ // in a reasonable way
+ match &predecessor.terminator().kind {
+ // The following terminators are
+ // unconditionally valid
+ TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } => {}
+
+ TerminatorKind::FalseEdge { real_target, .. } => {
+ if *real_target != block_id {
+ continue 'predec_iter;
+ }
+ }
+
+ // The following terminators are not allowed
+ TerminatorKind::Resume
+ | TerminatorKind::Drop { .. }
+ | TerminatorKind::DropAndReplace { .. }
+ | TerminatorKind::Call { .. }
+ | TerminatorKind::Assert { .. }
+ | TerminatorKind::FalseUnwind { .. }
+ | TerminatorKind::Yield { .. }
+ | TerminatorKind::Abort
+ | TerminatorKind::Return
+ | TerminatorKind::Unreachable
+ | TerminatorKind::InlineAsm { .. }
+ | TerminatorKind::GeneratorDrop => {
+ continue 'predec_iter;
+ }
+ }
+
+ if is_likely_const(switch_place, predecessor) {
+ new_blocks.push((predecessor_id, block_id));
+ predecessors_left -= 1;
+ if predecessors_left < 2 {
+ // If the original block only has one predecessor left,
+ // we have nothing left to do
+ break 'predec_iter;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Once the analysis is done, perform the duplication
+ let body_span = body.span;
+ let copied_blocks = new_blocks.len();
+ let blocks = body.basic_blocks_mut();
+ for (pred_id, target_id) in new_blocks {
+ let new_block = blocks[target_id].clone();
+ let new_block_id = blocks.push(new_block);
+ let terminator = blocks[pred_id].terminator_mut();
+
+ match terminator.kind {
+ TerminatorKind::Goto { ref mut target } => {
+ *target = new_block_id;
+ }
+
+ TerminatorKind::FalseEdge { ref mut real_target, .. } => {
+ if *real_target == target_id {
+ *real_target = new_block_id;
+ }
+ }
+
+ TerminatorKind::SwitchInt { ref mut targets, .. } => {
+ targets.all_targets_mut().iter_mut().for_each(|x| {
+ if *x == target_id {
+ *x = new_block_id;
+ }
+ });
+ }
+
+ TerminatorKind::Resume
+ | TerminatorKind::Abort
+ | TerminatorKind::Return
+ | TerminatorKind::Unreachable
+ | TerminatorKind::GeneratorDrop
+ | TerminatorKind::Assert { .. }
+ | TerminatorKind::DropAndReplace { .. }
+ | TerminatorKind::FalseUnwind { .. }
+ | TerminatorKind::Drop { .. }
+ | TerminatorKind::Call { .. }
+ | TerminatorKind::InlineAsm { .. }
+ | TerminatorKind::Yield { .. } => {
+ span_bug!(
+ body_span,
+ "basic block terminator had unexpected kind {:?}",
+ &terminator.kind
+ )
+ }
+ }
+ }
+
+ copied_blocks
+}
+
+/// This function describes a rough heuristic guessing
+/// whether a place is last set with a const within the block.
+/// Notably, it will be overly pessimistic in cases that are already
+/// not handled by `separate_const_switch`.
+fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<'tcx>) -> bool {
+ for statement in block.statements.iter().rev() {
+ match &statement.kind {
+ StatementKind::Assign(assign) => {
+ if assign.0 == tracked_place {
+ match assign.1 {
+ // These rvalues are definitely constant
+ Rvalue::Use(Operand::Constant(_))
+ | Rvalue::Ref(_, _, _)
+ | Rvalue::AddressOf(_, _)
+ | Rvalue::Cast(_, Operand::Constant(_), _)
+ | Rvalue::NullaryOp(_, _)
+ | Rvalue::UnaryOp(_, Operand::Constant(_)) => return true,
+
+ // These rvalues make things ambiguous
+ Rvalue::Repeat(_, _)
+ | Rvalue::ThreadLocalRef(_)
+ | Rvalue::Len(_)
+ | Rvalue::BinaryOp(_, _)
+ | Rvalue::CheckedBinaryOp(_, _)
+ | Rvalue::Aggregate(_, _) => return false,
+
+ // These rvalues move the place to track
+ Rvalue::Cast(_, Operand::Copy(place) | Operand::Move(place), _)
+ | Rvalue::Use(Operand::Copy(place) | Operand::Move(place))
+ | Rvalue::UnaryOp(_, Operand::Copy(place) | Operand::Move(place))
+ | Rvalue::Discriminant(place) => tracked_place = place,
+ }
+ }
+ }
+
+ // If the discriminant is set, it is always set
+ // as a constant, so the job is done.
+ // As we are **ignoring projections**, if the place
+ // we are tracking sees its discriminant be set,
+ // that means we had to be tracking the discriminant
+ // specifically (as it is impossible to switch over
+ // an enum directly, and if we were switching over
+ // its content, we would have had to at least cast it to
+ // some variant first)
+ StatementKind::SetDiscriminant { place, .. } => {
+ if **place == tracked_place {
+ return true;
+ }
+ }
+
+ // If inline assembly is found, we probably should
+ // not try to analyze the code
+ StatementKind::LlvmInlineAsm(_) => return false,
+
+ // These statements have no influence on the place
+ // we are interested in
+ StatementKind::FakeRead(_)
+ | StatementKind::StorageLive(_)
+ | StatementKind::Retag(_, _)
+ | StatementKind::AscribeUserType(_, _)
+ | StatementKind::Coverage(_)
+ | StatementKind::StorageDead(_)
+ | StatementKind::CopyNonOverlapping(_)
+ | StatementKind::Nop => {}
+ }
+ }
+
+ // If no good reason for the place to be const is found,
+ // give up. We could maybe go up predecessors, but in
+ // most cases giving up now should be sufficient.
+ false
+}
+
+/// Finds a unique place that entirely determines the value
+/// of `switch_place`, if it exists. This is only a heuristic.
+/// Ideally we would like to track multiple determining places
+/// for some edge cases, but one is enough for a lot of situations.
+fn find_determining_place<'tcx>(
+ mut switch_place: Place<'tcx>,
+ block: &BasicBlockData<'tcx>,
+) -> Option<Place<'tcx>> {
+ for statement in block.statements.iter().rev() {
+ match &statement.kind {
+ StatementKind::Assign(op) => {
+ if op.0 != switch_place {
+ continue;
+ }
+
+ match op.1 {
+ // The following rvalues move the place
+ // that may be const in the predecessor
+ Rvalue::Use(Operand::Move(new) | Operand::Copy(new))
+ | Rvalue::UnaryOp(_, Operand::Copy(new) | Operand::Move(new))
+ | Rvalue::Cast(_, Operand::Move(new) | Operand::Copy(new), _)
+ | Rvalue::Repeat(Operand::Move(new) | Operand::Copy(new), _)
+ | Rvalue::Discriminant(new)
+ => switch_place = new,
+
+ // The following rvalues might still make the block
+ // be valid but for now we reject them
+ Rvalue::Len(_)
+ | Rvalue::Ref(_, _, _)
+ | Rvalue::BinaryOp(_, _)
+ | Rvalue::CheckedBinaryOp(_, _)
+ | Rvalue::Aggregate(_, _)
+
+ // The following rvalues definitely mean we cannot
+ // or should not apply this optimization
+ | Rvalue::Use(Operand::Constant(_))
+ | Rvalue::Repeat(Operand::Constant(_), _)
+ | Rvalue::ThreadLocalRef(_)
+ | Rvalue::AddressOf(_, _)
+ | Rvalue::NullaryOp(_, _)
+ | Rvalue::UnaryOp(_, Operand::Constant(_))
+ | Rvalue::Cast(_, Operand::Constant(_), _)
+ => return None,
+ }
+ }
+
+ // These statements have no influence on the place
+ // we are interested in
+ StatementKind::FakeRead(_)
+ | StatementKind::StorageLive(_)
+ | StatementKind::StorageDead(_)
+ | StatementKind::Retag(_, _)
+ | StatementKind::AscribeUserType(_, _)
+ | StatementKind::Coverage(_)
+ | StatementKind::CopyNonOverlapping(_)
+ | StatementKind::Nop => {}
+
+ // If inline assembly is found, we probably should
+ // not try to analyze the code
+ StatementKind::LlvmInlineAsm(_) => return None,
+
+ // If the discriminant is set, it is always set
+ // as a constant, so the job is already done.
+ // As we are **ignoring projections**, if the place
+ // we are tracking sees its discriminant be set,
+ // that means we had to be tracking the discriminant
+ // specifically (as it is impossible to switch over
+ // an enum directly, and if we were switching over
+ // its content, we would have had to at least cast it to
+ // some variant first)
+ StatementKind::SetDiscriminant { place, .. } => {
+ if **place == switch_place {
+ return None;
+ }
+ }
+ }
+ }
+
+ Some(switch_place)
+}
use rustc_hir as hir;
use rustc_middle::mir::BorrowKind;
use rustc_middle::thir::*;
-use rustc_middle::ty::{self, ParamEnv, TyCtxt};
+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;
use rustc_span::def_id::{DefId, LocalDefId};
/// The `#[target_feature]` attributes of the body. Used for checking
/// calls to functions with `#[target_feature]` (RFC 2396).
body_target_features: &'tcx Vec<Symbol>,
- in_possible_lhs_union_assign: bool,
+ /// When inside the LHS of an assignment to a field, this is the type
+ /// of the LHS and the span of the assignment expression.
+ assignment_info: Option<(Ty<'tcx>, Span)>,
in_union_destructure: bool,
param_env: ParamEnv<'tcx>,
inside_adt: bool,
}
fn visit_expr(&mut self, expr: &Expr<'tcx>) {
- // could we be in a the LHS of an assignment of a union?
+ // could we be in the LHS of an assignment to a field?
match expr.kind {
ExprKind::Field { .. }
| ExprKind::VarRef { .. }
| ExprKind::InlineAsm { .. }
| ExprKind::LlvmInlineAsm { .. }
| ExprKind::LogicalOp { .. }
- | ExprKind::Use { .. } => self.in_possible_lhs_union_assign = false,
+ | ExprKind::Use { .. } => {
+ // We don't need to save the old value and restore it
+ // because all the place expressions can't have more
+ // than one child.
+ self.assignment_info = None;
+ }
};
match expr.kind {
ExprKind::Scope { value, lint_level: LintLevel::Explicit(hir_id), region_scope: _ } => {
self.safety_context = closure_visitor.safety_context;
}
ExprKind::Field { lhs, .. } => {
- // assigning to union field is okay for AccessToUnionField
- if let ty::Adt(adt_def, _) = &self.thir[lhs].ty.kind() {
+ let lhs = &self.thir[lhs];
+ if let ty::Adt(adt_def, _) = lhs.ty.kind() {
if adt_def.is_union() {
- if self.in_possible_lhs_union_assign {
- // FIXME: trigger AssignToDroppingUnionField unsafety if needed
+ if let Some((assigned_ty, assignment_span)) = self.assignment_info {
+ // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping.
+ if !(assigned_ty
+ .ty_adt_def()
+ .map_or(false, |adt| adt.is_manually_drop())
+ || assigned_ty
+ .is_copy_modulo_regions(self.tcx.at(expr.span), self.param_env))
+ {
+ self.requires_unsafe(assignment_span, AssignToDroppingUnionField);
+ } else {
+ // write to non-drop union field, safe
+ }
} else {
self.requires_unsafe(expr.span, AccessToUnionField);
}
}
}
ExprKind::Assign { lhs, rhs } | ExprKind::AssignOp { lhs, rhs, .. } => {
+ let lhs = &self.thir[lhs];
// First, check whether we are mutating a layout constrained field
let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
- visit::walk_expr(&mut visitor, &self.thir[lhs]);
+ visit::walk_expr(&mut visitor, lhs);
if visitor.found {
self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField);
}
// Second, check for accesses to union fields
// don't have any special handling for AssignOp since it causes a read *and* write to lhs
if matches!(expr.kind, ExprKind::Assign { .. }) {
- // assigning to a union is safe, check here so it doesn't get treated as a read later
- self.in_possible_lhs_union_assign = true;
- visit::walk_expr(self, &self.thir()[lhs]);
- self.in_possible_lhs_union_assign = false;
+ self.assignment_info = Some((lhs.ty, expr.span));
+ visit::walk_expr(self, lhs);
+ self.assignment_info = None;
visit::walk_expr(self, &self.thir()[rhs]);
return; // we have already visited everything by now
}
UseOfMutableStatic,
UseOfExternStatic,
DerefOfRawPointer,
- #[allow(dead_code)] // FIXME
AssignToDroppingUnionField,
AccessToUnionField,
- #[allow(dead_code)] // FIXME
MutationOfLayoutConstrainedField,
- #[allow(dead_code)] // FIXME
BorrowOfLayoutConstrainedField,
CallToFunctionWith,
}
hir_context: hir_id,
body_unsafety,
body_target_features,
- in_possible_lhs_union_assign: false,
+ assignment_info: None,
in_union_destructure: false,
param_env: tcx.param_env(def.did),
inside_adt: false,
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME;
use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS};
-use rustc_session::parse::feature_err;
use rustc_session::Session;
-use rustc_span::{sym, Span};
+use rustc_span::Span;
use std::slice;
crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
impl<'tcx> MatchVisitor<'_, 'tcx> {
fn check_patterns(&mut self, pat: &Pat<'_>) {
pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
- if !self.tcx.features().bindings_after_at {
- check_legality_of_bindings_in_at_patterns(self, pat);
- }
check_for_bindings_named_same_as_variants(self, pat);
}
err.emit();
}
}
-
-/// Forbids bindings in `@` patterns. This used to be is necessary for memory safety,
-/// because of the way rvalues were handled in the borrow check. (See issue #14587.)
-fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_>) {
- AtBindingPatternVisitor { cx, bindings_allowed: true }.visit_pat(pat);
-
- struct AtBindingPatternVisitor<'a, 'b, 'tcx> {
- cx: &'a MatchVisitor<'b, 'tcx>,
- bindings_allowed: bool,
- }
-
- impl<'v> Visitor<'v> for AtBindingPatternVisitor<'_, '_, '_> {
- type Map = intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
- fn visit_pat(&mut self, pat: &Pat<'_>) {
- match pat.kind {
- hir::PatKind::Binding(.., ref subpat) => {
- if !self.bindings_allowed {
- feature_err(
- &self.cx.tcx.sess.parse_sess,
- sym::bindings_after_at,
- pat.span,
- "pattern bindings after an `@` are unstable",
- )
- .emit();
- }
-
- if subpat.is_some() {
- let bindings_were_allowed = self.bindings_allowed;
- self.bindings_allowed = false;
- intravisit::walk_pat(self, pat);
- self.bindings_allowed = bindings_were_allowed;
- }
- }
- _ => intravisit::walk_pat(self, pat),
- }
- }
- }
-}
#![feature(array_windows)]
#![feature(crate_visibility_modifier)]
-#![feature(bindings_after_at)]
+#![cfg_attr(bootstrap, feature(bindings_after_at))]
#![feature(box_syntax)]
#![feature(box_patterns)]
#![recursion_limit = "256"]
expected.sort_by_cached_key(|x| x.to_string());
expected.dedup();
+ let sm = self.sess.source_map();
+ let msg = format!("expected `;`, found {}", super::token_descr(&self.token));
+ let appl = Applicability::MachineApplicable;
+ if expected.contains(&TokenType::Token(token::Semi)) {
+ if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP {
+ // Likely inside a macro, can't provide meaningful suggestions.
+ } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) {
+ // The current token is in the same line as the prior token, not recoverable.
+ } else if [token::Comma, token::Colon].contains(&self.token.kind)
+ && self.prev_token.kind == token::CloseDelim(token::Paren)
+ {
+ // Likely typo: The current token is on a new line and is expected to be
+ // `.`, `;`, `?`, or an operator after a close delimiter token.
+ //
+ // let a = std::process::Command::new("echo")
+ // .arg("1")
+ // ,arg("2")
+ // ^
+ // https://github.com/rust-lang/rust/issues/72253
+ } else if self.look_ahead(1, |t| {
+ t == &token::CloseDelim(token::Brace)
+ || t.can_begin_expr() && t.kind != token::Colon
+ }) && [token::Comma, token::Colon].contains(&self.token.kind)
+ {
+ // Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is
+ // either `,` or `:`, and the next token could either start a new statement or is a
+ // block close. For example:
+ //
+ // let x = 32:
+ // let y = 42;
+ self.bump();
+ let sp = self.prev_token.span;
+ self.struct_span_err(sp, &msg)
+ .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl)
+ .emit();
+ return Ok(false);
+ } else if self.look_ahead(0, |t| {
+ t == &token::CloseDelim(token::Brace)
+ || (
+ t.can_begin_expr() && t != &token::Semi && t != &token::Pound
+ // Avoid triggering with too many trailing `#` in raw string.
+ )
+ }) {
+ // Missing semicolon typo. This is triggered if the next token could either start a
+ // new statement or is a block close. For example:
+ //
+ // let x = 32
+ // let y = 42;
+ let sp = self.prev_token.span.shrink_to_hi();
+ self.struct_span_err(sp, &msg)
+ .span_label(self.token.span, "unexpected token")
+ .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl)
+ .emit();
+ return Ok(false);
+ }
+ }
+
let expect = tokens_to_string(&expected[..]);
let actual = super::token_descr(&self.token);
let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
return Err(err);
}
- let sm = self.sess.source_map();
if self.prev_token.span == DUMMY_SP {
// Account for macro context where the previous span might not be
// available to avoid incorrect output (#54841).
if self.eat(&token::Semi) {
return Ok(());
}
- let sm = self.sess.source_map();
- let msg = format!("expected `;`, found {}", super::token_descr(&self.token));
- let appl = Applicability::MachineApplicable;
- if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP {
- // Likely inside a macro, can't provide meaningful suggestions.
- return self.expect(&token::Semi).map(drop);
- } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) {
- // The current token is in the same line as the prior token, not recoverable.
- } else if [token::Comma, token::Colon].contains(&self.token.kind)
- && self.prev_token.kind == token::CloseDelim(token::Paren)
- {
- // Likely typo: The current token is on a new line and is expected to be
- // `.`, `;`, `?`, or an operator after a close delimiter token.
- //
- // let a = std::process::Command::new("echo")
- // .arg("1")
- // ,arg("2")
- // ^
- // https://github.com/rust-lang/rust/issues/72253
- self.expect(&token::Semi)?;
- return Ok(());
- } else if self.look_ahead(1, |t| {
- t == &token::CloseDelim(token::Brace) || t.can_begin_expr() && t.kind != token::Colon
- }) && [token::Comma, token::Colon].contains(&self.token.kind)
- {
- // Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is
- // either `,` or `:`, and the next token could either start a new statement or is a
- // block close. For example:
- //
- // let x = 32:
- // let y = 42;
- self.bump();
- let sp = self.prev_token.span;
- self.struct_span_err(sp, &msg)
- .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl)
- .emit();
- return Ok(());
- } else if self.look_ahead(0, |t| {
- t == &token::CloseDelim(token::Brace)
- || (
- t.can_begin_expr() && t != &token::Semi && t != &token::Pound
- // Avoid triggering with too many trailing `#` in raw string.
- )
- }) {
- // Missing semicolon typo. This is triggered if the next token could either start a
- // new statement or is a block close. For example:
- //
- // let x = 32
- // let y = 42;
- let sp = self.prev_token.span.shrink_to_hi();
- self.struct_span_err(sp, &msg)
- .span_label(self.token.span, "unexpected token")
- .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl)
- .emit();
- return Ok(());
- }
self.expect(&token::Semi).map(drop) // Error unconditionally
}
fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
let check_attr_visitor = &mut CheckAttrVisitor { tcx };
tcx.hir().visit_item_likes_in_module(module_def_id, &mut check_attr_visitor.as_deep_visitor());
- tcx.hir().visit_exported_macros_in_krate(check_attr_visitor);
- check_invalid_macro_level_attr(tcx, tcx.hir().krate().non_exported_macro_attrs);
if module_def_id.is_top_level_module() {
check_attr_visitor.check_attributes(CRATE_HIR_ID, &DUMMY_SP, Target::Mod, None);
check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
+ tcx.hir().visit_exported_macros_in_krate(check_attr_visitor);
+ check_invalid_macro_level_attr(tcx, tcx.hir().krate().non_exported_macro_attrs);
}
}
}
}
+ #[allow(dead_code)] // FIXME(81658): should be used + lint reinstated after #83171 relands.
fn handle_assign(&mut self, expr: &'tcx hir::Expr<'tcx>) {
if self
.typeck_results()
}
}
+ #[allow(dead_code)] // FIXME(81658): should be used + lint reinstated after #83171 relands.
fn check_for_self_assign(&mut self, assign: &'tcx hir::Expr<'tcx>) {
fn check_for_self_assign_helper(
tcx: TyCtxt<'tcx>,
hir::ExprKind::MethodCall(..) => {
self.lookup_and_handle_method(expr.hir_id);
}
- hir::ExprKind::Assign(ref left, ref right, ..) => {
- self.handle_assign(left);
- self.check_for_self_assign(expr);
- self.visit_expr(right);
- return;
- }
hir::ExprKind::Field(ref lhs, ..) => {
self.handle_field_access(&lhs, expr.hir_id);
}
// Collect diagnostic items in this crate.
tcx.hir().krate().visit_all_item_likes(&mut collector);
- for m in tcx.hir().krate().exported_macros {
+ for m in tcx.hir().krate().exported_macros() {
collector.observe_item(m.def_id);
}
}
fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
- let sp = tcx.hir().krate().item.inner;
+ let sp = tcx.hir().krate().module().inner;
if *tcx.sess.parse_sess.reached_eof.borrow() {
// There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about
// the missing `fn main()` then as it might have been hidden inside an unclosed block.
annotator.annotate(
hir::CRATE_HIR_ID,
- krate.item.inner,
+ krate.module().inner,
None,
AnnotationKind::Required,
InheritDeprecation::Yes,
if tcx.stability().staged_api[&LOCAL_CRATE] {
let krate = tcx.hir().krate();
let mut missing = MissingStabilityAnnotations { tcx, access_levels };
- missing.check_missing_stability(hir::CRATE_HIR_ID, krate.item.inner);
+ missing.check_missing_stability(hir::CRATE_HIR_ID, krate.module().inner);
intravisit::walk_crate(&mut missing, krate);
krate.visit_all_item_likes(&mut missing.as_deep_visitor());
}
//! Defines the set of legal keys that can be used in queries.
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
-use rustc_hir::HirId;
use rustc_middle::infer::canonical::Canonical;
use rustc_middle::mir;
+use rustc_middle::traits;
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::subst::{GenericArg, SubstsRef};
use rustc_middle::ty::{self, Ty, TyCtxt};
}
}
-impl<'tcx> Key for (ty::Predicate<'tcx>, HirId) {
+impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::profiling::QueryInvocationId;
-use rustc_data_structures::profiling::SelfProfilerRef;
+use rustc_data_structures::profiling::{EventId, QueryInvocationId, SelfProfilerRef};
use rustc_data_structures::sharded::{self, Sharded};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
/// each task has a `DepNodeIndex` that uniquely identifies it. This unique
/// ID is used for self-profiling.
virtual_dep_node_index: Lrc<AtomicU32>,
+
+ /// The cached event id for profiling node interning. This saves us
+ /// from having to look up the event id every time we intern a node
+ /// which may incur too much overhead.
+ /// This will be None if self-profiling is disabled.
+ node_intern_event_id: Option<EventId>,
}
rustc_index::newtype_index! {
);
debug_assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
+ let node_intern_event_id = profiler
+ .get_or_alloc_cached_string("incr_comp_intern_dep_graph_node")
+ .map(EventId::from_label);
+
DepGraph {
data: Some(Lrc::new(DepGraphData {
previous_work_products: prev_work_products,
colors: DepNodeColorMap::new(prev_graph_node_count),
})),
virtual_dep_node_index: Lrc::new(AtomicU32::new(0)),
+ node_intern_event_id,
}
}
pub fn new_disabled() -> DepGraph<K> {
- DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) }
+ DepGraph {
+ data: None,
+ virtual_dep_node_index: Lrc::new(AtomicU32::new(0)),
+ node_intern_event_id: None,
+ }
}
/// Returns `true` if we are actually building the full dep-graph, and `false` otherwise.
let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads);
let mut hcx = dcx.create_stable_hashing_context();
+ let hashing_timer = dcx.profiler().incr_result_hashing();
let current_fingerprint = hash_result(&mut hcx, &result);
let print_status = cfg!(debug_assertions) && dcx.sess().opts.debugging_opts.dep_tasks;
+ // Get timer for profiling `DepNode` interning
+ let node_intern_timer = self
+ .node_intern_event_id
+ .map(|eid| dcx.profiler().generic_activity_with_event_id(eid));
// Intern the new `DepNode`.
let (dep_node_index, prev_and_color) = data.current.intern_node(
dcx.profiler(),
current_fingerprint,
print_status,
);
+ drop(node_intern_timer);
+
+ hashing_timer.finish_with_query_invocation_id(dep_node_index.into());
if let Some((prev_index, color)) = prev_and_color {
debug_assert!(
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_is_item = if let Some(parent_def_id) =
- parent_id.as_owner()
- {
- let parent_item_id = hir::ItemId { def_id: parent_def_id };
- let parent_impl_id = hir::ImplItemId { def_id: parent_def_id };
- let parent_trait_id =
- hir::TraitItemId { def_id: parent_def_id };
- let parent_foreign_id =
- hir::ForeignItemId { def_id: parent_def_id };
- let krate = self.tcx.hir().krate();
-
- krate.items.contains_key(&parent_item_id)
- || krate.impl_items.contains_key(&parent_impl_id)
- || krate.trait_items.contains_key(&parent_trait_id)
- || krate.foreign_items.contains_key(&parent_foreign_id)
- } else {
- false
- };
+ // FIXME(cjgillot) Can this check be replaced by
+ // `let parent_is_item = parent_id.is_owner();`?
+ let parent_is_item =
+ if let Some(parent_def_id) = parent_id.as_owner() {
+ matches!(
+ self.tcx.hir().krate().owners.get(parent_def_id),
+ Some(Some(_)),
+ )
+ } else {
+ false
+ };
if !parent_is_item {
if !self.trait_definition_only {
Scope::Binder { hir_id, .. } => {
break *hir_id;
}
- Scope::Body { id, .. } => break id.hir_id,
Scope::ObjectLifetimeDefault { ref s, .. }
| Scope::Elision { ref s, .. }
| Scope::Supertrait { ref s, .. }
| Scope::TraitRefBoundary { ref s, .. } => {
scope = *s;
}
- Scope::Root => {
- // See issue #83907. Just bail out from looking inside.
+ Scope::Root | Scope::Body { .. } => {
+ // See issues #83907 and #83693. Just bail out from looking inside.
self.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
"In fn_like_elision without appropriate scope above",
},
crate_root: crate_root.unwrap_or_else(|| "<no source>".to_owned()),
external_crates: self.save_ctxt.get_external_crates(),
- span: self.span_from_span(krate.item.inner),
+ span: self.span_from_span(krate.module().inner),
};
self.dumper.crate_prelude(data);
format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(id).to_def_id()));
let sm = self.tcx.sess.source_map();
- let filename = sm.span_to_filename(krate.item.inner);
+ let krate_mod = krate.module();
+ let filename = sm.span_to_filename(krate_mod.inner);
let data_id = id_from_hir_id(id, &self.save_ctxt);
let children =
- krate.item.item_ids.iter().map(|i| id_from_def_id(i.def_id.to_def_id())).collect();
- let span = self.span_from_span(krate.item.inner);
+ krate_mod.item_ids.iter().map(|i| id_from_def_id(i.def_id.to_def_id())).collect();
+ let span = self.span_from_span(krate_mod.inner);
let attrs = self.tcx.hir().attrs(id);
self.dumper.dump_def(
),
opt::multi_s(
"",
- "force-warns",
+ "force-warn",
"Specifiy lints that should warn even if \
they are allowed somewhere else",
"LINT",
never = never colorize output",
"auto|always|never",
),
- opt::opt(
- "",
- "pretty",
- "Pretty-print the input instead of compiling;
- valid types are: `normal` (un-annotated source),
- `expanded` (crates expanded), or
- `expanded,identified` (fully parenthesized, AST nodes with IDs).",
- "TYPE",
- ),
opt::multi_s(
"",
"remap-path-prefix",
let mut lint_opts_with_position = vec![];
let mut describe_lints = false;
- if !debugging_opts.unstable_options && matches.opt_present("force-warns") {
+ if !debugging_opts.unstable_options && matches.opt_present("force-warn") {
early_error(
error_format,
"the `-Z unstable-options` flag must also be passed to enable \
- the flag `--force-warns=lints`",
+ the flag `--force-warn=lints`",
);
}
let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
- let pretty = parse_pretty(matches, &debugging_opts, error_format);
+ let pretty = parse_pretty(&debugging_opts, error_format);
if !debugging_opts.unstable_options
&& !target_triple.triple().contains("apple")
}
}
-fn parse_pretty(
- matches: &getopts::Matches,
- debugging_opts: &DebuggingOptions,
- efmt: ErrorOutputType,
-) -> Option<PpMode> {
- fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
- use PpMode::*;
- let first = match (name, extended) {
- ("normal", _) => Source(PpSourceMode::Normal),
- ("identified", _) => Source(PpSourceMode::Identified),
- ("everybody_loops", true) => Source(PpSourceMode::EveryBodyLoops),
- ("expanded", _) => Source(PpSourceMode::Expanded),
- ("expanded,identified", _) => Source(PpSourceMode::ExpandedIdentified),
- ("expanded,hygiene", _) => Source(PpSourceMode::ExpandedHygiene),
- ("ast-tree", true) => AstTree(PpAstTreeMode::Normal),
- ("ast-tree,expanded", true) => AstTree(PpAstTreeMode::Expanded),
- ("hir", true) => Hir(PpHirMode::Normal),
- ("hir,identified", true) => Hir(PpHirMode::Identified),
- ("hir,typed", true) => Hir(PpHirMode::Typed),
- ("hir-tree", true) => HirTree,
- ("thir-tree", true) => ThirTree,
- ("mir", true) => Mir,
- ("mir-cfg", true) => MirCFG,
- _ => {
- if extended {
- early_error(
- efmt,
- &format!(
- "argument to `unpretty` must be one of `normal`, \
- `expanded`, `identified`, `expanded,identified`, \
- `expanded,hygiene`, `everybody_loops`, \
- `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
- `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
- name
- ),
- );
- } else {
- early_error(
- efmt,
- &format!(
- "argument to `pretty` must be one of `normal`, \
- `expanded`, `identified`, or `expanded,identified`; got {}",
- name
- ),
- );
- }
- }
- };
- tracing::debug!("got unpretty option: {:?}", first);
- first
- }
-
- if debugging_opts.unstable_options {
- if let Some(a) = matches.opt_default("pretty", "normal") {
- // stable pretty-print variants only
- return Some(parse_pretty_inner(efmt, &a, false));
- }
- }
-
- debugging_opts.unpretty.as_ref().map(|a| {
- // extended with unstable pretty-print variants
- parse_pretty_inner(efmt, &a, true)
- })
+fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Option<PpMode> {
+ use PpMode::*;
+
+ let first = match debugging_opts.unpretty.as_deref()? {
+ "normal" => Source(PpSourceMode::Normal),
+ "identified" => Source(PpSourceMode::Identified),
+ "everybody_loops" => Source(PpSourceMode::EveryBodyLoops),
+ "expanded" => Source(PpSourceMode::Expanded),
+ "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
+ "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
+ "ast-tree" => AstTree(PpAstTreeMode::Normal),
+ "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
+ "hir" => Hir(PpHirMode::Normal),
+ "hir,identified" => Hir(PpHirMode::Identified),
+ "hir,typed" => Hir(PpHirMode::Typed),
+ "hir-tree" => HirTree,
+ "thir-tree" => ThirTree,
+ "mir" => Mir,
+ "mir-cfg" => MirCFG,
+ name => early_error(
+ efmt,
+ &format!(
+ "argument to `unpretty` must be one of `normal`, \
+ `expanded`, `identified`, `expanded,identified`, \
+ `expanded,hygiene`, `everybody_loops`, \
+ `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
+ `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
+ name
+ ),
+ ),
+ };
+ tracing::debug!("got unpretty option: {:?}", first);
+ Some(first)
}
pub fn make_crate_type_option() -> RustcOptGroup {
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpSourceMode {
- /// `--pretty=normal`
+ /// `-Zunpretty=normal`
Normal,
/// `-Zunpretty=everybody_loops`
EveryBodyLoops,
- /// `--pretty=expanded`
+ /// `-Zunpretty=expanded`
Expanded,
- /// `--pretty=identified`
+ /// `-Zunpretty=identified`
Identified,
- /// `--pretty=expanded,identified`
+ /// `-Zunpretty=expanded,identified`
ExpandedIdentified,
- /// `--pretty=expanded,hygiene`
+ /// `-Zunpretty=expanded,hygiene`
ExpandedHygiene,
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpMode {
/// Options that print the source code, i.e.
- /// `--pretty` and `-Zunpretty=everybody_loops`
+ /// `-Zunpretty=normal` and `-Zunpretty=everybody_loops`
Source(PpSourceMode),
AstTree(PpAstTreeMode),
/// Options that print the HIR, i.e. `-Zunpretty=hir`
(default: no)"),
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
+ move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
+ "the size at which the `large_assignments` lint starts to be emitted"),
mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
"emit noalias metadata for mutable references (default: yes for LLVM >= 12, otherwise no)"),
new_llvm_pass_manager: Option<bool> = (None, parse_opt_bool, [TRACKED],
"specify the events recorded by the self profiler;
for example: `-Z self-profile-events=default,query-keys`
all options: none, all, default, generic-activity, query-provider, query-cache-hit
- query-blocked, incr-cache-load, query-keys, function-args, args, llvm"),
+ query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm"),
share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
"make the current crate share its generic instantiations"),
show_span: Option<String> = (None, parse_opt_string, [TRACKED],
"take the brakes off const evaluation. NOTE: this is unsound (default: no)"),
unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
"present the input source, unstable (and less-pretty) variants;
- valid types are any of the types for `--pretty`, as well as:
+ `normal`, `identified`,
`expanded`, `expanded,identified`,
`expanded,hygiene` (with internal representations),
`everybody_loops` (all function bodies replaced with `loop {}`),
use crate::cgu_reuse_tracker::CguReuseTracker;
use crate::code_stats::CodeStats;
pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
-use crate::config::{self, CrateType, OutputType, PrintRequest, SwitchWithOptPath};
+use crate::config::{self, CrateType, OutputType, SwitchWithOptPath};
use crate::filesearch;
use crate::lint::{self, LintId};
use crate::parse::ParseSess;
/// Set of enabled features for the current target.
pub target_features: FxHashSet<Symbol>,
- known_attrs: Lock<MarkedAttrs>,
used_attrs: Lock<MarkedAttrs>,
/// `Span`s for `if` conditions that we have suggested turning into `if let`.
== config::InstrumentCoverage::ExceptUnusedFunctions
}
- pub fn mark_attr_known(&self, attr: &Attribute) {
- self.known_attrs.lock().mark(attr)
- }
-
- pub fn is_attr_known(&self, attr: &Attribute) -> bool {
- self.known_attrs.lock().is_marked(attr)
- }
-
pub fn mark_attr_used(&self, attr: &Attribute) {
self.used_attrs.lock().mark(attr)
}
miri_unleashed_features: Lock::new(Default::default()),
asm_arch,
target_features: FxHashSet::default(),
- known_attrs: Lock::new(MarkedAttrs::new()),
used_attrs: Lock::new(MarkedAttrs::new()),
if_let_suggestions: Default::default(),
};
}
}
- // PGO does not work reliably with panic=unwind on Windows. Let's make it
- // an error to combine the two for now. It always runs into an assertions
- // if LLVM is built with assertions, but without assertions it sometimes
- // does not crash and will probably generate a corrupted binary.
- // We should only display this error if we're actually going to run PGO.
- // If we're just supposed to print out some data, don't show the error (#61002).
- if sess.opts.cg.profile_generate.enabled()
- && sess.target.is_like_msvc
- && sess.panic_strategy() == PanicStrategy::Unwind
- && sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs)
- {
- sess.err(
- "Profile-guided optimization does not yet work in conjunction \
- with `-Cpanic=unwind` on Windows when targeting MSVC. \
- See issue #61002 <https://github.com/rust-lang/rust/issues/61002> \
- for more information.",
- );
- }
-
// Sanitizers can only be used on platforms that we know have working sanitizer codegen.
let supported_sanitizers = sess.target.options.supported_sanitizers;
let unsupported_sanitizers = sess.opts.debugging_opts.sanitizer - supported_sanitizers;
rustc_dump_env_program_clauses,
rustc_dump_program_clauses,
rustc_dump_user_substs,
+ rustc_dump_vtable,
rustc_error,
rustc_evaluate_where_clauses,
rustc_expected_cgu_reuse,
-use crate::spec::{FramePointer, RelroLevel, TargetOptions};
+use crate::spec::{RelroLevel, TargetOptions};
pub fn opts() -> TargetOptions {
TargetOptions {
families: vec!["unix".to_string()],
has_rpath: true,
position_independent_executables: true,
- frame_pointer: FramePointer::Always, // FIXME 43575: should be MayOmit...
relro_level: RelroLevel::Full,
abi_return_struct_as_int: true,
dwarf_version: Some(2),
("armv6-unknown-freebsd", armv6_unknown_freebsd),
("armv7-unknown-freebsd", armv7_unknown_freebsd),
("i686-unknown-freebsd", i686_unknown_freebsd),
+ ("powerpc-unknown-freebsd", powerpc_unknown_freebsd),
("powerpc64-unknown-freebsd", powerpc64_unknown_freebsd),
("powerpc64le-unknown-freebsd", powerpc64le_unknown_freebsd),
("x86_64-unknown-freebsd", x86_64_unknown_freebsd),
--- /dev/null
+use crate::abi::Endian;
+use crate::spec::{LinkerFlavor, RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+ let mut base = super::freebsd_base::opts();
+ base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string());
+ // Extra hint to linker that we are generating secure-PLT code.
+ base.pre_link_args
+ .entry(LinkerFlavor::Gcc)
+ .or_default()
+ .push("--target=powerpc-unknown-freebsd13.0".to_string());
+ base.max_atomic_width = Some(32);
+
+ Target {
+ llvm_target: "powerpc-unknown-freebsd13.0".to_string(),
+ pointer_width: 32,
+ data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
+ arch: "powerpc".to_string(),
+ options: TargetOptions {
+ endian: Endian::Big,
+ features: "+secure-plt".to_string(),
+ relocation_model: RelocModel::Pic,
+ mcount: "_mcount".to_string(),
+ ..base
+ },
+ }
+}
extern crate tracing;
#[macro_use]
extern crate rustc_middle;
+#[macro_use]
+extern crate smallvec;
pub mod autoderef;
pub mod infer;
}
/// Whether member constraints should be generated for all opaque types
+#[derive(Debug)]
pub enum GenerateMemberConstraints {
/// The default, used by typeck
WhenRequired,
opaque_types: &OpaqueTypeMap<'tcx>,
free_region_relations: &FRR,
) {
- debug!("constrain_opaque_types()");
-
for &(opaque_type_key, opaque_defn) in opaque_types {
self.constrain_opaque_type(
opaque_type_key,
}
/// See `constrain_opaque_types` for documentation.
+ #[instrument(level = "debug", skip(self, free_region_relations))]
fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
) {
let def_id = opaque_type_key.def_id;
- debug!("constrain_opaque_type()");
- debug!("constrain_opaque_type: def_id={:?}", def_id);
- debug!("constrain_opaque_type: opaque_defn={:#?}", opaque_defn);
-
let tcx = self.tcx;
let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
- debug!("constrain_opaque_type: concrete_ty={:?}", concrete_ty);
+ debug!(?concrete_ty);
let first_own_region = match opaque_defn.origin {
hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => {
// type foo::<'p0..'pn>::Foo<'q0..'qm>
// fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
//
- // For these types we onlt iterate over `'l0..lm` below.
+ // For these types we only iterate over `'l0..lm` below.
tcx.generics_of(def_id).parent_count
}
// These opaque type inherit all lifetime parameters from their
// If there are required region bounds, we can use them.
if opaque_defn.has_required_region_bounds {
let bounds = tcx.explicit_item_bounds(def_id);
- debug!("constrain_opaque_type: predicates: {:#?}", bounds);
+ debug!("{:#?}", bounds);
let bounds: Vec<_> =
bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs)).collect();
- debug!("constrain_opaque_type: bounds={:#?}", bounds);
+ debug!("{:#?}", bounds);
let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs);
let required_region_bounds =
};
// Compute the least upper bound of it with the other regions.
- debug!("constrain_opaque_types: least_region={:?}", least_region);
- debug!("constrain_opaque_types: subst_region={:?}", subst_region);
+ debug!(?least_region);
+ debug!(?subst_region);
match least_region {
None => least_region = Some(subst_region),
Some(lr) => {
}
let least_region = least_region.unwrap_or(tcx.lifetimes.re_static);
- debug!("constrain_opaque_types: least_region={:?}", least_region);
+ debug!(?least_region);
if let GenerateMemberConstraints::IfNoStaticBound = mode {
if least_region != tcx.lifetimes.re_static {
SelectionError::Unimplemented => {
// If this obligation was generated as a result of well-formed checking, see if we
// can get a better error message by performing HIR-based well formed checking.
- if let ObligationCauseCode::WellFormed(Some(wf_hir_id)) =
+ if let ObligationCauseCode::WellFormed(Some(wf_loc)) =
root_obligation.cause.code.peel_derives()
{
if let Some(cause) =
- self.tcx.diagnostic_hir_wf_check((obligation.predicate, *wf_hir_id))
+ self.tcx.diagnostic_hir_wf_check((obligation.predicate, wf_loc.clone()))
{
obligation.cause = cause;
span = obligation.cause.span;
}
}
GeneratorInteriorOrUpvar::Upvar(upvar_span) => {
+ // `Some(ref_ty)` if `target_ty` is `&T` and `T` fails to impl `Sync`
+ let refers_to_non_sync = match target_ty.kind() {
+ ty::Ref(_, ref_ty, _) => match self.evaluate_obligation(&obligation) {
+ Ok(eval) if !eval.may_apply() => Some(ref_ty),
+ _ => None,
+ },
+ _ => None,
+ };
+
+ let (span_label, span_note) = match refers_to_non_sync {
+ // if `target_ty` is `&T` and `T` fails to impl `Sync`,
+ // include suggestions to make `T: Sync` so that `&T: Send`
+ Some(ref_ty) => (
+ format!(
+ "has type `{}` which {}, because `{}` is not `Sync`",
+ target_ty, trait_explanation, ref_ty
+ ),
+ format!(
+ "captured value {} because `&` references cannot be sent unless their referent is `Sync`",
+ trait_explanation
+ ),
+ ),
+ None => (
+ format!("has type `{}` which {}", target_ty, trait_explanation),
+ format!("captured value {}", trait_explanation),
+ ),
+ };
+
let mut span = MultiSpan::from_span(upvar_span);
- span.push_span_label(
- upvar_span,
- format!("has type `{}` which {}", target_ty, trait_explanation),
- );
- err.span_note(span, &format!("captured value {}", trait_explanation));
+ span.push_span_label(upvar_span, span_label);
+ err.span_note(span, &span_note);
}
}
let project_obligation = obligation.with(binder.rebind(data));
self.process_projection_obligation(
+ obligation,
project_obligation,
&mut pending_obligation.stalled_on,
)
let project_obligation = obligation.with(Binder::dummy(*data));
self.process_projection_obligation(
+ obligation,
project_obligation,
&mut pending_obligation.stalled_on,
)
fn process_projection_obligation(
&mut self,
+ obligation: &PredicateObligation<'tcx>,
project_obligation: PolyProjectionObligation<'tcx>,
stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
let tcx = self.selcx.tcx();
+
+ if obligation.predicate.is_global() {
+ // no type variables present, can use evaluation for better caching.
+ // FIXME: consider caching errors too.
+ if self.selcx.infcx().predicate_must_hold_considering_regions(obligation) {
+ return ProcessResult::Changed(vec![]);
+ } else {
+ tracing::debug!("Does NOT hold: {:?}", obligation);
+ }
+ }
+
match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)),
Ok(Ok(None)) => {
self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, WithConstness,
COMMON_VTABLE_ENTRIES,
};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
+use smallvec::SmallVec;
use std::fmt::Debug;
+use std::ops::ControlFlow;
pub use self::FulfillmentErrorCode::*;
pub use self::ImplSource::*;
result
}
+#[derive(Clone, Debug)]
+enum VtblSegment<'tcx> {
+ MetadataDSA,
+ TraitOwnEntries { trait_ref: ty::PolyTraitRef<'tcx>, emit_vptr: bool },
+}
+
+/// Prepare the segments for a vtable
+fn prepare_vtable_segments<'tcx, T>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>,
+) -> Option<T> {
+ // The following constraints holds for the final arrangement.
+ // 1. The whole virtual table of the first direct super trait is included as the
+ // the prefix. If this trait doesn't have any super traits, then this step
+ // consists of the dsa metadata.
+ // 2. Then comes the proper pointer metadata(vptr) and all own methods for all
+ // other super traits except those already included as part of the first
+ // direct super trait virtual table.
+ // 3. finally, the own methods of this trait.
+
+ // This has the advantage that trait upcasting to the first direct super trait on each level
+ // is zero cost, and to another trait includes only replacing the pointer with one level indirection,
+ // while not using too much extra memory.
+
+ // For a single inheritance relationship like this,
+ // D --> C --> B --> A
+ // The resulting vtable will consists of these segments:
+ // DSA, A, B, C, D
+
+ // For a multiple inheritance relationship like this,
+ // D --> C --> A
+ // \-> B
+ // The resulting vtable will consists of these segments:
+ // DSA, A, B, B-vptr, C, D
+
+ // For a diamond inheritance relationship like this,
+ // D --> B --> A
+ // \-> C -/
+ // The resulting vtable will consists of these segments:
+ // DSA, A, B, C, C-vptr, D
+
+ // For a more complex inheritance relationship like this:
+ // O --> G --> C --> A
+ // \ \ \-> B
+ // | |-> F --> D
+ // | \-> E
+ // |-> N --> J --> H
+ // \ \-> I
+ // |-> M --> K
+ // \-> L
+ // The resulting vtable will consists of these segments:
+ // DSA, A, B, B-vptr, C, D, D-vptr, E, E-vptr, F, F-vptr, G,
+ // H, H-vptr, I, I-vptr, J, J-vptr, K, K-vptr, L, L-vptr, M, M-vptr,
+ // N, N-vptr, O
+
+ // emit dsa segment first.
+ if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::MetadataDSA) {
+ return Some(v);
+ }
+
+ let mut emit_vptr_on_new_entry = false;
+ let mut visited = util::PredicateSet::new(tcx);
+ let predicate = trait_ref.without_const().to_predicate(tcx);
+ let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> =
+ smallvec![(trait_ref, emit_vptr_on_new_entry, None)];
+ visited.insert(predicate);
+
+ // the main traversal loop:
+ // basically we want to cut the inheritance directed graph into a few non-overlapping slices of nodes
+ // that each node is emited after all its descendents have been emitted.
+ // so we convert the directed graph into a tree by skipping all previously visted nodes using a visited set.
+ // this is done on the fly.
+ // Each loop run emits a slice - it starts by find a "childless" unvisited node, backtracking upwards, and it
+ // stops after it finds a node that has a next-sibling node.
+ // This next-sibling node will used as the starting point of next slice.
+
+ // Example:
+ // For a diamond inheritance relationship like this,
+ // D#1 --> B#0 --> A#0
+ // \-> C#1 -/
+
+ // Starting point 0 stack [D]
+ // Loop run #0: Stack after diving in is [D B A], A is "childless"
+ // after this point, all newly visited nodes won't have a vtable that equals to a prefix of this one.
+ // Loop run #0: Emiting the slice [B A] (in reverse order), B has a next-sibling node, so this slice stops here.
+ // Loop run #0: Stack after exiting out is [D C], C is the next starting point.
+ // Loop run #1: Stack after diving in is [D C], C is "childless", since its child A is skipped(already emitted).
+ // Loop run #1: Emiting the slice [D C] (in reverse order). No one has a next-sibling node.
+ // Loop run #1: Stack after exiting out is []. Now the function exits.
+
+ loop {
+ // dive deeper into the stack, recording the path
+ 'diving_in: loop {
+ if let Some((inner_most_trait_ref, _, _)) = stack.last() {
+ let inner_most_trait_ref = *inner_most_trait_ref;
+ let mut direct_super_traits_iter = tcx
+ .super_predicates_of(inner_most_trait_ref.def_id())
+ .predicates
+ .into_iter()
+ .filter_map(move |(pred, _)| {
+ pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_ref()
+ });
+
+ 'diving_in_skip_visited_traits: loop {
+ if let Some(next_super_trait) = direct_super_traits_iter.next() {
+ if visited.insert(next_super_trait.to_predicate(tcx)) {
+ stack.push((
+ next_super_trait.value,
+ emit_vptr_on_new_entry,
+ Some(direct_super_traits_iter),
+ ));
+ break 'diving_in_skip_visited_traits;
+ } else {
+ continue 'diving_in_skip_visited_traits;
+ }
+ } else {
+ break 'diving_in;
+ }
+ }
+ }
+ }
+
+ // Other than the left-most path, vptr should be emitted for each trait.
+ emit_vptr_on_new_entry = true;
+
+ // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level.
+ 'exiting_out: loop {
+ if let Some((inner_most_trait_ref, emit_vptr, siblings_opt)) = stack.last_mut() {
+ if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::TraitOwnEntries {
+ trait_ref: *inner_most_trait_ref,
+ emit_vptr: *emit_vptr,
+ }) {
+ return Some(v);
+ }
+
+ 'exiting_out_skip_visited_traits: loop {
+ if let Some(siblings) = siblings_opt {
+ if let Some(next_inner_most_trait_ref) = siblings.next() {
+ if visited.insert(next_inner_most_trait_ref.to_predicate(tcx)) {
+ *inner_most_trait_ref = next_inner_most_trait_ref.value;
+ *emit_vptr = emit_vptr_on_new_entry;
+ break 'exiting_out;
+ } else {
+ continue 'exiting_out_skip_visited_traits;
+ }
+ }
+ }
+ stack.pop();
+ continue 'exiting_out;
+ }
+ }
+ // all done
+ return None;
+ }
+ }
+}
+
+fn dump_vtable_entries<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ sp: Span,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ entries: &[VtblEntry<'tcx>],
+) {
+ let msg = format!("Vtable entries for `{}`: {:#?}", trait_ref, entries);
+ tcx.sess.struct_span_err(sp, &msg).emit();
+}
+
/// Given a trait `trait_ref`, iterates the vtable entries
/// that come from `trait_ref`, including its supertraits.
fn vtable_entries<'tcx>(
) -> &'tcx [VtblEntry<'tcx>] {
debug!("vtable_entries({:?})", trait_ref);
- let entries = COMMON_VTABLE_ENTRIES.iter().cloned().chain(
- supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
- let trait_methods = tcx
- .associated_items(trait_ref.def_id())
- .in_definition_order()
- .filter(|item| item.kind == ty::AssocKind::Fn);
-
- // Now list each method's DefId and InternalSubsts (for within its trait).
- // If the method can never be called from this object, produce `Vacant`.
- trait_methods.map(move |trait_method| {
- debug!("vtable_entries: trait_method={:?}", trait_method);
- let def_id = trait_method.def_id;
-
- // Some methods cannot be called on an object; skip those.
- if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
- debug!("vtable_entries: not vtable safe");
- return VtblEntry::Vacant;
- }
+ let mut entries = vec![];
- // The method may have some early-bound lifetimes; add regions for those.
- let substs = trait_ref.map_bound(|trait_ref| {
- InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
- GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
- GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
- trait_ref.substs[param.index as usize]
- }
- })
+ let vtable_segment_callback = |segment| -> ControlFlow<()> {
+ match segment {
+ VtblSegment::MetadataDSA => {
+ entries.extend(COMMON_VTABLE_ENTRIES);
+ }
+ VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+ let trait_methods = tcx
+ .associated_items(trait_ref.def_id())
+ .in_definition_order()
+ .filter(|item| item.kind == ty::AssocKind::Fn);
+ // Now list each method's DefId and InternalSubsts (for within its trait).
+ // If the method can never be called from this object, produce `Vacant`.
+ let own_entries = trait_methods.map(move |trait_method| {
+ debug!("vtable_entries: trait_method={:?}", trait_method);
+ let def_id = trait_method.def_id;
+
+ // Some methods cannot be called on an object; skip those.
+ if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
+ debug!("vtable_entries: not vtable safe");
+ return VtblEntry::Vacant;
+ }
+
+ // The method may have some early-bound lifetimes; add regions for those.
+ let substs = trait_ref.map_bound(|trait_ref| {
+ InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
+ GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+ GenericParamDefKind::Type { .. }
+ | GenericParamDefKind::Const { .. } => {
+ trait_ref.substs[param.index as usize]
+ }
+ })
+ });
+
+ // The trait type may have higher-ranked lifetimes in it;
+ // erase them if they appear, so that we get the type
+ // at some particular call site.
+ let substs = tcx
+ .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
+
+ // It's possible that the method relies on where-clauses that
+ // do not hold for this particular set of type parameters.
+ // Note that this method could then never be called, so we
+ // do not want to try and codegen it, in that case (see #23435).
+ let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
+ if impossible_predicates(tcx, predicates.predicates) {
+ debug!("vtable_entries: predicates do not hold");
+ return VtblEntry::Vacant;
+ }
+
+ let instance = ty::Instance::resolve_for_vtable(
+ tcx,
+ ty::ParamEnv::reveal_all(),
+ def_id,
+ substs,
+ )
+ .expect("resolution failed during building vtable representation");
+ VtblEntry::Method(instance)
});
- // The trait type may have higher-ranked lifetimes in it;
- // erase them if they appear, so that we get the type
- // at some particular call site.
- let substs =
- tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
-
- // It's possible that the method relies on where-clauses that
- // do not hold for this particular set of type parameters.
- // Note that this method could then never be called, so we
- // do not want to try and codegen it, in that case (see #23435).
- let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
- if impossible_predicates(tcx, predicates.predicates) {
- debug!("vtable_entries: predicates do not hold");
- return VtblEntry::Vacant;
+ entries.extend(own_entries);
+
+ if emit_vptr {
+ entries.push(VtblEntry::TraitVPtr(trait_ref));
}
+ }
+ }
- VtblEntry::Method(def_id, substs)
- })
- }),
- );
+ ControlFlow::Continue(())
+ };
+
+ let _ = prepare_vtable_segments(tcx, trait_ref, vtable_segment_callback);
+
+ if tcx.has_attr(trait_ref.def_id(), sym::rustc_dump_vtable) {
+ let sp = tcx.def_span(trait_ref.def_id());
+ dump_vtable_entries(tcx, sp, trait_ref, &entries);
+ }
- tcx.arena.alloc_from_iter(entries)
+ tcx.arena.alloc_from_iter(entries.into_iter())
}
/// Find slot base for trait methods within vtable entries of another trait
) -> usize {
let (trait_to_be_found, trait_owning_vtable) = key;
- let mut supertraits = util::supertraits(tcx, trait_owning_vtable);
+ let vtable_segment_callback = {
+ let mut vtable_base = 0;
+
+ move |segment| {
+ match segment {
+ VtblSegment::MetadataDSA => {
+ vtable_base += COMMON_VTABLE_ENTRIES.len();
+ }
+ VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+ if trait_ref == trait_to_be_found {
+ return ControlFlow::Break(vtable_base);
+ }
+ vtable_base += util::count_own_vtable_entries(tcx, trait_ref);
+ if emit_vptr {
+ vtable_base += 1;
+ }
+ }
+ }
+ ControlFlow::Continue(())
+ }
+ };
+
+ if let Some(vtable_base) =
+ prepare_vtable_segments(tcx, trait_owning_vtable, vtable_segment_callback)
+ {
+ vtable_base
+ } else {
+ bug!("Failed to find info for expected trait in vtable");
+ }
+}
+
+/// Find slot offset for trait vptr within vtable entries of another trait
+/// FIXME: This function is not yet used. Remove `#[allow(dead_code)]` when it's used in upcoming pr.
+#[allow(dead_code)]
+fn vtable_trait_vptr_slot_offset<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ key: (
+ ty::PolyTraitRef<'tcx>, // trait_to_be_found
+ ty::PolyTraitRef<'tcx>, // trait_owning_vtable
+ ),
+) -> Option<usize> {
+ let (trait_to_be_found, trait_owning_vtable) = key;
+
+ let vtable_segment_callback = {
+ let mut vptr_offset = 0;
+ move |segment| {
+ match segment {
+ VtblSegment::MetadataDSA => {
+ vptr_offset += COMMON_VTABLE_ENTRIES.len();
+ }
+ VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+ vptr_offset += util::count_own_vtable_entries(tcx, trait_ref);
+ if trait_ref == trait_to_be_found {
+ if emit_vptr {
+ return ControlFlow::Break(Some(vptr_offset));
+ } else {
+ return ControlFlow::Break(None);
+ }
+ }
- // For each of the non-matching predicates that
- // we pass over, we sum up the set of number of vtable
- // entries, so that we can compute the offset for the selected
- // trait.
- let vtable_base = ty::COMMON_VTABLE_ENTRIES.len()
- + supertraits
- .by_ref()
- .take_while(|t| *t != trait_to_be_found)
- .map(|t| util::count_own_vtable_entries(tcx, t))
- .sum::<usize>();
+ if emit_vptr {
+ vptr_offset += 1;
+ }
+ }
+ }
+ ControlFlow::Continue(())
+ }
+ };
- vtable_base
+ if let Some(vptr_offset) =
+ prepare_vtable_segments(tcx, trait_owning_vtable, vtable_segment_callback)
+ {
+ vptr_offset
+ } else {
+ bug!("Failed to find info for expected trait in vtable");
+ }
}
pub fn provide(providers: &mut ty::query::Providers) {
obligation: &PredicateObligation<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
let mut _orig_values = OriginalQueryValues::default();
- let c_pred = self
- .canonicalize_query(obligation.param_env.and(obligation.predicate), &mut _orig_values);
+ let c_pred = self.canonicalize_query_keep_static(
+ obligation.param_env.and(obligation.predicate),
+ &mut _orig_values,
+ );
// Run canonical query. If overflow occurs, rerun from scratch but this time
// in standard trait query mode so that overflow is handled appropriately
// within `SelectionContext`.
// so we cannot canonicalize it.
let c_data = self
.infcx
- .canonicalize_hr_query_hack(self.param_env.and(data), &mut orig_values);
+ .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
match tcx.normalize_projection_ty(c_data) {
// so we cannot canonicalize it.
let c_data = self
.infcx
- .canonicalize_hr_query_hack(self.param_env.and(data), &mut orig_values);
+ .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
let normalized_ty = match tcx.normalize_projection_ty(c_data) {
}
// FIXME(#33684) -- We need to use
- // `canonicalize_hr_query_hack` here because of things
+ // `canonicalize_query_keep_static` here because of things
// like the subtype query, which go awry around
// `'static` otherwise.
let mut canonical_var_values = OriginalQueryValues::default();
let old_param_env = query_key.param_env;
- let canonical_self = infcx.canonicalize_hr_query_hack(query_key, &mut canonical_var_values);
+ let canonical_self =
+ infcx.canonicalize_query_keep_static(query_key, &mut canonical_var_values);
let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?;
let InferOk { value, obligations } = infcx
pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
SelectionContext {
infcx,
- freshener: infcx.freshener(),
+ freshener: infcx.freshener_keep_static(),
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
SelectionContext {
infcx,
- freshener: infcx.freshener(),
+ freshener: infcx.freshener_keep_static(),
intercrate: true,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
debug!(?allow_negative_impls, "with_negative");
SelectionContext {
infcx,
- freshener: infcx.freshener(),
+ freshener: infcx.freshener_keep_static(),
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls,
debug!(?query_mode, "with_query_mode");
SelectionContext {
infcx,
- freshener: infcx.freshener(),
+ freshener: infcx.freshener_keep_static(),
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{Constness, GenericArg, GenericArgs};
-use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
+use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{self, Const, DefIdTree, Ty, TyCtxt, TypeFoldable};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
tcx.ty_error().into()
} else {
// This is a default type parameter.
+ let substs = substs.unwrap();
+ if substs.iter().any(|arg| match arg.unpack() {
+ GenericArgKind::Type(ty) => ty.references_error(),
+ _ => false,
+ }) {
+ // Avoid ICE #86756 when type error recovery goes awry.
+ return tcx.ty_error().into();
+ }
self.astconv
.normalize_ty(
self.span,
tcx.at(self.span).type_of(param.def_id).subst_spanned(
tcx,
- substs.unwrap(),
+ substs,
Some(self.span),
),
)
this does nothing because the given bound is not \
a default; only `?Sized` is supported",
);
+ return false;
}
}
}
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::{
self, ObligationCause, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt,
+ WellFormedLoc,
};
use std::collections::hash_map::Entry;
&self,
span: Span,
value: T,
- hir_id: hir::HirId,
+ loc: WellFormedLoc,
) -> T
where
T: TypeFoldable<'tcx>,
{
self.inh.normalize_associated_types_in_with_cause(
- ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(Some(hir_id))),
+ ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(Some(loc))),
self.param_env,
value,
)
self.borrow(assignee_place, diag_expr_id, ty::BorrowKind::MutBorrow);
}
}
-
-/// Truncate projections so that following rules are obeyed by the captured `place`:
+/// Truncate `place` so that an `unsafe` block isn't required to capture it.
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
/// them completely.
-/// - No Index projections are captured, since arrays are captured completely.
-fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
+/// - No projections are applied on top of Union ADTs, since these require unsafe blocks.
+fn restrict_precision_for_unsafe(mut place: Place<'tcx>) -> Place<'tcx> {
if place.projections.is_empty() {
// Nothing to do here
return place;
return place;
}
- let mut truncated_length = usize::MAX;
+ if place.base_ty.is_union() {
+ place.projections.truncate(0);
+ return place;
+ }
for (i, proj) in place.projections.iter().enumerate() {
if proj.ty.is_unsafe_ptr() {
- // Don't apply any projections on top of an unsafe ptr
- truncated_length = truncated_length.min(i + 1);
+ // Don't apply any projections on top of an unsafe ptr.
+ place.projections.truncate(i + 1);
break;
}
+
+ if proj.ty.is_union() {
+ // Don't capture preicse fields of a union.
+ place.projections.truncate(i + 1);
+ break;
+ }
+ }
+
+ place
+}
+
+/// Truncate projections so that following rules are obeyed by the captured `place`:
+/// - No Index projections are captured, since arrays are captured completely.
+/// - No unsafe block is required to capture `place`
+/// Truncate projections so that following rules are obeyed by the captured `place`:
+fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
+ place = restrict_precision_for_unsafe(place);
+
+ if place.projections.is_empty() {
+ // Nothing to do here
+ return place;
+ }
+
+ for (i, proj) in place.projections.iter().enumerate() {
match proj.kind {
ProjectionKind::Index => {
// Arrays are completely captured, so we drop Index projections
- truncated_length = truncated_length.min(i);
+ place.projections.truncate(i);
break;
}
ProjectionKind::Deref => {}
}
}
- let length = place.projections.len().min(truncated_length);
-
- place.projections.truncate(length);
-
place
}
use rustc_span::Span;
use rustc_trait_selection::opaque_types::may_define_opaque_type;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
+use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc};
+use std::convert::TryInto;
use std::iter;
use std::ops::ControlFlow;
span: Span,
sig_if_method: Option<&hir::FnSig<'_>>,
) {
- let code = ObligationCauseCode::WellFormed(Some(item_id));
+ let code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id.expect_owner())));
for_id(tcx, item_id, span).with_fcx(|fcx| {
let item = fcx.tcx.associated_item(fcx.tcx.hir().local_def_id(item_id));
match item.kind {
ty::AssocKind::Const => {
let ty = fcx.tcx.type_of(item.def_id);
- let ty = fcx.normalize_associated_types_in_wf(span, ty, item_id);
+ let ty = fcx.normalize_associated_types_in_wf(
+ span,
+ ty,
+ WellFormedLoc::Ty(item_id.expect_owner()),
+ );
fcx.register_wf_obligation(ty.into(), span, code.clone());
}
ty::AssocKind::Fn => {
}
if item.defaultness.has_value() {
let ty = fcx.tcx.type_of(item.def_id);
- let ty = fcx.normalize_associated_types_in_wf(span, ty, item_id);
+ let ty = fcx.normalize_associated_types_in_wf(
+ span,
+ ty,
+ WellFormedLoc::Ty(item_id.expect_owner()),
+ );
fcx.register_wf_obligation(ty.into(), span, code.clone());
}
}
fcx.register_wf_obligation(
field.ty.into(),
field.span,
- // We don't have an HIR id for the field
- ObligationCauseCode::WellFormed(None),
+ ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(field.def_id))),
)
}
for_id(tcx, item_id, ty_span).with_fcx(|fcx| {
let ty = tcx.type_of(tcx.hir().local_def_id(item_id));
- let item_ty = fcx.normalize_associated_types_in_wf(ty_span, ty, item_id);
+ let item_ty = fcx.normalize_associated_types_in_wf(
+ ty_span,
+ ty,
+ WellFormedLoc::Ty(item_id.expect_owner()),
+ );
let mut forbid_unsized = true;
if allow_foreign_ty {
fcx.register_wf_obligation(
item_ty.into(),
ty_span,
- ObligationCauseCode::WellFormed(Some(item_id)),
+ ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id.expect_owner()))),
);
if forbid_unsized {
fcx.register_bound(
fcx.register_wf_obligation(
self_ty.into(),
ast_self_ty.span,
- ObligationCauseCode::WellFormed(Some(item.hir_id())),
+ ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(
+ item.hir_id().expect_owner(),
+ ))),
);
}
}
implied_bounds: &mut Vec<Ty<'tcx>>,
) {
let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig);
- let sig = fcx.normalize_associated_types_in(span, sig);
- for (&input_ty, ty) in iter::zip(sig.inputs(), hir_decl.inputs) {
- fcx.register_wf_obligation(input_ty.into(), ty.span, ObligationCauseCode::WellFormed(None));
+ // 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 =
+ fcx.tcx.mk_type_list(inputs_and_output.iter().enumerate().map(|(i, ty)| {
+ fcx.normalize_associated_types_in_wf(
+ span,
+ ty,
+ WellFormedLoc::Param {
+ function: def_id.expect_local(),
+ // 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(),
+ },
+ )
+ }));
+ // Manually call `normalize_assocaited_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: fcx.normalize_associated_types_in(span, c_variadic),
+ unsafety: fcx.normalize_associated_types_in(span, unsafety),
+ abi: fcx.normalize_associated_types_in(span, abi),
+ };
+
+ for (i, (&input_ty, ty)) in iter::zip(sig.inputs(), hir_decl.inputs).enumerate() {
+ fcx.register_wf_obligation(
+ input_ty.into(),
+ ty.span,
+ ObligationCauseCode::WellFormed(Some(WellFormedLoc::Param {
+ function: def_id.expect_local(),
+ param_idx: i.try_into().unwrap(),
+ })),
+ );
}
+
implied_bounds.extend(sig.inputs());
fcx.register_wf_obligation(
struct AdtField<'tcx> {
ty: Ty<'tcx>,
+ def_id: LocalDefId,
span: Span,
}
.fields()
.iter()
.map(|field| {
- let field_ty = self.tcx.type_of(self.tcx.hir().local_def_id(field.hir_id));
+ let def_id = self.tcx.hir().local_def_id(field.hir_id);
+ let field_ty = self.tcx.type_of(def_id);
let field_ty = self.normalize_associated_types_in(field.ty.span, field_ty);
let field_ty = self.resolve_vars_if_possible(field_ty);
debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty);
- AdtField { ty: field_ty, span: field.ty.span }
+ AdtField { ty: field_ty, span: field.ty.span, def_id }
})
.collect();
AdtVariant { fields, explicit_discr: None }
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None
} else if tcx.lazy_normalization() {
+ if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
+ // If the def_id we are calling generics_of on is an anon ct default i.e:
+ //
+ // struct Foo<const N: usize = { .. }>;
+ // ^^^ ^ ^^^^^^ def id of this anon const
+ // ^ ^ param_id
+ // ^ parent_def_id
+ //
+ // then we only want to return generics for params to the left of `N`. If we don't do that we
+ // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, substs: [N#0])`.
+ //
+ // This causes ICEs (#86580) when building the substs for Foo in `fn foo() -> Foo { .. }` as
+ // we substitute the defaults with the partially built substs when we build the substs. Subst'ing
+ // the `N#0` on the unevaluated const indexes into the empty substs we're in the process of building.
+ //
+ // We fix this by having this function return the parent's generics ourselves and truncating the
+ // generics to only include non-forward declared params (with the exception of the `Self` ty)
+ //
+ // For the above code example that means we want `substs: []`
+ // For the following struct def we want `substs: [N#0]` when generics_of is called on
+ // the def id of the `{ N + 1 }` anon const
+ // struct Foo<const N: usize, const M: usize = { N + 1 }>;
+ //
+ // This has some implications for how we get the predicates available to the anon const
+ // see `explicit_predicates_of` for more information on this
+ let generics = tcx.generics_of(parent_def_id.to_def_id());
+ let param_def = tcx.hir().local_def_id(param_id).to_def_id();
+ let param_def_idx = generics.param_def_id_to_index[¶m_def];
+ // In the above example this would be .params[..N#0]
+ let params = generics.params[..param_def_idx as usize].to_owned();
+ let param_def_id_to_index =
+ params.iter().map(|param| (param.def_id, param.index)).collect();
+
+ return ty::Generics {
+ // we set the parent of these generics to be our parent's parent so that we
+ // dont end up with substs: [N, M, N] for the const default on a struct like this:
+ // struct Foo<const N: usize, const M: usize = { ... }>;
+ parent: generics.parent,
+ parent_count: generics.parent_count,
+ params,
+ param_def_id_to_index,
+ has_self: generics.has_self,
+ has_late_bound_regions: generics.has_late_bound_regions,
+ };
+ }
+
// HACK(eddyb) this provides the correct generics when
// `feature(const_generics)` is enabled, so that const expressions
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
}
fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
- if let DefKind::Trait = tcx.def_kind(def_id) {
+ let def_kind = tcx.def_kind(def_id);
+ if let DefKind::Trait = def_kind {
// Remove bounds on associated types from the predicates, they will be
// returned by `explicit_item_bounds`.
let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
}
}
} else {
+ if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
+ // In `generics_of` we set the generics' parent to be our parent's parent which means that
+ // we lose out on the predicates of our actual parent if we dont return those predicates here.
+ // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
+ //
+ // struct Foo<T, const N: usize = { <T as Trait>::ASSOC }>(T) where T: Trait;
+ // ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling
+ // ^^^ explicit_predicates_of on
+ // parent item we dont have set as the
+ // parent of generics returned by `generics_of`
+ //
+ // In the above code we want the anon const to have predicates in its param env for `T: Trait`
+ let item_id = tcx.hir().get_parent_item(hir_id);
+ let item_def_id = tcx.hir().local_def_id(item_id).to_def_id();
+ // In the above code example we would be calling `explicit_predicates_of(Foo)` here
+ return tcx.explicit_predicates_of(item_def_id);
+ }
+ }
gather_explicit_predicates_of(tcx, def_id)
}
}
let concrete_ty = tcx
.mir_borrowck(owner.expect_local())
.concrete_opaque_types
- .get_by(|(key, _)| key.def_id == def_id.to_def_id())
+ .get_value_matching(|(key, _)| key.def_id == def_id.to_def_id())
.map(|concrete_ty| *concrete_ty)
.unwrap_or_else(|| {
tcx.sess.delay_span_bug(
struct ConstraintLocator<'tcx> {
tcx: TyCtxt<'tcx>,
+
+ /// def_id of the opaque type whose defining uses are being checked
def_id: DefId,
- // (first found type span, actual type)
+
+ /// as we walk the defining uses, we are checking that all of them
+ /// define the same hidden type. This variable is set to `Some`
+ /// with the first type that we find, and then later types are
+ /// checked against it (we also carry the span of that first
+ /// type).
found: Option<(Span, Ty<'tcx>)>,
}
.tcx
.typeck(def_id)
.concrete_opaque_types
- .get_by(|(key, _)| key.def_id == self.def_id)
+ .any_value_matching(|(key, _)| key.def_id == self.def_id)
.is_none()
{
debug!("no constraints in typeck results");
/// When the current body being handled is a closure, then we must make sure that
/// - The parent closure only captures Places from the nested closure that are not local to it.
///
- /// In the following example the closures `c` only captures `p.x`` even though `incr`
+ /// In the following example the closures `c` only captures `p.x` even though `incr`
/// is a capture of the nested closure
///
/// ```rust,ignore(cannot-test-this-because-pseudo-code)
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::HirId;
use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::ObligationCause;
use rustc_infer::traits::TraitEngine;
+use rustc_infer::traits::{ObligationCause, WellFormedLoc};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, ToPredicate, TyCtxt};
+use rustc_middle::ty::{self, Region, ToPredicate, TyCtxt, TypeFoldable, TypeFolder};
use rustc_trait_selection::traits;
pub fn provide(providers: &mut Providers) {
// need access to `ItemCtxt`
fn diagnostic_hir_wf_check<'tcx>(
tcx: TyCtxt<'tcx>,
- (predicate, hir_id): (ty::Predicate<'tcx>, HirId),
+ (predicate, loc): (ty::Predicate<'tcx>, WellFormedLoc),
) -> Option<ObligationCause<'tcx>> {
let hir = tcx.hir();
- // HIR wfcheck should only ever happen as part of improving an existing error
- tcx.sess.delay_span_bug(hir.span(hir_id), "Performed HIR wfcheck without an existing error!");
- // Currently, we only handle WF checking for items (e.g. associated items).
- // It would be nice to extend this to handle wf checks inside functions.
- let def_id = match tcx.hir().opt_local_def_id(hir_id) {
- Some(def_id) => def_id,
- None => return None,
+ let def_id = match loc {
+ WellFormedLoc::Ty(def_id) => def_id,
+ WellFormedLoc::Param { function, param_idx: _ } => function,
};
+ let hir_id = hir.local_def_id_to_hir_id(def_id);
+
+ // HIR wfcheck should only ever happen as part of improving an existing error
+ tcx.sess
+ .delay_span_bug(tcx.def_span(def_id), "Performed HIR wfcheck without an existing error!");
- // FIXME - figure out how we want to handle wf-checking for
- // things inside a function body.
let icx = ItemCtxt::new(tcx, def_id.to_def_id());
// To perform HIR-based WF checking, we iterate over all HIR types
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
self.tcx.infer_ctxt().enter(|infcx| {
let mut fulfill = traits::FulfillmentContext::new();
- let tcx_ty = self.icx.to_ty(ty);
+ let tcx_ty =
+ self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
let cause = traits::ObligationCause::new(
ty.span,
self.hir_id,
depth: 0,
};
- let ty = match tcx.hir().get(hir_id) {
- hir::Node::ImplItem(item) => match item.kind {
- hir::ImplItemKind::TyAlias(ty) => Some(ty),
- _ => None,
- },
- hir::Node::TraitItem(item) => match item.kind {
- hir::TraitItemKind::Type(_, ty) => ty,
- _ => None,
+ // Get the starting `hir::Ty` using our `WellFormedLoc`.
+ // We will walk 'into' this type to try to find
+ // a more precise span for our predicate.
+ let ty = match loc {
+ WellFormedLoc::Ty(_) => match hir.get(hir_id) {
+ hir::Node::ImplItem(item) => match item.kind {
+ hir::ImplItemKind::TyAlias(ty) => Some(ty),
+ ref item => bug!("Unexpected ImplItem {:?}", item),
+ },
+ hir::Node::TraitItem(item) => match item.kind {
+ hir::TraitItemKind::Type(_, ty) => ty,
+ ref item => bug!("Unexpected TraitItem {:?}", item),
+ },
+ hir::Node::Item(item) => match item.kind {
+ hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => Some(ty),
+ hir::ItemKind::Impl(ref impl_) => {
+ assert!(impl_.of_trait.is_none(), "Unexpected trait impl: {:?}", impl_);
+ Some(impl_.self_ty)
+ }
+ ref item => bug!("Unexpected item {:?}", item),
+ },
+ hir::Node::Field(field) => Some(field.ty),
+ ref node => bug!("Unexpected node {:?}", node),
},
- _ => None,
+ WellFormedLoc::Param { function: _, param_idx } => {
+ let fn_decl = hir.fn_decl_by_hir_id(hir_id).unwrap();
+ // Get return type
+ if param_idx as usize == fn_decl.inputs.len() {
+ match fn_decl.output {
+ hir::FnRetTy::Return(ty) => Some(ty),
+ // The unit type `()` is always well-formed
+ hir::FnRetTy::DefaultReturn(_span) => None,
+ }
+ } else {
+ Some(&fn_decl.inputs[param_idx as usize])
+ }
+ }
};
if let Some(ty) = ty {
visitor.visit_ty(ty);
}
visitor.cause
}
+
+struct EraseAllBoundRegions<'tcx> {
+ tcx: TyCtxt<'tcx>,
+}
+
+// Higher ranked regions are complicated.
+// To make matters worse, the HIR WF check can instantiate them
+// outside of a `Binder`, due to the way we (ab)use
+// `ItemCtxt::to_ty`. To make things simpler, we just erase all
+// of them, regardless of depth. At worse, this will give
+// us an inaccurate span for an error message, but cannot
+// lead to unsoundess (we call `delay_span_bug` at the start
+// of `diagnostic_hir_wf_check`).
+impl<'tcx> TypeFolder<'tcx> for EraseAllBoundRegions<'tcx> {
+ fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+ fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
+ if let ty::ReLateBound(..) = r { &ty::ReErased } else { r }
+ }
+}
*/
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(bindings_after_at)]
+#![cfg_attr(bootstrap, feature(bindings_after_at))]
#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate<'_>, Span)] {
let id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());
+ if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization()
+ {
+ if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(id) {
+ // In `generics_of` we set the generics' parent to be our parent's parent which means that
+ // we lose out on the predicates of our actual parent if we dont return those predicates here.
+ // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
+ //
+ // struct Foo<'a, 'b, const N: usize = { ... }>(&'a &'b ());
+ // ^^^ ^^^^^^^ the def id we are calling
+ // ^^^ inferred_outlives_of on
+ // parent item we dont have set as the
+ // parent of generics returned by `generics_of`
+ //
+ // In the above code we want the anon const to have predicates in its param env for `'b: 'a`
+ let item_id = tcx.hir().get_parent_item(id);
+ let item_def_id = tcx.hir().local_def_id(item_id).to_def_id();
+ // In the above code example we would be calling `inferred_outlives_of(Foo)` here
+ return tcx.inferred_outlives_of(item_def_id);
+ }
+ }
+
match tcx.hir().get(id) {
Node::Item(item) => match item.kind {
hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => {
# This is false by default so that distributions don't unexpectedly download
# LLVM from the internet.
#
-# All tier 1 targets are currently supported; set this to `"if-supported"` if
+# All tier 1 targets are currently supported; set this to `"if-available"` if
# you are not sure whether you're on a tier 1 target.
#
# We also currently only support this when building LLVM for the build triple.
/// assert!(heap.is_empty())
/// ```
///
+/// A `BinaryHeap` with a known list of items can be initialized from an array:
+///
+/// ```
+/// use std::collections::BinaryHeap;
+///
+/// let heap = BinaryHeap::from([1, 5, 2]);
+/// ```
+///
/// ## Min-heap
///
/// Either `std::cmp::Reverse` or a custom `Ord` implementation can be used to
}
}
+#[stable(feature = "std_collections_from_array", since = "1.56.0")]
+impl<T: Ord, const N: usize> From<[T; N]> for BinaryHeap<T> {
+ /// ```
+ /// use std::collections::BinaryHeap;
+ ///
+ /// let mut h1 = BinaryHeap::from([1, 4, 2, 3]);
+ /// let mut h2: BinaryHeap<_> = [1, 4, 2, 3].into();
+ /// while let Some((a, b)) = h1.pop().zip(h2.pop()) {
+ /// assert_eq!(a, b);
+ /// }
+ /// ```
+ fn from(arr: [T; N]) -> Self {
+ core::array::IntoIter::new(arr).collect()
+ }
+}
+
#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
impl<T> From<BinaryHeap<T>> for Vec<T> {
/// Converts a `BinaryHeap<T>` into a `Vec<T>`.
/// }
/// ```
///
-/// `BTreeMap` also implements an [`Entry API`], which allows for more complex
+/// A `BTreeMap` with a known list of items can be initialized from an array:
+///
+/// ```
+/// use std::collections::BTreeMap;
+///
+/// let solar_distance = BTreeMap::from([
+/// ("Mercury", 0.4),
+/// ("Venus", 0.7),
+/// ("Earth", 1.0),
+/// ("Mars", 1.5),
+/// ]);
+/// ```
+///
+/// `BTreeMap` implements an [`Entry API`], which allows for complex
/// methods of getting, setting, updating and removing keys and their values:
///
/// [`Entry API`]: BTreeMap::entry
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
+ /// The elements are visited in ascending key order.
///
/// # Examples
///
}
}
+#[stable(feature = "std_collections_from_array", since = "1.56.0")]
+impl<K: Ord, V, const N: usize> From<[(K, V); N]> for BTreeMap<K, V> {
+ /// ```
+ /// use std::collections::BTreeMap;
+ ///
+ /// let map1 = BTreeMap::from([(1, 2), (3, 4)]);
+ /// let map2: BTreeMap<_, _> = [(1, 2), (3, 4)].into();
+ /// assert_eq!(map1, map2);
+ /// ```
+ fn from(arr: [(K, V); N]) -> Self {
+ core::array::IntoIter::new(arr).collect()
+ }
+}
+
impl<K, V> BTreeMap<K, V> {
/// Gets an iterator over the entries of the map, sorted by key.
///
}
map.check_invariants();
}
+
+#[test]
+fn from_array() {
+ let map = BTreeMap::from([(1, 2), (3, 4)]);
+ let unordered_duplicates = BTreeMap::from([(3, 4), (1, 2), (1, 2)]);
+ assert_eq!(map, unordered_duplicates);
+}
/// println!("{}", book);
/// }
/// ```
+///
+/// A `BTreeSet` with a known list of items can be initialized from an array:
+///
+/// ```
+/// use std::collections::BTreeSet;
+///
+/// let set = BTreeSet::from([1, 2, 3]);
+/// ```
#[derive(Hash, PartialEq, Eq, Ord, PartialOrd)]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "BTreeSet")]
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+ /// The elements are visited in ascending order.
///
/// # Examples
///
}
}
+#[stable(feature = "std_collections_from_array", since = "1.56.0")]
+impl<T: Ord, const N: usize> From<[T; N]> for BTreeSet<T> {
+ /// ```
+ /// use std::collections::BTreeSet;
+ ///
+ /// let set1 = BTreeSet::from([1, 2, 3, 4]);
+ /// let set2: BTreeSet<_> = [1, 2, 3, 4].into();
+ /// assert_eq!(set1, set2);
+ /// ```
+ fn from(arr: [T; N]) -> Self {
+ core::array::IntoIter::new(arr).collect()
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> IntoIterator for BTreeSet<T> {
type Item = T;
assert!(set.into_iter().eq(data.clone().into_iter().filter(|x| *x < key)));
assert!(right.into_iter().eq(data.into_iter().filter(|x| *x >= key)));
}
+
+#[test]
+fn from_array() {
+ let set = BTreeSet::from([1, 2, 3, 4]);
+ let unordered_duplicates = BTreeSet::from([4, 1, 4, 3, 2]);
+ assert_eq!(set, unordered_duplicates);
+}
/// The `LinkedList` allows pushing and popping elements at either end
/// in constant time.
///
+/// A `LinkedList` with a known list of items can be initialized from an array:
+/// ```
+/// use std::collections::LinkedList;
+///
+/// let list = LinkedList::from([1, 2, 3]);
+/// ```
+///
/// NOTE: It is almost always better to use `Vec` or `VecDeque` because
/// array-based containers are generally faster,
/// more memory efficient, and make better use of CPU cache.
}
}
+#[stable(feature = "std_collections_from_array", since = "1.56.0")]
+impl<T, const N: usize> From<[T; N]> for LinkedList<T> {
+ /// ```
+ /// use std::collections::LinkedList;
+ ///
+ /// let list1 = LinkedList::from([1, 2, 3, 4]);
+ /// let list2: LinkedList<_> = [1, 2, 3, 4].into();
+ /// assert_eq!(list1, list2);
+ /// ```
+ fn from(arr: [T; N]) -> Self {
+ core::array::IntoIter::new(arr).collect()
+ }
+}
+
// Ensure that `LinkedList` and its read-only iterators are covariant in their type parameters.
#[allow(dead_code)]
fn assert_covariance() {
use core::ptr::{self, NonNull};
use core::{fmt, mem};
+use crate::alloc::{Allocator, Global};
+
use super::{count, Iter, VecDeque};
/// A draining iterator over the elements of a `VecDeque`.
///
/// [`drain`]: VecDeque::drain
#[stable(feature = "drain", since = "1.6.0")]
-pub struct Drain<'a, T: 'a> {
+pub struct Drain<
+ 'a,
+ T: 'a,
+ #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+> {
pub(crate) after_tail: usize,
pub(crate) after_head: usize,
pub(crate) iter: Iter<'a, T>,
- pub(crate) deque: NonNull<VecDeque<T>>,
+ pub(crate) deque: NonNull<VecDeque<T, A>>,
}
#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<T: fmt::Debug> fmt::Debug for Drain<'_, T> {
+impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Drain")
.field(&self.after_tail)
}
#[stable(feature = "drain", since = "1.6.0")]
-unsafe impl<T: Sync> Sync for Drain<'_, T> {}
+unsafe impl<T: Sync, A: Allocator + Sync> Sync for Drain<'_, T, A> {}
#[stable(feature = "drain", since = "1.6.0")]
-unsafe impl<T: Send> Send for Drain<'_, T> {}
+unsafe impl<T: Send, A: Allocator + Send> Send for Drain<'_, T, A> {}
#[stable(feature = "drain", since = "1.6.0")]
-impl<T> Drop for Drain<'_, T> {
+impl<T, A: Allocator> Drop for Drain<'_, T, A> {
fn drop(&mut self) {
- struct DropGuard<'r, 'a, T>(&'r mut Drain<'a, T>);
+ struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
- impl<'r, 'a, T> Drop for DropGuard<'r, 'a, T> {
+ impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
fn drop(&mut self) {
self.0.for_each(drop);
}
#[stable(feature = "drain", since = "1.6.0")]
-impl<T> Iterator for Drain<'_, T> {
+impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
type Item = T;
#[inline]
}
#[stable(feature = "drain", since = "1.6.0")]
-impl<T> DoubleEndedIterator for Drain<'_, T> {
+impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
#[inline]
fn next_back(&mut self) -> Option<T> {
self.iter.next_back().map(|elt| unsafe { ptr::read(elt) })
}
#[stable(feature = "drain", since = "1.6.0")]
-impl<T> ExactSizeIterator for Drain<'_, T> {}
+impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {}
#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for Drain<'_, T> {}
+impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
use core::fmt;
-use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess};
+use core::iter::{FusedIterator, TrustedLen};
+
+use crate::alloc::{Allocator, Global};
use super::VecDeque;
/// [`into_iter`]: VecDeque::into_iter
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct IntoIter<T> {
- pub(crate) inner: VecDeque<T>,
+pub struct IntoIter<
+ T,
+ #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+> {
+ pub(crate) inner: VecDeque<T, A>,
}
#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
+impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoIter<T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("IntoIter").field(&self.inner).finish()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Iterator for IntoIter<T> {
+impl<T, A: Allocator> Iterator for IntoIter<T, A> {
type Item = T;
#[inline]
let len = self.inner.len();
(len, Some(len))
}
-
- #[inline]
- #[doc(hidden)]
- unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
- where
- Self: TrustedRandomAccess,
- {
- // Safety: The TrustedRandomAccess contract requires that callers only pass an index
- // that is in bounds.
- // Additionally Self: TrustedRandomAccess is only implemented for T: Copy which means even
- // multiple repeated reads of the same index would be safe and the
- // values are !Drop, thus won't suffer from double drops.
- unsafe {
- let idx = self.inner.wrap_add(self.inner.tail, idx);
- self.inner.buffer_read(idx)
- }
- }
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> DoubleEndedIterator for IntoIter<T> {
+impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
#[inline]
fn next_back(&mut self) -> Option<T> {
self.inner.pop_back()
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ExactSizeIterator for IntoIter<T> {
+impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {
fn is_empty(&self) -> bool {
self.inner.is_empty()
}
}
#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for IntoIter<T> {}
+impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {}
#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for IntoIter<T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-// T: Copy as approximation for !Drop since get_unchecked does not update the pointers
-// and thus we can't implement drop-handling
-unsafe impl<T> TrustedRandomAccess for IntoIter<T>
-where
- T: Copy,
-{
- const MAY_HAVE_SIDE_EFFECT: bool = false;
-}
+unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {}
macro_rules! __impl_slice_eq1 {
([$($vars:tt)*] $lhs:ty, $rhs:ty, $($constraints:tt)*) => {
#[stable(feature = "vec_deque_partial_eq_slice", since = "1.17.0")]
- impl<A, B, $($vars)*> PartialEq<$rhs> for $lhs
+ impl<T, U, A: Allocator, $($vars)*> PartialEq<$rhs> for $lhs
where
- A: PartialEq<B>,
+ T: PartialEq<U>,
$($constraints)*
{
fn eq(&self, other: &$rhs) -> bool {
use core::ptr::{self, NonNull};
use core::slice;
+use crate::alloc::{Allocator, Global};
use crate::collections::TryReserveError;
use crate::raw_vec::RawVec;
use crate::vec::Vec;
/// push onto the back in this manner, and iterating over `VecDeque` goes front
/// to back.
///
+/// A `VecDeque` with a known list of items can be initialized from an array:
+///
+/// ```
+/// use std::collections::VecDeque;
+///
+/// let deq = VecDeque::from([-1, 0, 1]);
+/// ```
+///
/// Since `VecDeque` is a ring buffer, its elements are not necessarily contiguous
/// in memory. If you want to access the elements as a single slice, such as for
/// efficient sorting, you can use [`make_contiguous`]. It rotates the `VecDeque`
/// [`make_contiguous`]: VecDeque::make_contiguous
#[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_type")]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct VecDeque<T> {
+pub struct VecDeque<
+ T,
+ #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+> {
// tail and head are pointers into the buffer. Tail always points
// to the first element that could be read, Head always points
// to where data should be written.
// is defined as the distance between the two.
tail: usize,
head: usize,
- buf: RawVec<T>,
+ buf: RawVec<T, A>,
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Clone> Clone for VecDeque<T> {
- fn clone(&self) -> VecDeque<T> {
- self.iter().cloned().collect()
+impl<T: Clone, A: Allocator + Clone> Clone for VecDeque<T, A> {
+ fn clone(&self) -> Self {
+ let mut deq = Self::with_capacity_in(self.len(), self.allocator().clone());
+ deq.extend(self.iter().cloned());
+ deq
}
fn clone_from(&mut self, other: &Self) {
}
#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T> Drop for VecDeque<T> {
+unsafe impl<#[may_dangle] T, A: Allocator> Drop for VecDeque<T, A> {
fn drop(&mut self) {
/// Runs the destructor for all items in the slice when it gets dropped (normally or
/// during unwinding).
}
}
-impl<T> VecDeque<T> {
+impl<T, A: Allocator> VecDeque<T, A> {
/// Marginally more convenient
#[inline]
fn ptr(&self) -> *mut T {
///
/// let vector: VecDeque<u32> = VecDeque::new();
/// ```
+ #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> VecDeque<T> {
- VecDeque::with_capacity(INITIAL_CAPACITY)
+ VecDeque::new_in(Global)
}
/// Creates an empty `VecDeque` with space for at least `capacity` elements.
///
/// let vector: VecDeque<u32> = VecDeque::with_capacity(10);
/// ```
+ #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(capacity: usize) -> VecDeque<T> {
+ Self::with_capacity_in(capacity, Global)
+ }
+}
+
+impl<T, A: Allocator> VecDeque<T, A> {
+ /// Creates an empty `VecDeque`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::VecDeque;
+ ///
+ /// let vector: VecDeque<u32> = VecDeque::new();
+ /// ```
+ #[inline]
+ #[unstable(feature = "allocator_api", issue = "32838")]
+ pub fn new_in(alloc: A) -> VecDeque<T, A> {
+ VecDeque::with_capacity_in(INITIAL_CAPACITY, alloc)
+ }
+
+ /// Creates an empty `VecDeque` with space for at least `capacity` elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::VecDeque;
+ ///
+ /// let vector: VecDeque<u32> = VecDeque::with_capacity(10);
+ /// ```
+ #[unstable(feature = "allocator_api", issue = "32838")]
+ pub fn with_capacity_in(capacity: usize, alloc: A) -> VecDeque<T, A> {
// +1 since the ringbuffer always leaves one space empty
let cap = cmp::max(capacity + 1, MINIMUM_CAPACITY + 1).next_power_of_two();
assert!(cap > capacity, "capacity overflow");
- VecDeque { tail: 0, head: 0, buf: RawVec::with_capacity(cap) }
+ VecDeque { tail: 0, head: 0, buf: RawVec::with_capacity_in(cap, alloc) }
}
/// Provides a reference to the element at the given index.
}
}
+ /// Returns a reference to the underlying allocator.
+ #[unstable(feature = "allocator_api", issue = "32838")]
+ #[inline]
+ pub fn allocator(&self) -> &A {
+ self.buf.allocator()
+ }
+
/// Returns a front-to-back iterator.
///
/// # Examples
/// ```
#[inline]
#[stable(feature = "drain", since = "1.6.0")]
- pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
+ pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, A>
where
R: RangeBounds<usize>,
{
#[inline]
#[must_use = "use `.truncate()` if you don't need the other half"]
#[stable(feature = "split_off", since = "1.4.0")]
- pub fn split_off(&mut self, at: usize) -> Self {
+ pub fn split_off(&mut self, at: usize) -> Self
+ where
+ A: Clone,
+ {
let len = self.len();
assert!(at <= len, "`at` out of bounds");
let other_len = len - at;
- let mut other = VecDeque::with_capacity(other_len);
+ let mut other = VecDeque::with_capacity_in(other_len, self.allocator().clone());
unsafe {
let (first_half, second_half) = self.as_slices();
}
}
-impl<T: Clone> VecDeque<T> {
+impl<T: Clone, A: Allocator> VecDeque<T, A> {
/// Modifies the `VecDeque` in-place so that `len()` is equal to new_len,
/// either by removing excess elements from the back or by appending clones of `value`
/// to the back.
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<A: PartialEq> PartialEq for VecDeque<A> {
- fn eq(&self, other: &VecDeque<A>) -> bool {
+impl<T: PartialEq, A: Allocator> PartialEq for VecDeque<T, A> {
+ fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<A: Eq> Eq for VecDeque<A> {}
+impl<T: Eq, A: Allocator> Eq for VecDeque<T, A> {}
-__impl_slice_eq1! { [] VecDeque<A>, Vec<B>, }
-__impl_slice_eq1! { [] VecDeque<A>, &[B], }
-__impl_slice_eq1! { [] VecDeque<A>, &mut [B], }
-__impl_slice_eq1! { [const N: usize] VecDeque<A>, [B; N], }
-__impl_slice_eq1! { [const N: usize] VecDeque<A>, &[B; N], }
-__impl_slice_eq1! { [const N: usize] VecDeque<A>, &mut [B; N], }
+__impl_slice_eq1! { [] VecDeque<T, A>, Vec<U, A>, }
+__impl_slice_eq1! { [] VecDeque<T, A>, &[U], }
+__impl_slice_eq1! { [] VecDeque<T, A>, &mut [U], }
+__impl_slice_eq1! { [const N: usize] VecDeque<T, A>, [U; N], }
+__impl_slice_eq1! { [const N: usize] VecDeque<T, A>, &[U; N], }
+__impl_slice_eq1! { [const N: usize] VecDeque<T, A>, &mut [U; N], }
#[stable(feature = "rust1", since = "1.0.0")]
-impl<A: PartialOrd> PartialOrd for VecDeque<A> {
- fn partial_cmp(&self, other: &VecDeque<A>) -> Option<Ordering> {
+impl<T: PartialOrd, A: Allocator> PartialOrd for VecDeque<T, A> {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<A: Ord> Ord for VecDeque<A> {
+impl<T: Ord, A: Allocator> Ord for VecDeque<T, A> {
#[inline]
- fn cmp(&self, other: &VecDeque<A>) -> Ordering {
+ fn cmp(&self, other: &Self) -> Ordering {
self.iter().cmp(other.iter())
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<A: Hash> Hash for VecDeque<A> {
+impl<T: Hash, A: Allocator> Hash for VecDeque<T, A> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.len().hash(state);
// It's not possible to use Hash::hash_slice on slices
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<A> Index<usize> for VecDeque<A> {
- type Output = A;
+impl<T, A: Allocator> Index<usize> for VecDeque<T, A> {
+ type Output = T;
#[inline]
- fn index(&self, index: usize) -> &A {
+ fn index(&self, index: usize) -> &T {
self.get(index).expect("Out of bounds access")
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<A> IndexMut<usize> for VecDeque<A> {
+impl<T, A: Allocator> IndexMut<usize> for VecDeque<T, A> {
#[inline]
- fn index_mut(&mut self, index: usize) -> &mut A {
+ fn index_mut(&mut self, index: usize) -> &mut T {
self.get_mut(index).expect("Out of bounds access")
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<A> FromIterator<A> for VecDeque<A> {
- fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> VecDeque<A> {
+impl<T> FromIterator<T> for VecDeque<T> {
+ fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> VecDeque<T> {
let iterator = iter.into_iter();
let (lower, _) = iterator.size_hint();
let mut deq = VecDeque::with_capacity(lower);
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> IntoIterator for VecDeque<T> {
+impl<T, A: Allocator> IntoIterator for VecDeque<T, A> {
type Item = T;
- type IntoIter = IntoIter<T>;
+ type IntoIter = IntoIter<T, A>;
/// Consumes the `VecDeque` into a front-to-back iterator yielding elements by
/// value.
- fn into_iter(self) -> IntoIter<T> {
+ fn into_iter(self) -> IntoIter<T, A> {
IntoIter { inner: self }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> IntoIterator for &'a VecDeque<T> {
+impl<'a, T, A: Allocator> IntoIterator for &'a VecDeque<T, A> {
type Item = &'a T;
type IntoIter = Iter<'a, T>;
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> IntoIterator for &'a mut VecDeque<T> {
+impl<'a, T, A: Allocator> IntoIterator for &'a mut VecDeque<T, A> {
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<A> Extend<A> for VecDeque<A> {
- fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
+impl<T, A: Allocator> Extend<T> for VecDeque<T, A> {
+ fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
// This function should be the moral equivalent of:
//
// for item in iter.into_iter() {
}
#[inline]
- fn extend_one(&mut self, elem: A) {
+ fn extend_one(&mut self, elem: T) {
self.push_back(elem);
}
}
#[stable(feature = "extend_ref", since = "1.2.0")]
-impl<'a, T: 'a + Copy> Extend<&'a T> for VecDeque<T> {
+impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for VecDeque<T, A> {
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
self.extend(iter.into_iter().cloned());
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Debug> fmt::Debug for VecDeque<T> {
+impl<T: fmt::Debug, A: Allocator> fmt::Debug for VecDeque<T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self).finish()
}
}
#[stable(feature = "vecdeque_vec_conversions", since = "1.10.0")]
-impl<T> From<Vec<T>> for VecDeque<T> {
+impl<T, A: Allocator> From<Vec<T, A>> for VecDeque<T, A> {
/// Turn a [`Vec<T>`] into a [`VecDeque<T>`].
///
/// [`Vec<T>`]: crate::vec::Vec
/// This avoids reallocating where possible, but the conditions for that are
/// strict, and subject to change, and so shouldn't be relied upon unless the
/// `Vec<T>` came from `From<VecDeque<T>>` and hasn't been reallocated.
- fn from(mut other: Vec<T>) -> Self {
+ fn from(mut other: Vec<T, A>) -> Self {
let len = other.len();
if mem::size_of::<T>() == 0 {
// There's no actual allocation for ZSTs to worry about capacity,
}
unsafe {
- let (other_buf, len, capacity) = other.into_raw_parts();
- let buf = RawVec::from_raw_parts(other_buf, capacity);
+ let (other_buf, len, capacity, alloc) = other.into_raw_parts_with_alloc();
+ let buf = RawVec::from_raw_parts_in(other_buf, capacity, alloc);
VecDeque { tail: 0, head: len, buf }
}
}
}
#[stable(feature = "vecdeque_vec_conversions", since = "1.10.0")]
-impl<T> From<VecDeque<T>> for Vec<T> {
+impl<T, A: Allocator> From<VecDeque<T, A>> for Vec<T, A> {
/// Turn a [`VecDeque<T>`] into a [`Vec<T>`].
///
/// [`Vec<T>`]: crate::vec::Vec
/// assert_eq!(vec, [8, 9, 1, 2, 3, 4]);
/// assert_eq!(vec.as_ptr(), ptr);
/// ```
- fn from(mut other: VecDeque<T>) -> Self {
+ fn from(mut other: VecDeque<T, A>) -> Self {
other.make_contiguous();
unsafe {
let buf = other.buf.ptr();
let len = other.len();
let cap = other.cap();
+ let alloc = ptr::read(other.allocator());
if other.tail != 0 {
ptr::copy(buf.add(other.tail), buf, len);
}
- Vec::from_raw_parts(buf, len, cap)
+ Vec::from_raw_parts_in(buf, len, cap, alloc)
}
}
}
+
+#[stable(feature = "std_collections_from_array", since = "1.56.0")]
+impl<T, const N: usize> From<[T; N]> for VecDeque<T> {
+ /// ```
+ /// use std::collections::VecDeque;
+ ///
+ /// let deq1 = VecDeque::from([1, 2, 3, 4]);
+ /// let deq2: VecDeque<_> = [1, 2, 3, 4].into();
+ /// assert_eq!(deq1, deq2);
+ /// ```
+ fn from(arr: [T; N]) -> Self {
+ core::array::IntoIter::new(arr).collect()
+ }
+}
use core::cmp::{self};
use core::mem::replace;
+use crate::alloc::Allocator;
+
use super::VecDeque;
/// PairSlices pairs up equal length slice parts of two deques
}
impl<'a, 'b, T> PairSlices<'a, 'b, T> {
- pub fn from(to: &'a mut VecDeque<T>, from: &'b VecDeque<T>) -> Self {
+ pub fn from<A: Allocator>(to: &'a mut VecDeque<T, A>, from: &'b VecDeque<T, A>) -> Self {
let (a0, a1) = to.as_mut_slices();
let (b0, b1) = from.as_slices();
PairSlices { a0, a1, b0, b1 }
//! [`Rc`]: rc
//! [`RefCell`]: core::cell
+// To run liballoc tests without x.py without ending up with two copies of liballoc, 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))]
#![allow(unused_attributes)]
#![stable(feature = "alloc", since = "1.36.0")]
#![doc(
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(async_stream)]
+#![cfg_attr(bootstrap, feature(bindings_after_at))]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(cfg_sanitize)]
#![feature(associated_type_bounds)]
#![feature(slice_group_by)]
#![feature(decl_macro)]
-#![feature(bindings_after_at)]
// Allow testing this library
#[cfg(test)]
/// assert_eq!(vec, [7, 1, 2, 3]);
/// ```
///
-/// The [`vec!`] macro is provided to make initialization more convenient:
+/// The [`vec!`] macro is provided for convenient initialization:
///
/// ```
-/// let mut vec = vec![1, 2, 3];
-/// vec.push(4);
-/// assert_eq!(vec, [1, 2, 3, 4]);
+/// let mut vec1 = vec![1, 2, 3];
+/// vec1.push(4);
+/// let vec2 = Vec::from([1, 2, 3, 4]);
+/// assert_eq!(vec1, vec2);
/// ```
///
/// It can also initialize each element of a `Vec<T>` with a given value.
"* \t",
[Reject(0, 1), Reject(1, 2), Reject(2, 3),]
);
+
+ // See #85462
+ #[test]
+ fn str_searcher_empty_needle_after_done() {
+ // Empty needle and haystack
+ {
+ let mut searcher = "".into_searcher("");
+
+ assert_eq!(searcher.next(), SearchStep::Match(0, 0));
+ assert_eq!(searcher.next(), SearchStep::Done);
+ assert_eq!(searcher.next(), SearchStep::Done);
+ assert_eq!(searcher.next(), SearchStep::Done);
+
+ let mut searcher = "".into_searcher("");
+
+ assert_eq!(searcher.next_back(), SearchStep::Match(0, 0));
+ assert_eq!(searcher.next_back(), SearchStep::Done);
+ assert_eq!(searcher.next_back(), SearchStep::Done);
+ assert_eq!(searcher.next_back(), SearchStep::Done);
+ }
+ // Empty needle and non-empty haystack
+ {
+ let mut searcher = "".into_searcher("a");
+
+ assert_eq!(searcher.next(), SearchStep::Match(0, 0));
+ assert_eq!(searcher.next(), SearchStep::Reject(0, 1));
+ assert_eq!(searcher.next(), SearchStep::Match(1, 1));
+ assert_eq!(searcher.next(), SearchStep::Done);
+ assert_eq!(searcher.next(), SearchStep::Done);
+ assert_eq!(searcher.next(), SearchStep::Done);
+
+ let mut searcher = "".into_searcher("a");
+
+ assert_eq!(searcher.next_back(), SearchStep::Match(1, 1));
+ assert_eq!(searcher.next_back(), SearchStep::Reject(0, 1));
+ assert_eq!(searcher.next_back(), SearchStep::Match(0, 0));
+ assert_eq!(searcher.next_back(), SearchStep::Done);
+ assert_eq!(searcher.next_back(), SearchStep::Done);
+ assert_eq!(searcher.next_back(), SearchStep::Done);
+ }
+ }
}
macro_rules! generate_iterator_test {
///
/// # Example
///
-/// ```no_run
-/// use std::alloc::{GlobalAlloc, Layout, alloc};
+/// ```
+/// use std::alloc::{GlobalAlloc, Layout};
+/// use std::cell::UnsafeCell;
/// use std::ptr::null_mut;
+/// use std::sync::atomic::{
+/// AtomicUsize,
+/// Ordering::{Acquire, SeqCst},
+/// };
///
-/// struct MyAllocator;
-///
-/// unsafe impl GlobalAlloc for MyAllocator {
-/// unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() }
-/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
+/// const ARENA_SIZE: usize = 128 * 1024;
+/// const MAX_SUPPORTED_ALIGN: usize = 4096;
+/// #[repr(C, align(4096))] // 4096 == MAX_SUPPORTED_ALIGN
+/// struct SimpleAllocator {
+/// arena: UnsafeCell<[u8; ARENA_SIZE]>,
+/// remaining: AtomicUsize, // we allocate from the top, counting down
/// }
///
/// #[global_allocator]
-/// static A: MyAllocator = MyAllocator;
+/// static ALLOCATOR: SimpleAllocator = SimpleAllocator {
+/// arena: UnsafeCell::new([0x55; ARENA_SIZE]),
+/// remaining: AtomicUsize::new(ARENA_SIZE),
+/// };
///
-/// fn main() {
-/// unsafe {
-/// assert!(alloc(Layout::new::<u32>()).is_null())
+/// unsafe impl Sync for SimpleAllocator {}
+///
+/// unsafe impl GlobalAlloc for SimpleAllocator {
+/// unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+/// let size = layout.size();
+/// let align = layout.align();
+///
+/// // `Layout` contract forbids making a `Layout` with align=0, or align not power of 2.
+/// // So we can safely use a mask to ensure alignment without worrying about UB.
+/// let align_mask_to_round_down = !(align - 1);
+///
+/// if align > MAX_SUPPORTED_ALIGN {
+/// return null_mut();
+/// }
+///
+/// let mut allocated = 0;
+/// if self
+/// .remaining
+/// .fetch_update(SeqCst, SeqCst, |mut remaining| {
+/// if size > remaining {
+/// return None;
+/// }
+/// remaining -= size;
+/// remaining &= align_mask_to_round_down;
+/// allocated = remaining;
+/// Some(remaining)
+/// })
+/// .is_err()
+/// {
+/// return null_mut();
+/// };
+/// (self.arena.get() as *mut u8).add(allocated)
/// }
+/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
+/// }
+///
+/// fn main() {
+/// let _s = format!("allocating a string!");
+/// let currently = ALLOCATOR.remaining.load(Acquire);
+/// println!("allocated so far: {}", ARENA_SIZE - currently);
/// }
/// ```
///
use crate::{
fmt,
- iter::{self, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess},
+ iter::{self, ExactSizeIterator, FusedIterator, TrustedLen},
mem::{self, MaybeUninit},
ops::Range,
ptr,
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
-
- #[inline]
- #[doc(hidden)]
- unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
- where
- Self: TrustedRandomAccess,
- {
- // SAFETY: Callers are only allowed to pass an index that is in bounds
- // Additionally Self: TrustedRandomAccess is only implemented for T: Copy which means even
- // multiple repeated reads of the same index would be safe and the
- // values are !Drop, thus won't suffer from double drops.
- unsafe { self.data.get_unchecked(self.alive.start + idx).assume_init_read() }
- }
}
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {}
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-// T: Copy as approximation for !Drop since get_unchecked does not update the pointers
-// and thus we can't implement drop-handling
-unsafe impl<T, const N: usize> TrustedRandomAccess for IntoIter<T, N>
-where
- T: Copy,
-{
- const MAY_HAVE_SIDE_EFFECT: bool = false;
-}
-
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
fn clone(&self) -> Self {
/// regardless of the step given.
///
/// Note 2: The time at which ignored elements are pulled is not fixed.
- /// `StepBy` behaves like the sequence `next(), nth(step-1), nth(step-1), …`,
- /// but is also free to behave like the sequence
- /// `advance_n_and_return_first(step), advance_n_and_return_first(step), …`
+ /// `StepBy` behaves like the sequence `self.next()`, `self.nth(step-1)`,
+ /// `self.nth(step-1)`, …, but is also free to behave like the sequence
+ /// `advance_n_and_return_first(&mut self, step)`,
+ /// `advance_n_and_return_first(&mut self, step)`, …
/// Which way is used may change for some iterators for performance reasons.
/// The second way will advance the iterator earlier and may consume more items.
///
/// `advance_n_and_return_first` is the equivalent of:
/// ```
- /// fn advance_n_and_return_first<I>(iter: &mut I, total_step: usize) -> Option<I::Item>
+ /// fn advance_n_and_return_first<I>(iter: &mut I, n: usize) -> Option<I::Item>
/// where
/// I: Iterator,
/// {
/// let next = iter.next();
- /// if total_step > 1 {
- /// iter.nth(total_step-2);
+ /// if n > 1 {
+ /// iter.nth(n - 2);
/// }
/// next
/// }
//
// 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
+// 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))]
#![stable(feature = "core", since = "1.6.0")]
#![doc(
html_playground_url = "https://play.rust-lang.org/",
language use and is subject to change"
)]
#[allow_internal_unstable(fmt_internals)]
+ #[doc(hidden)]
#[rustc_builtin_macro]
#[macro_export]
macro_rules! format_args_nl {
/// With `write`, we can avoid the need to write through a raw pointer:
///
/// ```rust
- /// #![feature(maybe_uninit_extra)]
/// use core::pin::Pin;
/// use core::mem::MaybeUninit;
///
end: usize,
is_match_fw: bool,
is_match_bw: bool,
+ // Needed in case of an empty haystack, see #85462
+ is_finished: bool,
}
impl<'a, 'b> StrSearcher<'a, 'b> {
end: haystack.len(),
is_match_fw: true,
is_match_bw: true,
+ is_finished: false,
}),
}
} else {
fn next(&mut self) -> SearchStep {
match self.searcher {
StrSearcherImpl::Empty(ref mut searcher) => {
+ if searcher.is_finished {
+ return SearchStep::Done;
+ }
// empty needle rejects every char and matches every empty string between them
let is_match = searcher.is_match_fw;
searcher.is_match_fw = !searcher.is_match_fw;
let pos = searcher.position;
match self.haystack[pos..].chars().next() {
_ if is_match => SearchStep::Match(pos, pos),
- None => SearchStep::Done,
+ None => {
+ searcher.is_finished = true;
+ SearchStep::Done
+ }
Some(ch) => {
searcher.position += ch.len_utf8();
SearchStep::Reject(pos, searcher.position)
fn next_back(&mut self) -> SearchStep {
match self.searcher {
StrSearcherImpl::Empty(ref mut searcher) => {
+ if searcher.is_finished {
+ return SearchStep::Done;
+ }
let is_match = searcher.is_match_bw;
searcher.is_match_bw = !searcher.is_match_bw;
let end = searcher.end;
match self.haystack[..end].chars().next_back() {
_ if is_match => SearchStep::Match(end, end),
- None => SearchStep::Done,
+ None => {
+ searcher.is_finished = true;
+ SearchStep::Done
+ }
Some(ch) => {
searcher.end -= ch.len_utf8();
SearchStep::Reject(searcher.end, end)
/// }
/// ```
///
-/// `HashMap` also implements an [`Entry API`](#method.entry), which allows
-/// for more complex methods of getting, setting, updating and removing keys and
+/// A `HashMap` with a known list of items can be initialized from an array:
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// let solar_distance = HashMap::from([
+/// ("Mercury", 0.4),
+/// ("Venus", 0.7),
+/// ("Earth", 1.0),
+/// ("Mars", 1.5),
+/// ]);
+/// ```
+///
+/// `HashMap` implements an [`Entry API`](#method.entry), which allows
+/// for complex methods of getting, setting, updating and removing keys and
/// their values:
///
/// ```
/// }
///
/// // Use a HashMap to store the vikings' health points.
-/// let mut vikings = HashMap::new();
-///
-/// vikings.insert(Viking::new("Einar", "Norway"), 25);
-/// vikings.insert(Viking::new("Olaf", "Denmark"), 24);
-/// vikings.insert(Viking::new("Harald", "Iceland"), 12);
+/// let vikings = HashMap::from([
+/// (Viking::new("Einar", "Norway"), 25),
+/// (Viking::new("Olaf", "Denmark"), 24),
+/// (Viking::new("Harald", "Iceland"), 12),
+/// ]);
///
/// // Use derived implementation to print the status of the vikings.
/// for (viking, health) in &vikings {
/// println!("{:?} has {} hp", viking, health);
/// }
/// ```
-///
-/// A `HashMap` with fixed list of elements can be initialized from an array:
-///
-/// ```
-/// use std::collections::HashMap;
-///
-/// let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)]
-/// .iter().cloned().collect();
-/// // use the values stored in map
-/// ```
#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")]
#[stable(feature = "rust1", since = "1.0.0")]
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
+ /// The elements are visited in unsorted (and unspecified) order.
///
/// # Examples
///
}
}
+#[stable(feature = "std_collections_from_array", since = "1.56.0")]
+// Note: as what is currently the most convenient built-in way to construct
+// a HashMap, a simple usage of this function must not *require* the user
+// to provide a type annotation in order to infer the third type parameter
+// (the hasher parameter, conventionally "S").
+// To that end, this impl is defined using RandomState as the concrete
+// type of S, rather than being generic over `S: BuildHasher + Default`.
+// It is expected that users who want to specify a hasher will manually use
+// `with_capacity_and_hasher`.
+// If type parameter defaults worked on impls, and if type parameter
+// defaults could be mixed with const generics, then perhaps
+// this could be generalized.
+// See also the equivalent impl on HashSet.
+impl<K, V, const N: usize> From<[(K, V); N]> for HashMap<K, V, RandomState>
+where
+ K: Eq + Hash,
+{
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let map1 = HashMap::from([(1, 2), (3, 4)]);
+ /// let map2: HashMap<_, _> = [(1, 2), (3, 4)].into();
+ /// assert_eq!(map1, map2);
+ /// ```
+ fn from(arr: [(K, V); N]) -> Self {
+ crate::array::IntoIter::new(arr).collect()
+ }
+}
+
/// An iterator over the entries of a `HashMap`.
///
/// This `struct` is created by the [`iter`] method on [`HashMap`]. See its
assert_eq!(map.len(), 2);
}
}
+
+#[test]
+fn from_array() {
+ let map = HashMap::from([(1, 2), (3, 4)]);
+ let unordered_duplicates = HashMap::from([(3, 4), (1, 2), (1, 2)]);
+ assert_eq!(map, unordered_duplicates);
+
+ // This next line must infer the hasher type parameter.
+ // If you make a change that causes this line to no longer infer,
+ // that's a problem!
+ let _must_not_require_type_annotation = HashMap::from([(1, 2)]);
+}
/// }
/// ```
///
-/// A `HashSet` with fixed list of elements can be initialized from an array:
+/// A `HashSet` with a known list of items can be initialized from an array:
///
/// ```
/// use std::collections::HashSet;
///
-/// let viking_names: HashSet<&'static str> =
-/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect();
-/// // use the values stored in the set
+/// let viking_names = HashSet::from(["Einar", "Olaf", "Harald"]);
/// ```
///
/// [hash set]: crate::collections#use-the-set-variant-of-any-of-these-maps-when
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+ /// The elements are visited in unsorted (and unspecified) order.
///
/// # Examples
///
}
}
+#[stable(feature = "std_collections_from_array", since = "1.56.0")]
+// Note: as what is currently the most convenient built-in way to construct
+// a HashSet, a simple usage of this function must not *require* the user
+// to provide a type annotation in order to infer the third type parameter
+// (the hasher parameter, conventionally "S").
+// To that end, this impl is defined using RandomState as the concrete
+// type of S, rather than being generic over `S: BuildHasher + Default`.
+// It is expected that users who want to specify a hasher will manually use
+// `with_capacity_and_hasher`.
+// If type parameter defaults worked on impls, and if type parameter
+// defaults could be mixed with const generics, then perhaps
+// this could be generalized.
+// See also the equivalent impl on HashMap.
+impl<T, const N: usize> From<[T; N]> for HashSet<T, RandomState>
+where
+ T: Eq + Hash,
+{
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let set1 = HashSet::from([1, 2, 3, 4]);
+ /// let set2: HashSet<_> = [1, 2, 3, 4].into();
+ /// assert_eq!(set1, set2);
+ /// ```
+ fn from(arr: [T; N]) -> Self {
+ crate::array::IntoIter::new(arr).collect()
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, S> Extend<T> for HashSet<T, S>
where
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
assert_eq!(set.len(), 0);
}
+
+#[test]
+fn from_array() {
+ let set = HashSet::from([1, 2, 3, 4]);
+ let unordered_duplicates = HashSet::from([4, 1, 4, 3, 2]);
+ assert_eq!(set, unordered_duplicates);
+
+ // This next line must infer the hasher type parameter.
+ // If you make a change that causes this line to no longer infer,
+ // that's a problem!
+ let _must_not_require_type_annotation = HashSet::from([1, 2]);
+}
}
}
-/// Sets the environment variable `k` to the value `v` for the currently running
+/// Sets the environment variable `key` to the value `value` for the currently running
/// process.
///
/// Note that while concurrent access to environment variables is safe in Rust,
///
/// # Panics
///
-/// This function may panic if `key` is empty, contains an ASCII equals sign
-/// `'='` or the NUL character `'\0'`, or when the value contains the NUL
-/// character.
+/// This function may panic if `key` is empty, contains an ASCII equals sign `'='`
+/// or the NUL character `'\0'`, or when `value` contains the NUL character.
///
/// # Examples
///
/// [`flush`]: BufWriter::flush
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufWriter<W: Write> {
- inner: Option<W>,
+ inner: W,
// The buffer. Avoid using this like a normal `Vec` in common code paths.
// That is, don't use `buf.push`, `buf.extend_from_slice`, or any other
// methods that require bounds checking or the like. This makes an enormous
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(capacity: usize, inner: W) -> BufWriter<W> {
- BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false }
+ BufWriter { inner, buf: Vec::with_capacity(capacity), panicked: false }
}
/// Send data in our local buffer into the inner writer, looping as
}
let mut guard = BufGuard::new(&mut self.buf);
- let inner = self.inner.as_mut().unwrap();
while !guard.done() {
self.panicked = true;
- let r = inner.write(guard.remaining());
+ let r = self.inner.write(guard.remaining());
self.panicked = false;
match r {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_ref(&self) -> &W {
- self.inner.as_ref().unwrap()
+ &self.inner
}
/// Gets a mutable reference to the underlying writer.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut(&mut self) -> &mut W {
- self.inner.as_mut().unwrap()
+ &mut self.inner
}
/// Returns a reference to the internally buffered data.
pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
match self.flush_buf() {
Err(e) => Err(IntoInnerError::new(self, e)),
- Ok(()) => Ok(self.inner.take().unwrap()),
+ Ok(()) => Ok(self.into_raw_parts().0),
}
}
pub fn into_raw_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) {
let buf = mem::take(&mut self.buf);
let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
- (self.inner.take().unwrap(), buf)
+
+ // SAFETY: forget(self) prevents double dropping inner
+ let inner = unsafe { ptr::read(&mut self.inner) };
+ mem::forget(self);
+
+ (inner, buf)
}
// Ensure this function does not get inlined into `write`, so that it
{
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("BufWriter")
- .field("writer", &self.inner.as_ref().unwrap())
+ .field("writer", &self.inner)
.field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity()))
.finish()
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> Drop for BufWriter<W> {
fn drop(&mut self) {
- if self.inner.is_some() && !self.panicked {
+ if !self.panicked {
// dtors should not panic, so we ignore a failed flush
let _r = self.flush_buf();
}
///
/// # Example
/// ```
- /// #![feature(io_into_inner_error_parts)]
/// use std::io::{BufWriter, ErrorKind, Write};
///
/// let mut not_enough_space = [0u8; 10];
/// let err = into_inner_err.into_error();
/// assert_eq!(err.kind(), ErrorKind::WriteZero);
/// ```
- #[unstable(feature = "io_into_inner_error_parts", issue = "79704")]
+ #[stable(feature = "io_into_inner_error_parts", since = "1.55.0")]
pub fn into_error(self) -> Error {
self.1
}
///
/// # Example
/// ```
- /// #![feature(io_into_inner_error_parts)]
/// use std::io::{BufWriter, ErrorKind, Write};
///
/// let mut not_enough_space = [0u8; 10];
/// assert_eq!(err.kind(), ErrorKind::WriteZero);
/// assert_eq!(recovered_writer.buffer(), b"t be actually written");
/// ```
- #[unstable(feature = "io_into_inner_error_parts", issue = "79704")]
+ #[stable(feature = "io_into_inner_error_parts", since = "1.55.0")]
pub fn into_parts(self) -> (Error, W) {
(self.1, self.0)
}
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
+ target_os = "netbsd",
target_os = "openbsd"
))]
pub mod ucred;
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
+ target_os = "netbsd",
target_os = "openbsd"
))]
use crate::os::unix::ucred;
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
+ target_os = "netbsd",
target_os = "openbsd"
))]
pub use ucred::UCred;
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
+ target_os = "netbsd",
target_os = "openbsd"
))]
pub fn peer_cred(&self) -> io::Result<UCred> {
#[cfg(any(target_os = "android", target_os = "linux"))]
pub use self::impl_linux::peer_cred;
-#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
+#[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "netbsd"
+))]
pub use self::impl_bsd::peer_cred;
#[cfg(any(target_os = "macos", target_os = "ios",))]
}
}
-#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
+#[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "netbsd"
+))]
pub mod impl_bsd {
use super::UCred;
use crate::io;
#[cfg(target_os = "vxworks")]
pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024;
+#[cfg(target_os = "fuchsia")]
+mod zircon {
+ type zx_handle_t = u32;
+ type zx_status_t = i32;
+ pub const ZX_PROP_NAME: u32 = 3;
+
+ extern "C" {
+ pub fn zx_object_set_property(
+ handle: zx_handle_t,
+ property: u32,
+ value: *const libc::c_void,
+ value_size: libc::size_t,
+ ) -> zx_status_t;
+ pub fn zx_thread_self() -> zx_handle_t;
+ }
+}
+
pub struct Thread {
id: libc::pthread_t,
}
}
}
+ #[cfg(target_os = "fuchsia")]
+ pub fn set_name(name: &CStr) {
+ use self::zircon::*;
+ unsafe {
+ zx_object_set_property(
+ zx_thread_self(),
+ ZX_PROP_NAME,
+ name.as_ptr() as *const libc::c_void,
+ name.to_bytes().len(),
+ );
+ }
+ }
+
#[cfg(any(
target_env = "newlib",
target_os = "haiku",
pub fn set_name(_name: &CStr) {
// Newlib, Haiku, Emscripten, and VxWorks have no way to set a thread name.
}
- #[cfg(target_os = "fuchsia")]
- pub fn set_name(_name: &CStr) {
- // FIXME: determine whether Fuchsia has a way to set a thread name.
- }
pub fn sleep(dur: Duration) {
let mut secs = dur.as_secs();
//!
//! This module contains some of the real meat in the rustbuild build system
//! which is where Cargo is used to compile the standard library, libtest, and
-//! compiler. This module is also responsible for assembling the sysroot as it
+//! the compiler. This module is also responsible for assembling the sysroot as it
//! goes along from the output of the previous stage.
use std::borrow::Cow;
use std::str::FromStr;
use crate::cache::{Interned, INTERNER};
+use crate::channel::GitInfo;
pub use crate::flags::Subcommand;
use crate::flags::{Color, Flags};
use crate::util::exe;
/// Call Build::ninja() instead of this.
pub ninja_in_file: bool,
pub verbose: usize,
- pub submodules: bool,
+ pub submodules: Option<bool>,
pub fast_submodules: bool,
pub compiler_docs: bool,
pub docs_minification: bool,
config.backtrace = true;
config.rust_optimize = true;
config.rust_optimize_tests = true;
- config.submodules = true;
+ config.submodules = None;
config.fast_submodules = true;
config.docs = true;
config.docs_minification = true;
config.npm = build.npm.map(PathBuf::from);
config.gdb = build.gdb.map(PathBuf::from);
config.python = build.python.map(PathBuf::from);
+ config.submodules = build.submodules;
set(&mut config.low_priority, build.low_priority);
set(&mut config.compiler_docs, build.compiler_docs);
set(&mut config.docs_minification, build.docs_minification);
set(&mut config.docs, build.docs);
- set(&mut config.submodules, build.submodules);
set(&mut config.fast_submodules, build.fast_submodules);
set(&mut config.locked_deps, build.locked_deps);
set(&mut config.vendor, build.vendor);
// CI-built LLVM can be either dynamic or static.
let ci_llvm = config.out.join(&*config.build.triple).join("ci-llvm");
- let link_type = t!(std::fs::read_to_string(ci_llvm.join("link-type.txt")));
- config.llvm_link_shared = link_type == "dynamic";
+ config.llvm_link_shared = if config.dry_run {
+ // just assume dynamic for now
+ true
+ } else {
+ let link_type = t!(
+ std::fs::read_to_string(ci_llvm.join("link-type.txt")),
+ format!("CI llvm missing: {}", ci_llvm.display())
+ );
+ link_type == "dynamic"
+ };
}
if config.llvm_thin_lto {
pub fn llvm_enabled(&self) -> bool {
self.rust_codegen_backends.contains(&INTERNER.intern_str("llvm"))
}
+
+ pub fn submodules(&self, rust_info: &GitInfo) -> bool {
+ self.submodules.unwrap_or(rust_info.is_git())
+ }
}
fn set<T>(field: &mut T, val: Option<T>) {
o("extended", "build.extended", "build an extended rust tool set")
v("tools", None, "List of extended tools will be installed")
+v("codegen-backends", None, "List of codegen backends to build")
v("build", "build.build", "GNUs ./configure syntax LLVM build triple")
v("host", None, "GNUs ./configure syntax LLVM host triples")
v("target", None, "GNUs ./configure syntax LLVM target triples")
set('target.{}.llvm-filecheck'.format(build()), value)
elif option.name == 'tools':
set('build.tools', value.split(','))
+ elif option.name == 'codegen-backends':
+ set('rust.codegen-backends', value.split(','))
elif option.name == 'host':
set('build.host', value.split(','))
elif option.name == 'target':
cmd.arg("--libfiles");
builder.verbose(&format!("running {:?}", cmd));
let files = output(&mut cmd);
+ let build_llvm_out = &builder.llvm_out(builder.config.build);
+ let target_llvm_out = &builder.llvm_out(target);
for file in files.trim_end().split(' ') {
- builder.install(Path::new(file), dst_libdir, 0o644);
+ // If we're not using a custom LLVM, make sure we package for the target.
+ let file = if let Ok(relative_path) = Path::new(file).strip_prefix(build_llvm_out) {
+ target_llvm_out.join(relative_path)
+ } else {
+ PathBuf::from(file)
+ };
+ builder.install(&file, dst_libdir, 0o644);
}
!builder.config.dry_run
} else {
fmt Run rustfmt
test, t Build and run some test suites
bench Build and run some benchmarks
- doc Build documentation
+ doc, d Build documentation
clean Clean out build directories
dist Build distribution artifacts
install Install distribution artifacts
|| (s == "t")
|| (s == "bench")
|| (s == "doc")
+ || (s == "d")
|| (s == "clean")
|| (s == "dist")
|| (s == "install")
"clippy" => {
opts.optflag("", "fix", "automatically apply lint suggestions");
}
- "doc" => {
+ "doc" | "d" => {
opts.optflag("", "open", "open the docs in a browser");
}
"clean" => {
./x.py test --stage 1",
);
}
- "doc" => {
+ "doc" | "d" => {
subcommand_help.push_str(
"\n
Arguments:
},
},
"bench" => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") },
- "doc" => Subcommand::Doc { paths, open: matches.opt_present("open") },
+ "doc" | "d" => Subcommand::Doc { paths, open: matches.opt_present("open") },
"clean" => {
if !paths.is_empty() {
println!("\nclean does not take a path argument\n");
};
let parent = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid.parse().unwrap());
- assert!(
- !parent.is_null(),
- "PID `{}` doesn't seem to exist: {}",
- pid,
- io::Error::last_os_error()
- );
+
+ // If we get a null parent pointer here, it is possible that either
+ // we have got an invalid pid or the parent process has been closed.
+ // Since the first case rarely happens
+ // (only when wrongly setting the environmental variable),
+ // so it might be better to improve the experience of the second case
+ // when users have interrupted the parent process and we don't finish
+ // duplicating the handle yet.
+ // We just need close the job object if that occurs.
+ if parent.is_null() {
+ CloseHandle(job);
+ return;
+ }
+
let mut parent_handle = ptr::null_mut();
let r = DuplicateHandle(
GetCurrentProcess(),
t!(std::fs::read_dir(dir)).next().is_none()
}
- if !self.config.submodules {
+ if !self.config.submodules(&self.rust_info) {
return;
}
"library/stdarch",
];
// Avoid running git when there isn't a git checkout.
- if !self.config.submodules {
+ if !self.config.submodules(&self.rust_info) {
return;
}
let output = output(
let idx = target.triple.find('-').unwrap();
format!("riscv{}{}", &target.triple[5..7], &target.triple[idx..])
+ } else if self.target.starts_with("powerpc") && self.target.ends_with("freebsd") {
+ // FreeBSD 13 had incompatible ABI changes on all PowerPC platforms.
+ // Set the version suffix to 13.0 so the correct target details are used.
+ format!("{}{}", self.target, "13.0")
} else {
target.to_string()
};
}
}
+ // Workaround for ppc32 lld limitation
+ if target == "powerpc-unknown-freebsd" {
+ cfg.define("CMAKE_EXE_LINKER_FLAGS", "-fuse-ld=bfd");
+ }
+
// https://llvm.org/docs/HowToCrossCompileLLVM.html
if target != builder.config.build {
builder.ensure(Llvm { target: builder.config.build });
// We remove existing folder to be sure there won't be artifacts remaining.
let _ = fs::remove_dir_all(&out_dir);
- let src_path = "src/test/rustdoc-gui/src";
+ let src_path = builder.build.src.join("src/test/rustdoc-gui/src");
// We generate docs for the libraries present in the rustdoc-gui's src folder.
- let mut cargo = Command::new(&builder.initial_cargo);
- cargo
- .arg("doc")
- .arg("--workspace")
- .arg("--target-dir")
- .arg(&out_dir)
- .env("RUSTDOC", builder.rustdoc(self.compiler))
- .env("RUSTC", builder.rustc(self.compiler))
- .current_dir(&builder.build.src.join(src_path));
- builder.run(&mut cargo);
+ for entry in src_path.read_dir().expect("read_dir call failed") {
+ if let Ok(entry) = entry {
+ let path = entry.path();
+
+ if !path.is_dir() {
+ continue;
+ }
+
+ let mut cargo = Command::new(&builder.initial_cargo);
+ cargo
+ .arg("doc")
+ .arg("--target-dir")
+ .arg(&out_dir)
+ .env("RUSTDOC", builder.rustdoc(self.compiler))
+ .env("RUSTC", builder.rustc(self.compiler))
+ .current_dir(path);
+ builder.run(&mut cargo);
+ }
+ }
// We now run GUI tests.
let mut command = Command::new(&nodejs);
`powerpc-wrs-vxworks` | ? | |
`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
`powerpc64le-unknown-freebsd` | | | PPC64LE FreeBSD
+`powerpc-unknown-freebsd` | | | PowerPC FreeBSD
`powerpc64-unknown-linux-musl` | ? | |
`powerpc64-wrs-vxworks` | ? | |
`powerpc64le-unknown-linux-musl` | ? | |
--- /dev/null
+# `force-warn`
+
+The tracking issue for this feature is: [#85512](https://github.com/rust-lang/rust/issues/85512).
+
+------------------------
+
+This feature allows you to cause any lint to produce a warning even if the lint has a different level by default or another level is set somewhere else. For instance, the `force-warn` option can be used to make a lint (e.g., `dead_code`) produce a warning even if that lint is allowed in code with `#![allow(dead_code)]`.
+
+## Example
+
+```rust,ignore (partial-example)
+#![allow(dead_code)]
+
+fn dead_function() {}
+// This would normally not produce a warning even though the
+// function is not used, because dead code is being allowed
+
+fn main() {}
+```
+
+We can force a warning to be produced by providing `--force-warn dead_code` to rustc.
+++ /dev/null
-# `force-warns`
-
-The tracking issue for this feature is: [#85512](https://github.com/rust-lang/rust/issues/85512).
-
-------------------------
-
-This feature allows you to cause any lint to produce a warning even if the lint has a different level by default or another level is set somewhere else. For instance, the `force-warns` option can be used to make a lint (e.g., `dead_code`) produce a warning even if that lint is allowed in code with `#![allow(dead_code)]`.
-
-## Example
-
-```rust,ignore (partial-example)
-#![allow(dead_code)]
-
-fn dead_function() {}
-// This would normally not produce a warning even though the
-// function is not used, because dead code is being allowed
-
-fn main() {}
-```
-
-We can force a warning to be produced by providing `--force-warns dead_code` to rustc.
--- /dev/null
+# `move_size_limit`
+
+--------------------
+
+The `-Zmove-size-limit=N` compiler flag enables `large_assignments` lints which
+will warn when moving objects whose size exceeds `N` bytes.
+
+Lint warns only about moves in functions that participate in code generation.
+Consequently it will be ineffective for compiler invocatation that emit
+metadata only, i.e., `cargo check` like workflows.
if root.is_local() {
tcx.hir()
.krate()
- .item
+ .module()
.item_ids
.iter()
.filter_map(|&id| {
if root.is_local() {
tcx.hir()
.krate()
- .item
+ .module()
.item_ids
.iter()
.filter_map(|&id| {
})
.collect(),
];
- let default_settings = default_settings.into_iter().flatten().collect();
+ let default_settings = default_settings
+ .into_iter()
+ .flatten()
+ .map(
+ // The keys here become part of `data-` attribute names in the generated HTML. The
+ // browser does a strange mapping when converting them into attributes on the
+ // `dataset` property on the DOM HTML Node:
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset
+ //
+ // The original key values we have are the same as the DOM storage API keys and the
+ // command line options, so contain `-`. Our Javascript needs to be able to look
+ // these values up both in `dataset` and in the storage API, so it needs to be able
+ // to convert the names back and forth. Despite doing this kebab-case to
+ // StudlyCaps transformation automatically, the JS DOM API does not provide a
+ // mechanism for doing the just transformation on a string. So we want to avoid
+ // the StudlyCaps representation in the `dataset` property.
+ //
+ // We solve this by replacing all the `-`s with `_`s. We do that here, when we
+ // generate the `data-` attributes, and in the JS, when we look them up. (See
+ // `getSettingValue` in `storage.js.`) Converting `-` to `_` is simple in JS.
+ //
+ // The values will be HTML-escaped by the default Tera escaping.
+ |(k, v)| (k.replace('-', "_"), v),
+ )
+ .collect();
let test_args = matches.opt_strs("test-args");
let test_args: Vec<String> =
registry: rustc_driver::diagnostics_registry(),
};
- let mut test_args = options.test_args.clone();
+ let test_args = options.test_args.clone();
let display_warnings = options.display_warnings;
let nocapture = options.nocapture;
let externs = options.externs.clone();
hir_collector.visit_testable(
"".to_string(),
CRATE_HIR_ID,
- krate.item.inner,
+ krate.module().inner,
|this| {
intravisit::walk_crate(this, krate);
},
Err(ErrorReported) => return Err(ErrorReported),
};
- test_args.insert(0, "rustdoctest".to_string());
- if nocapture {
- test_args.push("--nocapture".to_string());
- }
-
- test::test_main(&test_args, tests, Some(test::Options::new().display_output(display_warnings)));
+ run_tests(test_args, nocapture, display_warnings, tests);
// Collect and warn about unused externs, but only if we've gotten
// reports for each doctest
Ok(())
}
+crate fn run_tests(
+ mut test_args: Vec<String>,
+ nocapture: bool,
+ display_warnings: bool,
+ tests: Vec<test::TestDescAndFn>,
+) {
+ test_args.insert(0, "rustdoctest".to_string());
+ if nocapture {
+ test_args.push("--nocapture".to_string());
+ }
+ test::test_main(&test_args, tests, Some(test::Options::new().display_output(display_warnings)));
+}
+
// Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade.
fn scrape_test_config(attrs: &[ast::Attribute]) -> TestOptions {
use rustc_ast_pretty::pprust;
use crate::clean::RenderedLink;
use crate::doctest;
use crate::html::escape::Escape;
+use crate::html::format::Buffer;
use crate::html::highlight;
use crate::html::toc::TocBuilder;
html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag,
};
-use super::format::Buffer;
-
#[cfg(test)]
mod tests;
/// A subset of [`opts()`] used for rendering summaries.
pub(crate) fn summary_opts() -> Options {
- Options::ENABLE_STRIKETHROUGH | Options::ENABLE_SMART_PUNCTUATION
+ Options::ENABLE_STRIKETHROUGH | Options::ENABLE_SMART_PUNCTUATION | Options::ENABLE_TABLES
}
/// When `to_string` is called, this struct will emit the HTML corresponding to
return Some(Event::Html(
format!(
"<div class=\"example-wrap\">\
- <pre{}>{}</pre>\
+ <pre class=\"language-{}\">{}</pre>\
</div>",
- format!(" class=\"language-{}\"", lang),
+ lang,
Escape(&text),
)
.into(),
)
}
+fn is_forbidden_tag(t: &Tag<'_>) -> bool {
+ matches!(t, Tag::CodeBlock(_) | Tag::Table(_) | Tag::TableHead | Tag::TableRow | Tag::TableCell)
+}
+
impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
type Item = Event<'a>;
if let Some(event) = self.inner.next() {
let mut is_start = true;
let is_allowed_tag = match event {
- Event::Start(Tag::CodeBlock(_)) | Event::End(Tag::CodeBlock(_)) => {
- return None;
- }
Event::Start(ref c) => {
+ if is_forbidden_tag(c) {
+ return None;
+ }
self.depth += 1;
check_if_allowed_tag(c)
}
Event::End(ref c) => {
+ if is_forbidden_tag(c) {
+ return None;
+ }
self.depth -= 1;
is_start = false;
check_if_allowed_tag(c)
let mut stopped_early = false;
fn push(s: &mut String, text_length: &mut usize, text: &str) {
- s.push_str(text);
+ write!(s, "{}", Escape(text)).unwrap();
*text_length += text.len();
}
t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
t("dud [link]", "dud [link]");
t("code `let x = i32;` ...", "code <code>let x = i32;</code> …");
- t("type `Type<'static>` ...", "type <code>Type<'static></code> …");
+ t("type `Type<'static>` ...", "type <code>Type<'static></code> …");
+ // Test to ensure escaping and length-limiting work well together.
+ // The output should be limited based on the input length,
+ // rather than the output, because escaped versions of characters
+ // are usually longer than how the character is actually displayed.
+ t(
+ "& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &",
+ "& & & & & & & & & & & & \
+ & & & & & & & & & & & & \
+ & & & & & …",
+ );
t("# top header", "top header");
t("# top header\n\nfollowed by a paragraph", "top header");
t("## header", "header");
if out.is_empty() {
write!(
&mut out,
- "<h3 class=\"notable\">Notable traits for {}</h3>\
+ "<div class=\"notable\">Notable traits for {}</div>\
<code class=\"content\">",
impl_.for_.print(cx)
);
);
render_rightside(w, cx, item, containing_item);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
- w.write_str("<code>");
+ w.write_str("<h4 class=\"code-header\">");
render_assoc_item(
w,
item,
ItemType::Impl,
cx,
);
- w.write_str("</code>");
+ w.write_str("</h4>");
w.write_str("</div>");
}
}
id, item_type, in_trait_class
);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
- w.write_str("<code>");
+ w.write_str("<h4 class=\"code-header\">");
assoc_type(
w,
item,
"",
cx,
);
- w.write_str("</code>");
+ w.write_str("</h4>");
w.write_str("</div>");
}
clean::AssocConstItem(ref ty, ref default) => {
);
render_rightside(w, cx, item, containing_item);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
- w.write_str("<code>");
+ w.write_str("<h4 class=\"code-header\">");
assoc_const(
w,
item,
"",
cx,
);
- w.write_str("</code>");
+ w.write_str("</h4>");
w.write_str("</div>");
}
clean::AssocTypeItem(ref bounds, ref default) => {
let id = cx.derive_id(source_id.clone());
write!(w, "<div id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
- w.write_str("<code>");
+ w.write_str("<h4 class=\"code-header\">");
assoc_type(
w,
item,
"",
cx,
);
- w.write_str("</code>");
+ w.write_str("</h4>");
w.write_str("</div>");
}
clean::StrippedItem(..) => return,
write!(w, "<div id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
render_rightside(w, cx, &i.impl_item, containing_item);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
- write!(w, "<code class=\"in-band\">");
+ write!(w, "<h3 class=\"code-header in-band\">");
if let Some(use_absolute) = use_absolute {
write!(w, "{}", i.inner_impl().print(use_absolute, cx));
} else {
write!(w, "{}", i.inner_impl().print(false, cx));
}
- write!(w, "</code>");
+ write!(w, "</h3>");
let is_trait = i.inner_impl().trait_.is_some();
if is_trait {
use clean::AttributesExt;
use std::cmp::Ordering;
+use std::fmt;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
n_fields > 12
}
-fn toggle_open(w: &mut Buffer, text: &str) {
+fn toggle_open(w: &mut Buffer, text: impl fmt::Display) {
write!(
w,
"<details class=\"rustdoc-toggle type-contents-toggle\">\
let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
let required = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
let provided = t.items.iter().filter(|m| m.is_method()).collect::<Vec<_>>();
+ let count_types = types.len();
+ let count_consts = consts.len();
+ let count_methods = required.len() + provided.len();
// Output the trait definition
wrap_into_docblock(w, |w| {
let mut toggle = false;
// If there are too many associated types, hide _everything_
- if should_hide_fields(types.len()) {
+ if should_hide_fields(count_types) {
toggle = true;
- toggle_open(w, "associated items");
+ toggle_open(
+ w,
+ format_args!("{} associated items", count_types + count_consts + count_methods),
+ );
}
for t in &types {
render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
// We also do this if the types + consts is large because otherwise we could
// render a bunch of types and _then_ a bunch of consts just because both were
// _just_ under the limit
- if !toggle && should_hide_fields(types.len() + consts.len()) {
+ if !toggle && should_hide_fields(count_types + count_consts) {
toggle = true;
- toggle_open(w, "associated constants and methods");
+ toggle_open(
+ w,
+ format_args!(
+ "{} associated constant{} and {} method{}",
+ count_consts,
+ pluralize(count_consts),
+ count_methods,
+ pluralize(count_methods),
+ ),
+ );
}
if !types.is_empty() && !consts.is_empty() {
w.write_str("\n");
render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
w.write_str(";\n");
}
- if !toggle && should_hide_fields(required.len() + provided.len()) {
+ if !toggle && should_hide_fields(count_methods) {
toggle = true;
- toggle_open(w, "methods");
+ toggle_open(w, format_args!("{} methods", count_methods));
}
if !consts.is_empty() && !required.is_empty() {
w.write_str("\n");
render_stability_since(w, m, t, cx.tcx());
write_srclink(cx, m, w);
write!(w, "</div>");
- write!(w, "<code>");
+ write!(w, "<h4 class=\"code-header\">");
render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl, cx);
- w.write_str("</code>");
+ w.write_str("</h4>");
w.write_str("</div>");
if toggled {
write!(w, "</summary>");
wrap_into_docblock(w, |w| {
w.write_str("<pre class=\"rust union\">");
render_attributes_in_pre(w, it, "");
- render_union(w, it, Some(&s.generics), &s.fields, "", true, cx);
+ render_union(w, it, Some(&s.generics), &s.fields, "", cx);
w.write_str("</pre>")
});
w.write_str(" {}");
} else {
w.write_str(" {\n");
- let toggle = should_hide_fields(e.variants.len());
+ let count_variants = e.variants.len();
+ let toggle = should_hide_fields(count_variants);
if toggle {
- toggle_open(w, "variants");
+ toggle_open(w, format_args!("{} variants", count_variants));
}
for v in &e.variants {
w.write_str(" ");
use crate::clean::Variant;
if let clean::VariantItem(Variant::Struct(ref s)) = *variant.kind {
- toggle_open(w, "fields");
let variant_id = cx.derive_id(format!(
"{}.{}.fields",
ItemType::Variant,
variant.name.as_ref().unwrap()
));
- write!(w, "<div class=\"autohide sub-variant\" id=\"{id}\">", id = variant_id);
+ write!(w, "<div class=\"sub-variant\" id=\"{id}\">", id = variant_id);
write!(
w,
"<h3>Fields of <b>{name}</b></h3><div>",
}
}
w.write_str("</div></div>");
- toggle_close(w);
}
}
}
g: Option<&clean::Generics>,
fields: &[clean::Item],
tab: &str,
- structhead: bool,
cx: &Context<'_>,
) {
write!(
w,
- "{}{}{}",
+ "{}union {}",
it.visibility.print_with_space(it.def_id, cx),
- if structhead { "union " } else { "" },
it.name.as_ref().unwrap()
);
if let Some(g) = g {
fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count();
let toggle = should_hide_fields(count_fields);
if toggle {
- toggle_open(w, "fields");
+ toggle_open(w, format_args!("{} fields", count_fields));
}
for field in fields {
let has_visible_fields = count_fields > 0;
let toggle = should_hide_fields(count_fields);
if toggle {
- toggle_open(w, "fields");
+ toggle_open(w, format_args!("{} fields", count_fields));
}
for field in fields {
if let clean::StructFieldItem(ref ty) = *field.kind {
writeln!(w, "</div>");
}
+
+fn pluralize(count: usize) -> &'static str {
+ if count > 1 { "s" } else { "" }
+}
h2, h3, h4 {
border-bottom: 1px solid;
}
+h3.code-header, h4.code-header {
+ font-size: 1em;
+ font-weight: 600;
+ border: none;
+ padding: 0;
+ margin: 0;
+}
.impl,
.impl-items .method,
.methods .method,
margin-bottom: .6em;
}
-code, pre, a.test-arrow {
+code, pre, a.test-arrow, .code-header {
font-family: "Source Code Pro", monospace;
}
.docblock code, .docblock-short code {
.logo-container > img {
max-width: 100px;
max-height: 100px;
+ height: 100%;
position: absolute;
left: 50%;
top: 50%;
font-weight: normal;
}
-.method > code, .trait-impl > code, .invisible > code {
+.method > .code-header, .trait-impl > .code-header, .invisible > .code-header {
max-width: calc(100% - 41px);
display: block;
}
padding: 0px;
}
-.in-band > code {
+.in-band > code, .in-band > .code-header {
display: inline-block;
}
}
.invisible > .srclink,
-.method > code + .srclink {
+.method > .code-header + .srclink {
position: absolute;
top: 0;
right: 0;
padding-top: 1px;
}
-#main > details > .sub-variant > h3 {
+#main .sub-variant > h3 {
font-size: 15px;
margin-left: 25px;
margin-bottom: 5px;
left: -10px;
}
-:target > code {
+:target > code, :target > .code-header {
opacity: 1;
}
color: #999;
}
-:target, :target * {
+:target, :target > * {
background: rgba(255, 236, 164, 0.06);
}
color: #999;
}
-:target, :target * {
+:target, :target > * {
background-color: #494a3d;
}
color: #999;
}
-:target, :target * {
+:target, :target > * {
background: #FDFFD3;
}
}
}
- var code = document.createElement("code");
+ var code = document.createElement("h3");
code.innerHTML = struct.text;
+ addClass(code, "code-header");
addClass(code, "in-band");
onEachLazy(code.getElementsByTagName("a"), function(elem) {
return current;
}
if (settingsDataset !== null) {
+ // See the comment for `default_settings.into_iter()` etc. in
+ // `Options::from_matches` in `librustdoc/config.rs`.
var def = settingsDataset[settingName.replace(/-/g,'_')];
if (def !== undefined) {
return def;
</select> {#- -#}
{%- endif -%}
<input {# -#}
- class="search-input"{# -#}
+ class="search-input" {# -#}
name="search" {# -#}
disabled {# -#}
autocomplete="off" {# -#}
"LEVEL",
)
}),
- unstable("force-warns", |o| {
+ unstable("force-warn", |o| {
o.optopt(
"",
- "force-warns",
+ "force-warn",
"Lints that will warn even if allowed somewhere else",
"LINTS",
)
}
/// Runs any tests/code examples in the markdown file `input`.
-crate fn test(mut options: Options) -> Result<(), String> {
+crate fn test(options: Options) -> Result<(), String> {
let input_str = read_to_string(&options.input)
.map_err(|err| format!("{}: {}", options.input.display(), err))?;
let mut opts = TestOptions::default();
find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores, None);
- options.test_args.insert(0, "rustdoctest".to_string());
- if options.nocapture {
- options.test_args.push("--nocapture".to_string());
- }
- test::test_main(
- &options.test_args,
+ crate::doctest::run_tests(
+ options.test_args,
+ options.nocapture,
+ options.display_warnings,
collector.tests,
- Some(test::Options::new().display_output(options.display_warnings)),
);
Ok(())
}
}
crate fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> {
- let span = krate.item.inner;
+ let span = krate.module().inner;
let mut top_level_module = self.visit_mod_contents(
&Spanned { span, node: hir::VisibilityKind::Public },
hir::CRATE_HIR_ID,
- &krate.item,
+ &krate.module(),
self.cx.tcx.crate_name(LOCAL_CRATE),
);
// Attach the crate's exported macros to the top-level module.
// In the case of macros 2.0 (`pub macro`), and for built-in `derive`s or attributes as
// well (_e.g._, `Copy`), these are wrongly bundled in there too, so we need to fix that by
// moving them back to their correct locations.
- 'exported_macros: for def in krate.exported_macros {
+ 'exported_macros: for def in krate.exported_macros() {
// The `def` of a macro in `exported_macros` should correspond to either:
// - a `#[macro_export] macro_rules!` macro,
// - a built-in `derive` (or attribute) macro such as the ones in `::core`,
// Test that `-Cprofile-generate` creates expected instrumentation artifacts in LLVM IR.
-// Compiling with `-Cpanic=abort` because PGO+unwinding isn't supported on all platforms.
// needs-profiler-support
-// compile-flags: -Cprofile-generate -Ccodegen-units=1 -Cpanic=abort
+// compile-flags: -Cprofile-generate -Ccodegen-units=1
// CHECK: @__llvm_profile_raw_version =
// CHECK-DAG: @__profc_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = {{.*}}global
// cdb-check: [0x1] : 42 [Type: int]
// cdb-command: dx vecdeque
-// cdb-check:vecdeque : { len=0x2 } [Type: alloc::collections::vec_deque::VecDeque<i32>]
-// cdb-check: [<Raw View>] [Type: alloc::collections::vec_deque::VecDeque<i32>]
+// cdb-check:vecdeque : { len=0x2 } [Type: alloc::collections::vec_deque::VecDeque<i32,alloc::alloc::Global>]
+// cdb-check: [<Raw View>] [Type: alloc::collections::vec_deque::VecDeque<i32,alloc::alloc::Global>]
// cdb-check: [len] : 0x2
// cdb-check: [capacity] : 0x8 [Type: unsigned [...]]
// cdb-check: [0x0] : 90 [Type: int]
--- /dev/null
+- // MIR for `identity` before ConstProp
++ // MIR for `identity` after ConstProp
+
+ fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
+ debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:28:13: 28:14
+ let mut _0: std::result::Result<i32, i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:28:37: 28:53
+ let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _3: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, i32>, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _4: std::result::Result<i32, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9
+ let mut _5: isize; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ let _6: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ let mut _7: !; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ let mut _8: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 1 {
+ debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:29:9: 29:10
+ scope 2 {
+ scope 8 (inlined <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+ debug residual => _8; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let _16: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _17: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _18: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 9 {
+ debug e => _16; // in scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 10 (inlined <i32 as From<i32>>::from) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+ debug t => _18; // in scope 10 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+ }
+ }
+ }
+ }
+ scope 3 {
+ debug val => _9; // in scope 3 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 4 {
+ }
+ }
+ scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+ debug self => _4; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _10: isize; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let _11: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _12: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let _13: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _14: std::result::Result<std::convert::Infallible, i32>; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _15: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 6 {
+ debug v => _11; // in scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+ scope 7 {
+ debug e => _13; // in scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9
+ _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9
+ StorageLive(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _10 = discriminant(_4); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ switchInt(move _10) -> [0_isize: bb5, 1_isize: bb3, otherwise: bb4]; // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+
+ bb1: {
+ StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _9 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _2 = _9; // scope 4 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
+ discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
+ StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11
+ StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:30:1: 30:2
+ return; // scope 0 at $DIR/separate_const_switch.rs:30:2: 30:2
+ }
+
+ bb2: {
+ StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ _6 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ StorageLive(_8); // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10
+ _8 = _6; // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10
+ StorageLive(_16); // scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _16 = move ((_8 as Err).0: i32); // scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_17); // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_18); // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _18 = move _16; // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _17 = move _18; // scope 10 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_18); // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ ((_0 as Err).0: i32) = move _17; // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ discriminant(_0) = 1; // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_17); // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_16); // scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10
+ StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11
+ StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:30:1: 30:2
+ return; // scope 0 at $DIR/separate_const_switch.rs:30:2: 30:2
+ }
+
+ bb3: {
+ StorageLive(_13); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _13 = move ((_4 as Err).0: i32); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_14); // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_15); // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _15 = move _13; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ ((_14 as Err).0: i32) = move _15; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ discriminant(_14) = 1; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_15); // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _14; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ discriminant(_3) = 1; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_14); // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_13); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+- switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
++ _5 = const 1_isize; // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
++ switchInt(const 1_isize) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ }
+
+ bb4: {
+ unreachable; // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+
+ bb5: {
+ StorageLive(_11); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _11 = move ((_4 as Ok).0: i32); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_12); // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _12 = move _11; // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ ((_3 as Continue).0: i32) = move _12; // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ discriminant(_3) = 0; // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_12); // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_11); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+- switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
++ _5 = const 0_isize; // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
++ switchInt(const 0_isize) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ }
+ }
+
--- /dev/null
+// MIR for `identity` after PreCodegen
+
+fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
+ debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:28:13: 28:14
+ let mut _0: std::result::Result<i32, i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:28:37: 28:53
+ let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _3: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, i32>, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _4: std::result::Result<i32, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9
+ let _5: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ let mut _6: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ let _7: i32; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 1 {
+ debug residual => _5; // in scope 1 at $DIR/separate_const_switch.rs:29:9: 29:10
+ scope 2 {
+ scope 8 (inlined <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+ debug residual => _6; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let _14: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _15: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _16: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 9 {
+ debug e => _14; // in scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 10 (inlined <i32 as From<i32>>::from) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+ debug t => _16; // in scope 10 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+ }
+ }
+ }
+ }
+ scope 3 {
+ debug val => _7; // in scope 3 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 4 {
+ }
+ }
+ scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+ debug self => _4; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _8: isize; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let _9: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _10: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let _11: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _12: std::result::Result<std::convert::Infallible, i32>; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _13: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 6 {
+ debug v => _9; // in scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+ scope 7 {
+ debug e => _11; // in scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9
+ _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9
+ StorageLive(_8); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _8 = discriminant(_4); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ switchInt(move _8) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+
+ bb1: {
+ StorageLive(_11); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _11 = move ((_4 as Err).0: i32); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_12); // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_13); // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _13 = move _11; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ ((_12 as Err).0: i32) = move _13; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ discriminant(_12) = 1; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_13); // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _12; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ discriminant(_3) = 1; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_12); // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_11); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_8); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ StorageLive(_5); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ _5 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ StorageLive(_6); // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10
+ _6 = _5; // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10
+ StorageLive(_14); // scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _14 = move ((_6 as Err).0: i32); // scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_15); // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_16); // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _16 = move _14; // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _15 = move _16; // scope 10 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_16); // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ ((_0 as Err).0: i32) = move _15; // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ discriminant(_0) = 1; // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_15); // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_14); // scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_6); // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10
+ StorageDead(_5); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11
+ StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:30:1: 30:2
+ return; // scope 0 at $DIR/separate_const_switch.rs:30:2: 30:2
+ }
+
+ bb2: {
+ unreachable; // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+
+ bb3: {
+ StorageLive(_9); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _9 = move ((_4 as Ok).0: i32); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_10); // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _10 = move _9; // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ ((_3 as Continue).0: i32) = move _10; // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ discriminant(_3) = 0; // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_10); // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_9); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_8); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ StorageLive(_7); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _7 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _2 = _7; // scope 4 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_7); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
+ discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
+ StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11
+ StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:30:1: 30:2
+ return; // scope 0 at $DIR/separate_const_switch.rs:30:2: 30:2
+ }
+}
--- /dev/null
+- // MIR for `identity` before SeparateConstSwitch
++ // MIR for `identity` after SeparateConstSwitch
+
+ fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
+ debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:28:13: 28:14
+ let mut _0: std::result::Result<i32, i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:28:37: 28:53
+ let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _3: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, i32>, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _4: std::result::Result<i32, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9
+ let mut _5: isize; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ let _6: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ let mut _7: !; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ let mut _8: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 1 {
+ debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:29:9: 29:10
+ scope 2 {
+ scope 8 (inlined <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+ debug residual => _8; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let _16: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _17: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _18: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 9 {
+ debug e => _16; // in scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 10 (inlined <i32 as From<i32>>::from) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+ debug t => _18; // in scope 10 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+ }
+ }
+ }
+ }
+ scope 3 {
+ debug val => _9; // in scope 3 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 4 {
+ }
+ }
+ scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+ debug self => _4; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _10: isize; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let _11: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _12: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let _13: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _14: std::result::Result<std::convert::Infallible, i32>; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ let mut _15: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 6 {
+ debug v => _11; // in scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+ scope 7 {
+ debug e => _13; // in scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9
+ _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9
+ StorageLive(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _10 = discriminant(_4); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+- switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
++ switchInt(move _10) -> [0_isize: bb5, 1_isize: bb3, otherwise: bb4]; // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+
+ bb1: {
+- StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+- StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+- switchInt(move _5) -> [0_isize: bb2, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+- }
+-
+- bb2: {
+ StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _9 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _2 = _9; // scope 4 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
+ discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
+ StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11
+ StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:30:1: 30:2
+ return; // scope 0 at $DIR/separate_const_switch.rs:30:2: 30:2
+ }
+
+- bb3: {
++ bb2: {
+ StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ _6 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ StorageLive(_8); // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10
+ _8 = _6; // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10
+ StorageLive(_16); // scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _16 = move ((_8 as Err).0: i32); // scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_17); // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_18); // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _18 = move _16; // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _17 = move _18; // scope 10 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_18); // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ ((_0 as Err).0: i32) = move _17; // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ discriminant(_0) = 1; // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_17); // scope 9 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_16); // scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10
+ StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11
+ StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:30:1: 30:2
+ return; // scope 0 at $DIR/separate_const_switch.rs:30:2: 30:2
+ }
+
+- bb4: {
++ bb3: {
+ StorageLive(_13); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _13 = move ((_4 as Err).0: i32); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_14); // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_15); // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _15 = move _13; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ ((_14 as Err).0: i32) = move _15; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ discriminant(_14) = 1; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_15); // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _14; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ discriminant(_3) = 1; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_14); // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_13); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+- goto -> bb1; // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
++ StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
++ StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
++ _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
++ switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ }
+
+- bb5: {
++ bb4: {
+ unreachable; // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ }
+
+- bb6: {
++ bb5: {
+ StorageLive(_11); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _11 = move ((_4 as Ok).0: i32); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageLive(_12); // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ _12 = move _11; // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ ((_3 as Continue).0: i32) = move _12; // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ discriminant(_3) = 0; // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_12); // scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10
+ StorageDead(_11); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
+- goto -> bb1; // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10
++ StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
++ StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
++ _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
++ switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+ }
+ }
+
--- /dev/null
+#![feature(control_flow_enum)]
+#![feature(try_trait_v2)]
+
+use std::ops::ControlFlow;
+
+// EMIT_MIR separate_const_switch.too_complex.SeparateConstSwitch.diff
+// EMIT_MIR separate_const_switch.too_complex.ConstProp.diff
+// EMIT_MIR separate_const_switch.too_complex.PreCodegen.after.mir
+fn too_complex(x: Result<i32, usize>) -> Option<i32> {
+ // The pass should break the outer match into
+ // two blocks that only have one parent each.
+ // Parents are one of the two branches of the first
+ // match, so a later pass can propagate constants.
+ match {
+ match x {
+ Ok(v) => ControlFlow::Continue(v),
+ Err(r) => ControlFlow::Break(r),
+ }
+ } {
+ ControlFlow::Continue(v) => Some(v),
+ ControlFlow::Break(r) => None,
+ }
+}
+
+// EMIT_MIR separate_const_switch.identity.SeparateConstSwitch.diff
+// EMIT_MIR separate_const_switch.identity.ConstProp.diff
+// EMIT_MIR separate_const_switch.identity.PreCodegen.after.mir
+fn identity(x: Result<i32, i32>) -> Result<i32, i32> {
+ Ok(x?)
+}
+
+fn main() {
+ too_complex(Ok(0));
+ identity(Ok(0));
+}
--- /dev/null
+- // MIR for `too_complex` before ConstProp
++ // MIR for `too_complex` after ConstProp
+
+ fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
+ debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:9:16: 9:17
+ let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:9:42: 9:53
+ let mut _2: std::ops::ControlFlow<usize, i32>; // in scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6
+ let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:16:13: 16:18
+ let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17
+ let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:16:44: 16:45
+ let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18
+ let mut _7: usize; // in scope 0 at $DIR/separate_const_switch.rs:17:42: 17:43
+ let mut _8: isize; // in scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
+ let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32
+ let mut _10: i32; // in scope 0 at $DIR/separate_const_switch.rs:20:42: 20:43
+ let _11: usize; // in scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
+ scope 1 {
+ debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:16:16: 16:17
+ }
+ scope 2 {
+ debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:17:17: 17:18
+ }
+ scope 3 {
+ debug v => _9; // in scope 3 at $DIR/separate_const_switch.rs:20:31: 20:32
+ }
+ scope 4 {
+ debug r => _11; // in scope 4 at $DIR/separate_const_switch.rs:21:28: 21:29
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6
+ _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:16:13: 16:18
+ switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/separate_const_switch.rs:16:13: 16:18
+ }
+
+ bb1: {
+ StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18
+ _6 = ((_1 as Err).0: usize); // scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18
+ StorageLive(_7); // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43
+ _7 = _6; // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43
+ ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
+ discriminant(_2) = 1; // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
+ StorageDead(_7); // scope 2 at $DIR/separate_const_switch.rs:17:43: 17:44
+ StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:17:43: 17:44
+- _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
+- switchInt(move _8) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
++ _8 = const 1_isize; // scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
++ switchInt(const 1_isize) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
+ }
+
+ bb2: {
+ StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17
+ _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17
+ StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45
+ _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45
+ ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
+ discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
+ StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:16:45: 16:46
+ StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:16:45: 16:46
+- _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
+- switchInt(move _8) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
++ _8 = const 0_isize; // scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
++ switchInt(const 0_isize) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
+ }
+
+ bb3: {
+ StorageLive(_11); // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
+ _11 = ((_2 as Break).0: usize); // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
+ discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38
+ StorageDead(_11); // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38
+ goto -> bb5; // scope 0 at $DIR/separate_const_switch.rs:14:5: 22:6
+ }
+
+ bb4: {
+ StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32
+ _9 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32
+ StorageLive(_10); // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43
+ _10 = _9; // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43
+ ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
+ discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
+ StorageDead(_10); // scope 3 at $DIR/separate_const_switch.rs:20:43: 20:44
+ StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:20:43: 20:44
+ goto -> bb5; // scope 0 at $DIR/separate_const_switch.rs:14:5: 22:6
+ }
+
+ bb5: {
+ StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:23:1: 23:2
+ return; // scope 0 at $DIR/separate_const_switch.rs:23:2: 23:2
+ }
+ }
+
--- /dev/null
+// MIR for `too_complex` after PreCodegen
+
+fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
+ debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:9:16: 9:17
+ let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:9:42: 9:53
+ let mut _2: std::ops::ControlFlow<usize, i32>; // in scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6
+ let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:16:13: 16:18
+ let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17
+ let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:16:44: 16:45
+ let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18
+ let mut _7: usize; // in scope 0 at $DIR/separate_const_switch.rs:17:42: 17:43
+ let _8: i32; // in scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32
+ let mut _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:20:42: 20:43
+ let _10: usize; // in scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
+ scope 1 {
+ debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:16:16: 16:17
+ }
+ scope 2 {
+ debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:17:17: 17:18
+ }
+ scope 3 {
+ debug v => _8; // in scope 3 at $DIR/separate_const_switch.rs:20:31: 20:32
+ }
+ scope 4 {
+ debug r => _10; // in scope 4 at $DIR/separate_const_switch.rs:21:28: 21:29
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6
+ _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:16:13: 16:18
+ switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/separate_const_switch.rs:16:13: 16:18
+ }
+
+ bb1: {
+ StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18
+ _6 = ((_1 as Err).0: usize); // scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18
+ StorageLive(_7); // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43
+ _7 = _6; // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43
+ ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
+ discriminant(_2) = 1; // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
+ StorageDead(_7); // scope 2 at $DIR/separate_const_switch.rs:17:43: 17:44
+ StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:17:43: 17:44
+ StorageLive(_10); // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
+ _10 = ((_2 as Break).0: usize); // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
+ discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38
+ StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38
+ goto -> bb3; // scope 0 at $DIR/separate_const_switch.rs:14:5: 22:6
+ }
+
+ bb2: {
+ StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17
+ _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17
+ StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45
+ _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45
+ ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
+ discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
+ StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:16:45: 16:46
+ StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:16:45: 16:46
+ StorageLive(_8); // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32
+ _8 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32
+ StorageLive(_9); // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43
+ _9 = _8; // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43
+ ((_0 as Some).0: i32) = move _9; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
+ discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
+ StorageDead(_9); // scope 3 at $DIR/separate_const_switch.rs:20:43: 20:44
+ StorageDead(_8); // scope 0 at $DIR/separate_const_switch.rs:20:43: 20:44
+ goto -> bb3; // scope 0 at $DIR/separate_const_switch.rs:14:5: 22:6
+ }
+
+ bb3: {
+ StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:23:1: 23:2
+ return; // scope 0 at $DIR/separate_const_switch.rs:23:2: 23:2
+ }
+}
--- /dev/null
+- // MIR for `too_complex` before SeparateConstSwitch
++ // MIR for `too_complex` after SeparateConstSwitch
+
+ fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
+ debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:9:16: 9:17
+ let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:9:42: 9:53
+ let mut _2: std::ops::ControlFlow<usize, i32>; // in scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6
+ let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:16:13: 16:18
+ let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17
+ let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:16:44: 16:45
+ let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18
+ let mut _7: usize; // in scope 0 at $DIR/separate_const_switch.rs:17:42: 17:43
+ let mut _8: isize; // in scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
+ let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32
+ let mut _10: i32; // in scope 0 at $DIR/separate_const_switch.rs:20:42: 20:43
+ let _11: usize; // in scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
+ scope 1 {
+ debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:16:16: 16:17
+ }
+ scope 2 {
+ debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:17:17: 17:18
+ }
+ scope 3 {
+ debug v => _9; // in scope 3 at $DIR/separate_const_switch.rs:20:31: 20:32
+ }
+ scope 4 {
+ debug r => _11; // in scope 4 at $DIR/separate_const_switch.rs:21:28: 21:29
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:14:11: 19:6
+ _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:16:13: 16:18
+ switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/separate_const_switch.rs:16:13: 16:18
+ }
+
+ bb1: {
+ StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18
+ _6 = ((_1 as Err).0: usize); // scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18
+ StorageLive(_7); // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43
+ _7 = _6; // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43
+ ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
+ discriminant(_2) = 1; // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
+ StorageDead(_7); // scope 2 at $DIR/separate_const_switch.rs:17:43: 17:44
+ StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:17:43: 17:44
+- goto -> bb3; // scope 0 at $DIR/separate_const_switch.rs:15:9: 18:10
++ _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
++ switchInt(move _8) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
+ }
+
+ bb2: {
+ StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17
+ _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17
+ StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45
+ _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45
+ ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
+ discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
+ StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:16:45: 16:46
+ StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:16:45: 16:46
+- goto -> bb3; // scope 0 at $DIR/separate_const_switch.rs:15:9: 18:10
+- }
+-
+- bb3: {
+ _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
+- switchInt(move _8) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
++ switchInt(move _8) -> [0_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:20:9: 20:33
+ }
+
+- bb4: {
++ bb3: {
+ StorageLive(_11); // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
+ _11 = ((_2 as Break).0: usize); // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
+ discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38
+ StorageDead(_11); // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38
+- goto -> bb6; // scope 0 at $DIR/separate_const_switch.rs:14:5: 22:6
++ goto -> bb5; // scope 0 at $DIR/separate_const_switch.rs:14:5: 22:6
+ }
+
+- bb5: {
++ bb4: {
+ StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32
+ _9 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32
+ StorageLive(_10); // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43
+ _10 = _9; // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43
+ ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
+ discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
+ StorageDead(_10); // scope 3 at $DIR/separate_const_switch.rs:20:43: 20:44
+ StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:20:43: 20:44
+- goto -> bb6; // scope 0 at $DIR/separate_const_switch.rs:14:5: 22:6
++ goto -> bb5; // scope 0 at $DIR/separate_const_switch.rs:14:5: 22:6
+ }
+
+- bb6: {
++ bb5: {
+ StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:23:1: 23:2
+ return; // scope 0 at $DIR/separate_const_switch.rs:23:2: 23:2
+ }
+ }
+
// This is meant as a test case for Issue 3961.
//
-// Test via: rustc --pretty normal src/test/pretty/block-comment-wchar.rs
+// Test via: rustc -Zunpretty normal src/test/pretty/block-comment-wchar.rs
// ignore-tidy-cr
// ignore-tidy-tab
// pp-exact:block-comment-wchar.pp
// This is meant as a test case for Issue 3961.
//
-// Test via: rustc --pretty normal src/test/pretty/block-comment-wchar.rs
+// Test via: rustc -Zunpretty normal src/test/pretty/block-comment-wchar.rs
// ignore-tidy-cr
// ignore-tidy-tab
// pp-exact:block-comment-wchar.pp
-include ../tools.mk
-# This test makes sure that instrumented binaries record the right counts for
-# functions being called and branches being taken. We run an instrumented binary
-# with an argument that causes a know path through the program and then check
-# that the expected counts get added to the use-phase LLVM IR.
-
-# LLVM doesn't support instrumenting binaries that use SEH:
-# https://github.com/rust-lang/rust/issues/61002
-#
-# Things work fine with -Cpanic=abort though.
-ifdef IS_MSVC
-COMMON_FLAGS=-Cpanic=abort
-endif
-
# For some very small programs GNU ld seems to not properly handle
# instrumentation sections correctly. Neither Gold nor LLD have that problem.
ifeq ($(UNAME),Linux)
COMPILE_FLAGS=-Copt-level=3 -Clto=fat -Cprofile-generate="$(TMPDIR)"
-# LLVM doesn't yet support instrumenting binaries that use unwinding on MSVC:
-# https://github.com/rust-lang/rust/issues/61002
-#
-# Things work fine with -Cpanic=abort though.
-ifdef IS_MSVC
-COMPILE_FLAGS+= -Cpanic=abort
-endif
-
all:
$(RUSTC) $(COMPILE_FLAGS) test.rs
$(call RUN,test) || exit 1
COMPILE_FLAGS=-O -Ccodegen-units=1 -Cprofile-generate="$(TMPDIR)"
-# LLVM doesn't yet support instrumenting binaries that use unwinding on MSVC:
-# https://github.com/rust-lang/rust/issues/61002
-#
-# Things work fine with -Cpanic=abort though.
-ifdef IS_MSVC
-COMPILE_FLAGS+= -Cpanic=abort
-endif
-
all:
$(RUSTC) $(COMPILE_FLAGS) --emit=llvm-ir test.rs
# We expect symbols starting with "__llvm_profile_".
COMPILE_FLAGS=-g -Cprofile-generate="$(TMPDIR)"
-# LLVM doesn't yet support instrumenting binaries that use unwinding on MSVC:
-# https://github.com/rust-lang/rust/issues/61002
-#
-# Things work fine with -Cpanic=abort though.
-ifdef IS_MSVC
-COMPILE_FLAGS+= -Cpanic=abort
-endif
-
all:
$(RUSTC) $(COMPILE_FLAGS) test.rs
$(call RUN,test) || exit 1
-include ../tools.mk
-# This test makes sure that indirect call promotion is performed. The test
-# programs calls the same function a thousand times through a function pointer.
-# Only PGO data provides the information that it actually always is the same
-# function. We verify that the indirect call promotion pass inserts a check
-# whether it can make a direct call instead of the indirect call.
-
-# LLVM doesn't support instrumenting binaries that use SEH:
-# https://github.com/rust-lang/rust/issues/61002
-#
-# Things work fine with -Cpanic=abort though.
-ifdef IS_MSVC
-COMMON_FLAGS=-Cpanic=abort
-endif
-
all:
# We don't compile `opaque` with either optimizations or instrumentation.
# We don't compile `opaque` with either optimizations or instrumentation.
COMMON_FLAGS=-Copt-level=2 -Ccodegen-units=1 -Cllvm-args=-disable-preinline
-# LLVM doesn't support instrumenting binaries that use SEH:
-# https://github.com/rust-lang/rust/issues/61002
-#
-# Things work fine with -Cpanic=abort though.
-ifdef IS_MSVC
-COMMON_FLAGS+= -Cpanic=abort
-endif
-
ifeq ($(UNAME),Darwin)
# macOS does not have the `tac` command, but `tail -r` does the same thing
TAC := tail -r
-include ../tools.mk
all:
- $(RUSTC) -o $(TMPDIR)/input.expanded.rs -Z unstable-options \
- --pretty=expanded input.rs
+ $(RUSTC) -o $(TMPDIR)/input.expanded.rs -Zunpretty=expanded input.rs
-include ../tools.mk
all:
- $(RUSTC) -o $(TMPDIR)/input.out --pretty=normal -Z unstable-options input.rs
+ $(RUSTC) -o $(TMPDIR)/input.out -Zunpretty=normal input.rs
diff -u $(TMPDIR)/input.out input.pp
all:
$(RUSTDOC) --output-format=json x.html 2>&1 | diff - output-format-json.stderr
- $(RUSTC) --force-warns dead_code x.rs 2>&1 | diff - force-warns.stderr
+ $(RUSTC) --force-warn dead_code x.rs 2>&1 | diff - force-warn.stderr
--- /dev/null
+error: the `-Z unstable-options` flag must also be passed to enable the flag `--force-warn=lints`
+
+++ /dev/null
-error: the `-Z unstable-options` flag must also be passed to enable the flag `--force-warns=lints`
-
--- /dev/null
+// This test ensures that the default settings are correctly applied.
+//
+// The "settings" crate uses "ayu" as default setting, which is what we will
+// check.
+goto: file://|DOC_PATH|/settings/index.html
+// Wait a bit to be sure the default theme is applied.
+wait-for: 1000
+assert-css: ("body", {"background-color": "rgb(15, 20, 25)"})
// This test checks that the font weight is correctly applied.
assert-css: ("//*[@class='docblock type-decl']//a[text()='Alias']", {"font-weight": "400"})
assert-css: ("//*[@class='structfield small-section-header']//a[text()='Alias']", {"font-weight": "400"})
-assert-css: ("#method\.a_method > code", {"font-weight": "600"})
-assert-css: ("#associatedtype\.X > code", {"font-weight": "600"})
-assert-css: ("#associatedconstant\.Y > code", {"font-weight": "600"})
+assert-css: ("#method\.a_method > .code-header", {"font-weight": "600"})
+assert-css: ("#associatedtype\.X > .code-header", {"font-weight": "600"})
+assert-css: ("#associatedconstant\.Y > .code-header", {"font-weight": "600"})
goto: file://|DOC_PATH|/test_docs/type.SomeType.html
assert-css: (".top-doc .docblock p", {"font-weight": "400"}, ALL)
assert: ("#implementors-list > .impl:nth-child(1) > a.anchor")
assert-attribute: ("#implementors-list > .impl:nth-child(1)", {"id": "impl-Whatever"})
assert-attribute: ("#implementors-list > .impl:nth-child(1) > a.anchor", {"href": "#impl-Whatever"})
-assert: "#implementors-list > .impl:nth-child(1) > code.in-band"
+assert: "#implementors-list > .impl:nth-child(1) > .code-header.in-band"
assert: ("#implementors-list > .impl:nth-child(2) > a.anchor")
assert-attribute: ("#implementors-list > .impl:nth-child(2)", {"id": "impl-Whatever-1"})
assert-attribute: ("#implementors-list > .impl:nth-child(2) > a.anchor", {"href": "#impl-Whatever-1"})
-assert: "#implementors-list > .impl:nth-child(2) > code.in-band"
+assert: "#implementors-list > .impl:nth-child(2) > .code-header.in-band"
--- /dev/null
+// This test ensures that <table> elements aren't display in items summary.
+goto: file://|DOC_PATH|/lib2/summary_table/index.html
+// We check that we picked the right item first.
+assert-text: (".item-table .item-left", "Foo")
+// Then we check that its summary is empty.
+assert-text: (".item-table .item-right", "")
--- /dev/null
+// This test checks that the correct font is used on module items (in index.html pages).
+goto: file://|DOC_PATH|/test_docs/index.html
+assert-css: (".item-table .module-item a", {"font-family": '"Fira Sans", Arial, sans-serif'}, ALL)
+assert-css: (".item-table .docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'}, ALL)
+++ /dev/null
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "implementors"
-version = "0.1.0"
-
-[[package]]
-name = "lib2"
-version = "0.1.0"
-dependencies = [
- "implementors",
-]
-
-[[package]]
-name = "test_docs"
-version = "0.1.0"
+++ /dev/null
-[workspace]
-members = [
- "test_docs",
- "lib2",
- "implementors",
-]
+++ /dev/null
-[package]
-name = "implementors"
-version = "0.1.0"
-edition = "2018"
-
-[lib]
-path = "lib.rs"
+++ /dev/null
-pub trait Whatever {
- fn method() {}
-}
-
-pub struct Struct;
-
-impl Whatever for Struct {}
--- /dev/null
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "implementors"
+version = "0.1.0"
+
+[[package]]
+name = "lib2"
+version = "0.1.0"
+dependencies = [
+ "implementors",
+]
path = "lib.rs"
[dependencies]
-implementors = { path = "../implementors" }
+implementors = { path = "./implementors" }
--- /dev/null
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "implementors"
+version = "0.1.0"
--- /dev/null
+[package]
+name = "implementors"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+path = "lib.rs"
--- /dev/null
+pub trait Whatever {
+ fn method() {}
+}
+
+pub struct Struct;
+
+impl Whatever for Struct {}
/// I wanna sqdkfnqds f dsqf qds f dsqf dsq f dsq f qds f qds f qds f dsqq f dsf sqdf dsq fds f dsq f dq f ds fq sd fqds f dsq f sqd fsq df sd fdsqfqsd fdsq f dsq f dsqfd s dfq
pub struct Foo;
}
+
+pub mod summary_table {
+ /// | header 1 | header 2 |
+ /// | -------- | -------- |
+ /// | content | content |
+ pub struct Foo;
+}
--- /dev/null
+[build]
+rustdocflags = ["--default-theme", "ayu"]
--- /dev/null
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "settings"
+version = "0.1.0"
--- /dev/null
+[package]
+name = "settings"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+path = "lib.rs"
--- /dev/null
+pub fn foo() {}
--- /dev/null
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "test_docs"
+version = "0.1.0"
pub struct Bar;
impl Foo for Bar {
- // @has assoc_consts/struct.Bar.html '//code' 'impl Foo for Bar'
+ // @has assoc_consts/struct.Bar.html '//h3[@class="code-header in-band"]' 'impl Foo for Bar'
// @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
const FOO: usize = 12;
// @has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool'
const QUX_DEFAULT2: u32 = 3;
}
-// @has assoc_consts/struct.Bar.html '//code' 'impl Qux for Bar'
+// @has assoc_consts/struct.Bar.html '//h3[@class="code-header in-band"]' 'impl Qux for Bar'
impl Qux for Bar {
// @has - '//*[@id="associatedconstant.QUX0"]' 'const QUX0: u8'
// @has - '//*[@class="docblock"]' "Docs for QUX0 in trait."
// @has assoc_types/trait.Index.html
pub trait Index<I: ?Sized> {
- // @has - '//*[@id="associatedtype.Output"]//code' 'type Output: ?Sized'
+ // @has - '//*[@id="associatedtype.Output"]//h4[@class="code-header"]' 'type Output: ?Sized'
type Output: ?Sized;
- // @has - '//*[@id="tymethod.index"]//code' \
+ // @has - '//*[@id="tymethod.index"]//h4[@class="code-header"]' \
// "fn index<'a>(&'a self, index: I) -> &'a Self::Output"
- // @has - '//*[@id="tymethod.index"]//code//a[@href="trait.Index.html#associatedtype.Output"]' \
+ // @has - '//*[@id="tymethod.index"]//h4[@class="code-header"]//a[@href="trait.Index.html#associatedtype.Output"]' \
// "Output"
fn index<'a>(&'a self, index: I) -> &'a Self::Output;
}
}
// @has async_fn/struct.Foo.html
-// @matches - '//code' 'pub async fn f\(\)$'
-// @matches - '//code' 'pub async unsafe fn g\(\)$'
-// @matches - '//code' 'pub async fn mut_self\(self, first: usize\)$'
+// @matches - '//h4[@class="code-header"]' 'pub async fn f\(\)$'
+// @matches - '//h4[@class="code-header"]' 'pub async unsafe fn g\(\)$'
+// @matches - '//h4[@class="code-header"]' 'pub async fn mut_self\(self, first: usize\)$'
pub struct Foo;
impl Foo {
#![crate_name = "foo"]
-// @has foo/struct.S.html '//div[@id="impl-Into%3CU%3E"]//code' 'impl<T, U> Into<U> for T'
+// @has foo/struct.S.html '//div[@id="impl-Into%3CU%3E"]//h3[@class="code-header in-band"]' 'impl<T, U> Into<U> for T'
pub struct S2 {}
mod m {
pub struct S {}
pub struct Foo;
impl Foo {
- // @has 'foo/struct.Foo.html' '//div[@id="method.gated"]/code' 'pub fn gated() -> u32'
+ // @has 'foo/struct.Foo.html' '//div[@id="method.gated"]/h4[@class="code-header"]' 'pub fn gated() -> u32'
// @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
pub const fn gated() -> u32 { 42 }
- // @has 'foo/struct.Foo.html' '//div[@id="method.gated_unsafe"]/code' 'pub unsafe fn gated_unsafe() -> u32'
+ // @has 'foo/struct.Foo.html' '//div[@id="method.gated_unsafe"]/h4[@class="code-header"]' 'pub unsafe fn gated_unsafe() -> u32'
// @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
pub const unsafe fn gated_unsafe() -> u32 { 42 }
- // @has 'foo/struct.Foo.html' '//div[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32'
+ // @has 'foo/struct.Foo.html' '//div[@id="method.stable_impl"]/h4[@class="code-header"]' 'pub const fn stable_impl() -> u32'
// @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.2.0")]
inner: T,
}
-// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//div/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
+// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//div/h3[@class="code-header in-band"]' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
impl Add for Simd<u8, 16> {
type Output = Self;
// @has foo/trait.Trait.html '//pre[@class="rust trait"]' \
// 'pub trait Trait<const N: usize>'
-// @has - '//*[@id="impl-Trait%3C1_usize%3E-for-u8"]//code' 'impl Trait<1_usize> for u8'
-// @has - '//*[@id="impl-Trait%3C2_usize%3E-for-u8"]//code' 'impl Trait<2_usize> for u8'
-// @has - '//*[@id="impl-Trait%3C{1%20+%202}%3E-for-u8"]//code' 'impl Trait<{1 + 2}> for u8'
-// @has - '//*[@id="impl-Trait%3CN%3E-for-%5Bu8%3B%20N%5D"]//code' \
+// @has - '//*[@id="impl-Trait%3C1_usize%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<1_usize> for u8'
+// @has - '//*[@id="impl-Trait%3C2_usize%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<2_usize> for u8'
+// @has - '//*[@id="impl-Trait%3C{1%20+%202}%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<{1 + 2}> for u8'
+// @has - '//*[@id="impl-Trait%3CN%3E-for-%5Bu8%3B%20N%5D"]//h3[@class="code-header in-band"]' \
// 'impl<const N: usize> Trait<N> for [u8; N]'
pub trait Trait<const N: usize> {}
impl Trait<1> for u8 {}
// @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)'
pub struct Bar<T, const N: usize>([T; N]);
-// @has foo/struct.Foo.html '//div[@id="impl"]/code' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
+// @has foo/struct.Foo.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
impl<const M: usize> Foo<M> where u8: Trait<M> {
// @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize'
pub const FOO_ASSOC: usize = M + 13;
}
}
-// @has foo/struct.Bar.html '//div[@id="impl"]/code' 'impl<const M: usize> Bar<u8, M>'
+// @has foo/struct.Bar.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Bar<u8, M>'
impl<const M: usize> Bar<u8, M> {
// @has - '//*[@id="method.hey"]' \
// 'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>'
}
// @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>'
-// @has foo/struct.VSet.html '//div[@id="impl-Send"]/code' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
-// @has foo/struct.VSet.html '//div[@id="impl-Sync"]/code' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//div[@id="impl-Send"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//div[@id="impl-Sync"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
pub struct VSet<T, const ORDER: Order> {
inner: Vec<T>,
}
-// @has foo/struct.VSet.html '//div[@id="impl"]/code' 'impl<T> VSet<T, {Order::Sorted}>'
+// @has foo/struct.VSet.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, {Order::Sorted}>'
impl <T> VSet<T, {Order::Sorted}> {
pub fn new() -> Self {
Self { inner: Vec::new() }
}
}
-// @has foo/struct.VSet.html '//div[@id="impl-1"]/code' 'impl<T> VSet<T, {Order::Unsorted}>'
+// @has foo/struct.VSet.html '//div[@id="impl-1"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, {Order::Unsorted}>'
impl <T> VSet<T, {Order::Unsorted}> {
pub fn new() -> Self {
Self { inner: Vec::new() }
pub struct Escape<const S: &'static str>;
-// @has foo/struct.Escape.html '//div[@id="impl"]/code' 'impl Escape<{ r#"<script>alert("Escape");</script>"# }>'
+// @has foo/struct.Escape.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl Escape<{ r#"<script>alert("Escape");</script>"# }>'
impl Escape<{ r#"<script>alert("Escape");</script>"# }> {
pub fn f() {}
}
unsafe impl<T: Default> Send for Hasher<T> {}
// @has foo/struct.Foo.html
-// @has - '//code' 'impl Send for Foo'
+// @has - '//h3[@class="code-header in-band"]' 'impl Send for Foo'
pub struct Foo {
hasher: Hasher<[u8; 3]>,
}
pub struct Foo;
impl Foo {
- // @has const/struct.Foo.html '//*[@id="method.new"]//code' 'const unsafe fn new'
+ // @has const/struct.Foo.html '//*[@id="method.new"]//h4[@class="code-header"]' 'const unsafe fn new'
pub const unsafe fn new() -> Foo {
Foo
}
--- /dev/null
+// compile-flags: --default-theme ayu
+
+// @has default_theme/index.html
+// @has - '//script[@id="default-settings"]/@data-theme' 'ayu'
+// @has - '//script[@id="default-settings"]/@data-use_system_theme' 'false'
+
+pub fn whatever() {}
// @has issue_33054/impls/struct.Foo.html
-// @has - '//code' 'impl Foo'
-// @has - '//code' 'impl Bar for Foo'
+// @has - '//h3[@class="code-header in-band"]' 'impl Foo'
+// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo'
// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
// @count - '//*[@id="main"]/details/summary/*[@class="impl has-srclink"]' 1
// @has issue_33054/impls/bar/trait.Bar.html
-// @has - '//code' 'impl Bar for Foo'
+// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo'
// @count - '//*[@class="struct"]' 1
pub mod impls;
extern crate extern_impl_trait;
-// @has 'foo/struct.X.html' '//code' "impl Foo<Associated = ()> + 'a"
+// @has 'foo/struct.X.html' '//h4[@class="code-header"]' "impl Foo<Associated = ()> + 'a"
pub use extern_impl_trait::X;
-// @has 'foo/struct.Y.html' '//code' "impl ?Sized + Foo<Associated = ()> + 'a"
+// @has 'foo/struct.Y.html' '//h4[@class="code-header"]' "impl ?Sized + Foo<Associated = ()> + 'a"
pub use extern_impl_trait::Y;
pub struct Foo;
impl Foo {
- // @has - '//code' 'fn rust0()'
+ // @has - '//h4[@class="code-header"]' 'fn rust0()'
pub fn rust0() {}
- // @has - '//code' 'fn rust1()'
+ // @has - '//h4[@class="code-header"]' 'fn rust1()'
pub extern "Rust" fn rust1() {}
- // @has - '//code' 'extern "C" fn c0()'
+ // @has - '//h4[@class="code-header"]' 'extern "C" fn c0()'
pub extern fn c0() {}
- // @has - '//code' 'extern "C" fn c1()'
+ // @has - '//h4[@class="code-header"]' 'extern "C" fn c1()'
pub extern "C" fn c1() {}
- // @has - '//code' 'extern "system" fn system0()'
+ // @has - '//h4[@class="code-header"]' 'extern "system" fn system0()'
pub extern "system" fn system0() {}
}
// @has foo/trait.Bar.html
pub trait Bar {}
-// @has - '//code' 'impl Bar for fn()'
+// @has - '//h3[@class="code-header in-band"]' 'impl Bar for fn()'
impl Bar for fn() {}
-// @has - '//code' 'impl Bar for extern "C" fn()'
+// @has - '//h3[@class="code-header in-band"]' 'impl Bar for extern "C" fn()'
impl Bar for extern fn() {}
-// @has - '//code' 'impl Bar for extern "system" fn()'
+// @has - '//h3[@class="code-header in-band"]' 'impl Bar for extern "system" fn()'
impl Bar for extern "system" fn() {}
extern crate rustdoc_extern_method as foo;
// @has extern_method/trait.Foo.html //pre "pub trait Foo"
-// @has - '//*[@id="tymethod.foo"]//code' 'extern "rust-call" fn foo'
-// @has - '//*[@id="method.foo_"]//code' 'extern "rust-call" fn foo_'
+// @has - '//*[@id="tymethod.foo"]//h4[@class="code-header"]' 'extern "rust-call" fn foo'
+// @has - '//*[@id="method.foo_"]//h4[@class="code-header"]' 'extern "rust-call" fn foo_'
pub use foo::Foo;
// @has extern_method/trait.Bar.html //pre "pub trait Bar"
pub trait Bar {
- // @has - '//*[@id="tymethod.bar"]//code' 'extern "rust-call" fn bar'
+ // @has - '//*[@id="tymethod.bar"]//h4[@class="code-header"]' 'extern "rust-call" fn bar'
extern "rust-call" fn bar(&self, _: ());
- // @has - '//*[@id="method.bar_"]//code' 'extern "rust-call" fn bar_'
+ // @has - '//*[@id="method.bar_"]//h4[@class="code-header"]' 'extern "rust-call" fn bar_'
extern "rust-call" fn bar_(&self, _: ()) { }
}
use std::fmt;
-// @!has foo/struct.Bar.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @!has foo/struct.Bar.html '//div[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
pub struct Bar;
-// @has foo/struct.Foo.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @has foo/struct.Foo.html '//div[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
pub struct Foo;
// @has foo/struct.Foo.html '//div[@class="sidebar-links"]/a[@href="#impl-ToString"]' 'ToString'
// @has - '//span[@id="structfield.some_trait"]' "some_trait: &'a dyn for<'b> Trait<'b>"
impl<'a> Foo<'a> {
- // @has - '//code' "pub fn bar<T>() where T: Trait<'a>,"
+ // @has - '//h4[@class="code-header"]' "pub fn bar<T>() where T: Trait<'a>,"
pub fn bar<T>()
where
T: Trait<'a>,
// @has foo/trait.B.html
pub trait B<'x> {}
-// @has - '//code[@class="in-band"]' "impl<'a> B<'a> for dyn for<'b> Trait<'b>"
+// @has - '//h3[@class="code-header in-band"]' "impl<'a> B<'a> for dyn for<'b> Trait<'b>"
impl<'a> B<'a> for dyn for<'b> Trait<'b> {}
// @has foo/struct.Bar.html
pub struct Bar<T> { field: T }
-// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
// "impl Foo for Bar<u8>"
impl Foo for Bar<u8> {}
-// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
// "impl Foo for Bar<u16>"
impl Foo for Bar<u16> {}
-// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
// "impl<'a> Foo for &'a Bar<u8>"
impl<'a> Foo for &'a Bar<u8> {}
pub enum Baz {}
}
-// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
// "impl Foo for foo::mod1::Baz"
impl Foo for mod1::Baz {}
-// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
// "impl<'a> Foo for &'a foo::mod2::Baz"
impl<'a> Foo for &'a mod2::Baz {}
pub struct Foo<T> { field: T }
-// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//code' \
+// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
-// @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//code' \
+// @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
// "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync {}
pub use impl_trait_aux::async_fn;
// @has impl_trait/struct.Foo.html
-// @has - '//*[@id="method.method"]//code' "pub fn method<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)"
-// @!has - '//*[@id="method.method"]//code' 'where'
+// @has - '//*[@id="method.method"]//h4[@class="code-header"]' "pub fn method<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)"
+// @!has - '//*[@id="method.method"]//h4[@class="code-header"]' 'where'
pub use impl_trait_aux::Foo;
// @has impl_trait/struct.Bar.html
extern crate rustdoc_nonreachable_impls;
// @has issue_31948_1/struct.Wobble.html
-// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
-// @!has - '//*[@class="impl"]//code' 'Bar for'
-// @!has - '//*[@class="impl"]//code' 'Qux for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Woof for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Bar for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Qux for'
pub use rustdoc_nonreachable_impls::hidden::Wobble;
// @has issue_31948_1/trait.Bark.html
-// @has - '//code' 'for Foo'
-// @has - '//code' 'for Wobble'
-// @!has - '//code' 'for Wibble'
+// @has - '//h3[@class="code-header in-band"]' 'for Foo'
+// @has - '//h3[@class="code-header in-band"]' 'for Wobble'
+// @!has - '//h3[@class="code-header in-band"]' 'for Wibble'
pub use rustdoc_nonreachable_impls::Bark;
// @has issue_31948_1/trait.Woof.html
-// @has - '//code' 'for Foo'
-// @has - '//code' 'for Wobble'
-// @!has - '//code' 'for Wibble'
+// @has - '//h3[@class="code-header in-band"]' 'for Foo'
+// @has - '//h3[@class="code-header in-band"]' 'for Wobble'
+// @!has - '//h3[@class="code-header in-band"]' 'for Wibble'
pub use rustdoc_nonreachable_impls::Woof;
// @!has issue_31948_1/trait.Bar.html
extern crate rustdoc_nonreachable_impls;
// @has issue_31948_2/struct.Wobble.html
-// @has - '//*[@class="impl has-srclink"]//code' 'Qux for'
-// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
-// @!has - '//*[@class="impl"]//code' 'Bar for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Qux for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Woof for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Bar for'
pub use rustdoc_nonreachable_impls::hidden::Wobble;
// @has issue_31948_2/trait.Qux.html
-// @has - '//code' 'for Foo'
-// @has - '//code' 'for Wobble'
+// @has - '//h3[@class="code-header in-band"]' 'for Foo'
+// @has - '//h3[@class="code-header in-band"]' 'for Wobble'
pub use rustdoc_nonreachable_impls::hidden::Qux;
// @!has issue_31948_2/trait.Bar.html
extern crate rustdoc_nonreachable_impls;
// @has issue_31948/struct.Foo.html
-// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
-// @!has - '//*[@class="impl has-srclink"]//code' 'Bar for'
-// @!has - '//*[@class="impl"]//code' 'Qux for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Woof for'
+// @!has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bar for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Qux for'
pub use rustdoc_nonreachable_impls::Foo;
// @has issue_31948/trait.Bark.html
-// @has - '//code' 'for Foo'
-// @!has - '//code' 'for Wibble'
-// @!has - '//code' 'for Wobble'
+// @has - '//h3[@class="code-header in-band"]' 'for Foo'
+// @!has - '//h3[@class="code-header in-band"]' 'for Wibble'
+// @!has - '//h3[@class="code-header in-band"]' 'for Wobble'
pub use rustdoc_nonreachable_impls::Bark;
// @has issue_31948/trait.Woof.html
-// @has - '//code' 'for Foo'
-// @!has - '//code' 'for Wibble'
-// @!has - '//code' 'for Wobble'
+// @has - '//h3[@class="code-header in-band"]' 'for Foo'
+// @!has - '//h3[@class="code-header in-band"]' 'for Wibble'
+// @!has - '//h3[@class="code-header in-band"]' 'for Wobble'
pub use rustdoc_nonreachable_impls::Woof;
// @!has issue_31948/trait.Bar.html
extern crate rustdoc_trait_object_impl;
// @has issue_32881/trait.Bar.html
-// @has - '//code' "impl<'a> dyn Bar"
-// @has - '//code' "impl<'a> Debug for dyn Bar"
+// @has - '//h3[@class="code-header in-band"]' "impl<'a> dyn Bar"
+// @has - '//h3[@class="code-header in-band"]' "impl<'a> Debug for dyn Bar"
pub use rustdoc_trait_object_impl::Bar;
extern crate bar;
// @has issue_33113/trait.Bar.html
-// @has - '//code' "for &'a char"
-// @has - '//code' "for Foo"
+// @has - '//h3[@class="code-header in-band"]' "for &'a char"
+// @has - '//h3[@class="code-header in-band"]' "for Foo"
pub use bar::Bar;
extern crate inner;
// @has trait_vis/struct.SomeStruct.html
-// @has - '//code' 'impl Clone for SomeStruct'
+// @has - '//h3[@class="code-header in-band"]' 'impl Clone for SomeStruct'
pub use inner::SomeStruct;
}
// @has trait_vis/struct.SomeStruct.html
-// @has - '//code' 'impl ThisTrait for SomeStruct'
-// @!has - '//code' 'impl PrivateTrait for SomeStruct'
+// @has - '//h3[@class="code-header in-band"]' 'impl ThisTrait for SomeStruct'
+// @!has - '//h3[@class="code-header in-band"]' 'impl PrivateTrait for SomeStruct'
pub use asdf::SomeStruct;
}
// @has issue_19190/struct.Bar.html
-// @has - '//*[@id="method.foo"]//code' 'fn foo(&self)'
+// @has - '//*[@id="method.foo"]//h4[@class="code-header"]' 'fn foo(&self)'
// @has - '//*[@id="method.foo"]' 'fn foo(&self)'
-// @!has - '//*[@id="method.static_foo"]//code' 'fn static_foo()'
+// @!has - '//*[@id="method.static_foo"]//h4[@class="code-header"]' 'fn static_foo()'
// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()'
}
impl Foo<u8> {
- // @has - '//*[@id="method.pass"]//code' 'fn pass()'
+ // @has - '//*[@id="method.pass"]//h4[@class="code-header"]' 'fn pass()'
pub fn pass() {}
}
impl Foo<u16> {
- // @has - '//*[@id="method.pass-1"]//code' 'fn pass() -> usize'
+ // @has - '//*[@id="method.pass-1"]//h4[@class="code-header"]' 'fn pass() -> usize'
pub fn pass() -> usize { 42 }
}
impl Foo<u32> {
- // @has - '//*[@id="method.pass-2"]//code' 'fn pass() -> isize'
+ // @has - '//*[@id="method.pass-2"]//h4[@class="code-header"]' 'fn pass() -> isize'
pub fn pass() -> isize { 42 }
}
impl<T> Bar for Foo<T> {
- // @has - '//*[@id="associatedtype.Item"]//code' 'type Item = T'
+ // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' 'type Item = T'
type Item=T;
- // @has - '//*[@id="method.quux"]//code' 'fn quux(self)'
+ // @has - '//*[@id="method.quux"]//h4[@class="code-header"]' 'fn quux(self)'
fn quux(self) {}
}
impl<'a, T> Bar for &'a Foo<T> {
- // @has - '//*[@id="associatedtype.Item-1"]//code' "type Item = &'a T"
+ // @has - '//*[@id="associatedtype.Item-1"]//h4[@class="code-header"]' "type Item = &'a T"
type Item=&'a T;
- // @has - '//*[@id="method.quux-1"]//code' 'fn quux(self)'
+ // @has - '//*[@id="method.quux-1"]//h4[@class="code-header"]' 'fn quux(self)'
fn quux(self) {}
}
impl<'a, T> Bar for &'a mut Foo<T> {
- // @has - '//*[@id="associatedtype.Item-2"]//code' "type Item = &'a mut T"
+ // @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item = &'a mut T"
type Item=&'a mut T;
- // @has - '//*[@id="method.quux-2"]//code' 'fn quux(self)'
+ // @has - '//*[@id="method.quux-2"]//h4[@class="code-header"]' 'fn quux(self)'
fn quux(self) {}
}
// @matches issue_27362/fn.foo.html '//pre' "pub const fn foo()"
// @matches issue_27362/fn.bar.html '//pre' "pub const unsafe fn bar()"
-// @matches issue_27362/struct.Foo.html '//code' "const unsafe fn baz()"
+// @matches issue_27362/struct.Foo.html '//h4[@class="code-header"]' "const unsafe fn baz()"
fn my_string(&self) -> String;
}
-// @has - "//div[@id='implementors-list']//div[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug"
+// @has - "//div[@id='implementors-list']//div[@id='impl-MyTrait']//h3[@class='code-header in-band']" "impl<T> MyTrait for T where T: Debug"
impl<T> MyTrait for T where T: fmt::Debug {
fn my_string(&self) -> String {
format!("{:?}", self)
pub struct Baz;
-// @has foo/trait.Foo.html '//code' 'impl Foo<i32> for Bar'
+// @has foo/trait.Foo.html '//h3[@class="code-header in-band"]' 'impl Foo<i32> for Bar'
impl Foo<i32> for Bar {}
-// @has foo/trait.Foo.html '//code' 'impl<T> Foo<T> for Baz'
+// @has foo/trait.Foo.html '//h3[@class="code-header in-band"]' 'impl<T> Foo<T> for Baz'
impl<T> Foo<T> for Baz {}
}
// @has issue_35169_2/struct.Bar.html
-// @has - '//*[@id="method.by_ref"]//code' 'fn by_ref(&self)'
+// @has - '//*[@id="method.by_ref"]//h4[@class="code-header"]' 'fn by_ref(&self)'
// @has - '//*[@id="method.by_ref"]' 'fn by_ref(&self)'
-// @has - '//*[@id="method.by_explicit_ref"]//code' 'fn by_explicit_ref(self: &Foo)'
+// @has - '//*[@id="method.by_explicit_ref"]//h4[@class="code-header"]' 'fn by_explicit_ref(self: &Foo)'
// @has - '//*[@id="method.by_explicit_ref"]' 'fn by_explicit_ref(self: &Foo)'
-// @has - '//*[@id="method.by_mut_ref"]//code' 'fn by_mut_ref(&mut self)'
+// @has - '//*[@id="method.by_mut_ref"]//h4[@class="code-header"]' 'fn by_mut_ref(&mut self)'
// @has - '//*[@id="method.by_mut_ref"]' 'fn by_mut_ref(&mut self)'
-// @has - '//*[@id="method.by_explicit_mut_ref"]//code' 'fn by_explicit_mut_ref(self: &mut Foo)'
+// @has - '//*[@id="method.by_explicit_mut_ref"]//h4[@class="code-header"]' 'fn by_explicit_mut_ref(self: &mut Foo)'
// @has - '//*[@id="method.by_explicit_mut_ref"]' 'fn by_explicit_mut_ref(self: &mut Foo)'
-// @!has - '//*[@id="method.by_explicit_box"]//code' 'fn by_explicit_box(self: Box<Foo>)'
+// @!has - '//*[@id="method.by_explicit_box"]//h4[@class="code-header"]' 'fn by_explicit_box(self: Box<Foo>)'
// @!has - '//*[@id="method.by_explicit_box"]' 'fn by_explicit_box(self: Box<Foo>)'
-// @!has - '//*[@id="method.by_explicit_self_box"]//code' 'fn by_explicit_self_box(self: Box<Self>)'
+// @!has - '//*[@id="method.by_explicit_self_box"]//h4[@class="code-header"]' 'fn by_explicit_self_box(self: Box<Self>)'
// @!has - '//*[@id="method.by_explicit_self_box"]' 'fn by_explicit_self_box(self: Box<Self>)'
-// @!has - '//*[@id="method.static_foo"]//code' 'fn static_foo()'
+// @!has - '//*[@id="method.static_foo"]//h4[@class="code-header"]' 'fn static_foo()'
// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()'
}
// @has issue_35169/struct.Bar.html
-// @has - '//*[@id="method.by_ref"]//code' 'fn by_ref(&self)'
+// @has - '//*[@id="method.by_ref"]//h4[@class="code-header"]' 'fn by_ref(&self)'
// @has - '//*[@id="method.by_ref"]' 'fn by_ref(&self)'
-// @has - '//*[@id="method.by_explicit_ref"]//code' 'fn by_explicit_ref(self: &Foo)'
+// @has - '//*[@id="method.by_explicit_ref"]//h4[@class="code-header"]' 'fn by_explicit_ref(self: &Foo)'
// @has - '//*[@id="method.by_explicit_ref"]' 'fn by_explicit_ref(self: &Foo)'
-// @!has - '//*[@id="method.by_mut_ref"]//code' 'fn by_mut_ref(&mut self)'
+// @!has - '//*[@id="method.by_mut_ref"]//h4[@class="code-header"]' 'fn by_mut_ref(&mut self)'
// @!has - '//*[@id="method.by_mut_ref"]' 'fn by_mut_ref(&mut self)'
-// @!has - '//*[@id="method.by_explicit_mut_ref"]//code' 'fn by_explicit_mut_ref(self: &mut Foo)'
+// @!has - '//*[@id="method.by_explicit_mut_ref"]//h4[@class="code-header"]' 'fn by_explicit_mut_ref(self: &mut Foo)'
// @!has - '//*[@id="method.by_explicit_mut_ref"]' 'fn by_explicit_mut_ref(self: &mut Foo)'
-// @!has - '//*[@id="method.by_explicit_box"]//code' 'fn by_explicit_box(self: Box<Foo>)'
+// @!has - '//*[@id="method.by_explicit_box"]//h4[@class="code-header"]' 'fn by_explicit_box(self: Box<Foo>)'
// @!has - '//*[@id="method.by_explicit_box"]' 'fn by_explicit_box(self: Box<Foo>)'
-// @!has - '//*[@id="method.by_explicit_self_box"]//code' 'fn by_explicit_self_box(self: Box<Self>)'
+// @!has - '//*[@id="method.by_explicit_self_box"]//h4[@class="code-header"]' 'fn by_explicit_self_box(self: Box<Self>)'
// @!has - '//*[@id="method.by_explicit_self_box"]' 'fn by_explicit_self_box(self: Box<Self>)'
-// @!has - '//*[@id="method.static_foo"]//code' 'fn static_foo()'
+// @!has - '//*[@id="method.static_foo"]//h4[@class="code-header"]' 'fn static_foo()'
// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()'
extern crate issue_46727;
// @has issue_46727/trait.Foo.html
-// @has - '//code' 'impl<T> Foo for Bar<[T; 3]>'
+// @has - '//h3[@class="code-header in-band"]' 'impl<T> Foo for Bar<[T; 3]>'
pub use issue_46727::{Foo, Bar};
}
// @has issue_50159/struct.Switch.html
-// @has - '//code' 'impl<B> Send for Switch<B> where <B as Signal>::Item: Send'
-// @has - '//code' 'impl<B> Sync for Switch<B> where <B as Signal>::Item: Sync'
+// @has - '//h3[@class="code-header in-band"]' 'impl<B> Send for Switch<B> where <B as Signal>::Item: Send'
+// @has - '//h3[@class="code-header in-band"]' 'impl<B> Sync for Switch<B> where <B as Signal>::Item: Sync'
// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
pub struct Switch<B: Signal> {
}
// @has issue_51236/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<T> Send for Owned<T> where <T as Owned<'static>>::Reader: Send"
pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
// @has foo/trait.MyTrait.html
// @!has - 'MyStruct'
-// @count - '//*[code="impl<T> MyTrait for T"]' 1
+// @count - '//*[h3="impl<T> MyTrait for T"]' 1
pub trait MyTrait {}
impl<T> MyTrait for T {}
// @has issue_54705/struct.ScopeFutureContents.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<'scope, S> Send for ScopeFutureContents<'scope, S> where S: Sync"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S> where S: Sync"
pub struct ScopeFutureContents<'scope, S>
where S: ScopeHandle<'scope>,
#![feature(negative_impls)]
// @has issue_55321/struct.A.html
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl !Send for A"
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl !Sync for A"
pub struct A();
impl !Sync for A {}
// @has issue_55321/struct.B.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<T> !Send for B<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<T> !Sync for B<T>"
pub struct B<T: ?Sized>(A, Box<T>);
}
// @has issue_56822/struct.Parser.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<'a> Send for Parser<'a>"
pub struct Parser<'a> {
field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output
{}
// @has issue_60726/struct.IntoIter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<T> !Send for IntoIter<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<T> !Sync for IntoIter<T>"
pub struct IntoIter<T>{
hello:DynTrait<FooInterface<T>>,
extern crate real_gimli;
// issue #74672
-// @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//code' 'impl Deref for EndianSlice'
+// @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//h3[@class="code-header in-band"]' 'impl Deref for EndianSlice'
pub use realcore::Deref;
-// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//code' 'impl Join for Foo'
+// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//h3[@class="code-header in-band"]' 'impl Join for Foo'
pub use realcore::Join;
pub struct Struct1 {}
// @has issue_80233_normalize_auto_trait/struct.Question.html
-// @has - '//code' 'impl<T> Send for Question<T>'
+// @has - '//h3[@class="code-header in-band"]' 'impl<T> Send for Question<T>'
pub struct Question<T: Trait1> {
pub ins: <<Vec<T> as Trait3>::Type3 as Trait2>::Type2,
}
use std::convert::AsRef;
pub struct Local;
-// @has issue_82465_asref_for_and_of_local/struct.Local.html '//code' 'impl AsRef<str> for Local'
+// @has issue_82465_asref_for_and_of_local/struct.Local.html '//h3[@class="code-header in-band"]' 'impl AsRef<str> for Local'
impl AsRef<str> for Local {
fn as_ref(&self) -> &str {
todo!()
}
}
-// @has - '//code' 'impl AsRef<Local> for str'
+// @has - '//h3[@class="code-header in-band"]' 'impl AsRef<Local> for str'
impl AsRef<Local> for str {
fn as_ref(&self) -> &Local {
todo!()
// @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo<B>"
pub struct Bravo<B>(B);
-// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//code' \
+// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl !Send for Alpha"
impl !Send for Alpha {}
-// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//code' "\
+// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' "\
// impl<B> !Send for Bravo<B>"
impl<B> !Send for Bravo<B> {}
include!("primitive/primitive-generic-impl.rs");
-// @has foo/primitive.i32.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @has foo/primitive.i32.html '//div[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
pub struct A;
pub struct B;
-// @has recursive_deref/struct.A.html '//code' 'impl Deref for A'
+// @has recursive_deref/struct.A.html '//h3[@class="code-header in-band"]' 'impl Deref for A'
impl Deref for A {
type Target = B;
}
}
-// @has recursive_deref/struct.B.html '//code' 'impl Deref for B'
+// @has recursive_deref/struct.B.html '//h3[@class="code-header in-band"]' 'impl Deref for B'
impl Deref for B {
type Target = A;
// @has - '//*[@class="sidebar-title"]/a[@href="#foreign-impls"]' 'Implementations on Foreign Types'
// @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types'
// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-u32"]' 'u32'
-// @has - '//div[@id="impl-Foo-for-u32"]//code' 'impl Foo for u32'
+// @has - '//div[@id="impl-Foo-for-u32"]//h3[@class="code-header in-band"]' 'impl Foo for u32'
// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str"
-// @has - '//div[@id="impl-Foo-for-%26%27a%20str"]//code' "impl<'a> Foo for &'a str"
+// @has - '//div[@id="impl-Foo-for-%26%27a%20str"]//h3[@class="code-header in-band"]' "impl<'a> Foo for &'a str"
pub trait Foo {}
impl Foo for u32 {}
pub struct Foo<T: ?Sized>(T);
// @has foo/struct.Unsized.html
-// @has - '//div[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
+// @has - '//div[@id="impl-Sized"]//h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
pub struct Unsized {
data: [u8],
}
#![crate_name = "foo"]
// @has foo/struct.Unsized.html
-// @has - '//div[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
+// @has - '//div[@id="impl-Sized"]/h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
// @!has - '//div[@id="impl-Sized"]//a[@class="srclink"]' '[src]'
-// @has - '//div[@id="impl-Sync"]/code' 'impl Sync for Unsized'
+// @has - '//div[@id="impl-Sync"]/h3[@class="code-header in-band"]' 'impl Sync for Unsized'
// @!has - '//div[@id="impl-Sync"]//a[@class="srclink"]' '[src]'
-// @has - '//div[@id="impl-Any"]/code' 'impl<T> Any for T'
+// @has - '//div[@id="impl-Any"]/h3[@class="code-header in-band"]' 'impl<T> Any for T'
// @has - '//div[@id="impl-Any"]//a[@class="srclink"]' '[src]'
pub struct Unsized {
data: [u8],
// @has basic/struct.Foo.html
-// @has - '//code' 'impl<T> Send for Foo<T> where T: Send'
-// @has - '//code' 'impl<T> Sync for Foo<T> where T: Sync'
+// @has - '//h3[@class="code-header in-band"]' 'impl<T> Send for Foo<T> where T: Send'
+// @has - '//h3[@class="code-header in-band"]' 'impl<T> Sync for Foo<T> where T: Sync'
// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0
// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
pub struct Foo<T> {
}
// @has complex/struct.NotOuter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \
// -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
pub auto trait Banana {}
// @has crate_local/struct.Peach.html
-// @has - '//code' 'impl Banana for Peach'
-// @has - '//code' 'impl Send for Peach'
-// @has - '//code' 'impl Sync for Peach'
+// @has - '//h3[@class="code-header in-band"]' 'impl Banana for Peach'
+// @has - '//h3[@class="code-header in-band"]' 'impl Send for Peach'
+// @has - '//h3[@class="code-header in-band"]' 'impl Sync for Peach'
pub struct Peach;
{}
// @has lifetimes/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<'c, K> Send for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<'c, K> Sync for Foo<'c, K> where K: Sync"
pub struct Foo<'c, K: 'c> {
inner_field: Inner<'c, K>,
// @has manual/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// 'impl<T> Sync for Foo<T> where T: Sync'
//
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// 'impl<T> Send for Foo<T>'
//
// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
}
// @has negative/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<T> !Send for Outer<T>"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<T> !Sync for Outer<T>"
pub struct Outer<T: Copy> {
inner_field: Inner<T>,
}
// @has nested/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// 'impl<T> Send for Foo<T> where T: Copy'
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// 'impl<T> Sync for Foo<T> where T: Sync'
pub struct Foo<T> {
inner_field: Inner<T>,
}
// @has no_redundancy/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<T> Send for Outer<T> where T: Copy + Send"
pub struct Outer<T> {
inner_field: Inner<T>,
struct VariableKind<I: Interner>(I::InternedType);
// @has overflow/struct.BoundVarsCollector.html
-// @has - '//code' "impl<'tcx> Send for BoundVarsCollector<'tcx>"
+// @has - '//h3[@class="code-header in-band"]' "impl<'tcx> Send for BoundVarsCollector<'tcx>"
pub struct BoundVarsCollector<'tcx> {
val: VariableKind<RustInterner<'tcx>>
}
}
// @has project/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<'c, K> Send for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<'c, K> Sync for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
// 'c: 'static,"
pub struct Foo<'c, K: 'c> {
// @has self_referential/struct.WriteAndThen.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<P1> Send for WriteAndThen<P1> where <P1 as Pattern>::Value: Send"
pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
where P1: Pattern;
}
// @has static_region/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<T> Send for Owned<T> where <T as OwnedTrait<'static>>::Reader: Send"
pub struct Owned<T> where T: OwnedTrait<'static> {
marker: <T as OwnedTrait<'static>>::Reader,
// @has 'toggle_item_contents/struct.BigPubStruct.html'
// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 fields'
pub struct BigPubStruct {
pub a: usize,
pub b: usize,
// @has 'toggle_item_contents/union.BigUnion.html'
// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 fields'
pub union BigUnion {
pub a: usize,
pub b: usize,
}
// @has 'toggle_item_contents/enum.Enum.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
+// @!has - '//details[@class="rustdoc-toggle type-contents-toggle"]'
pub enum Enum {
A, B, C,
D {
}
}
+// @has 'toggle_item_contents/enum.EnumStructVariant.html'
+// @!has - '//details[@class="rustdoc-toggle type-contents-toggle"]'
+pub enum EnumStructVariant {
+ A, B, C,
+ D {
+ a: u8,
+ }
+}
+
// @has 'toggle_item_contents/enum.LargeEnum.html'
// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show variants'
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 variants'
pub enum LargeEnum {
A, B, C, D, E, F(u8), G, H, I, J, K, L, M
}
// @has 'toggle_item_contents/trait.GinormousTrait.html'
// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated items'
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 16 associated items'
pub trait GinormousTrait {
type A;
type B;
// @has 'toggle_item_contents/trait.HugeTrait.html'
// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated constants and methods'
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 12 associated constants and 2 methods'
pub trait HugeTrait {
type A;
const M: usize = 1;
fn bar();
}
+// @has 'toggle_item_contents/trait.GiganticTrait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 1 associated constant and 1 method'
+pub trait GiganticTrait {
+ type A;
+ type B;
+ type C;
+ type D;
+ type E;
+ type F;
+ type G;
+ type H;
+ type I;
+ type J;
+ type K;
+ type L;
+ const M: usize = 1;
+ #[must_use]
+ fn foo();
+}
+
// @has 'toggle_item_contents/trait.BigTrait.html'
// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show methods'
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 14 methods'
pub trait BigTrait {
type A;
#[must_use]
// summary. Struct methods with no documentation should not be wrapped.
//
// @has foo/struct.Foo.html
-// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//code' 'is_documented()'
+// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
-// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//code' 'not_documented()'
+// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
pub struct Foo {
}
// summary. Trait methods with no documentation should not be wrapped.
//
// @has foo/trait.Foo.html
-// @has - '//details[@class="rustdoc-toggle"]//summary//code' 'is_documented()'
-// @!has - '//details[@class="rustdoc-toggle"]//summary//code' 'not_documented()'
+// @has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
+// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
// @has - '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented is documented'
-// @has - '//details[@class="rustdoc-toggle"]//summary//code' 'is_documented_optional()'
-// @!has - '//details[@class="rustdoc-toggle"]//summary//code' 'not_documented_optional()'
+// @has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()'
+// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()'
// @has - '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
pub trait Foo {
fn not_documented();
// @!has - '//*[@id="method.d"]/../../div[@class="docblock"]/p/em'
fn d() {}
- // @has - '//*[@id="impl-Trait"]/code/a/@href' 'trait.Trait.html'
+ // @has - '//*[@id="impl-Trait"]/h3//a/@href' 'trait.Trait.html'
}
pub struct Bounded<T: Clone>(T);
// @has traits_in_bodies/struct.SomeStruct.html
-// @has - '//code' 'impl Clone for SomeStruct'
+// @has - '//h3[@class="code-header in-band"]' 'impl Clone for SomeStruct'
pub struct SomeStruct;
fn asdf() -> Bounded<SomeStruct> {
}
// @has traits_in_bodies/struct.Point.html
-// @has - '//code' 'impl Copy for Point'
+// @has - '//h3[@class="code-header in-band"]' 'impl Copy for Point'
#[derive(Clone)]
pub struct Point {
x: i32,
};
// @has traits_in_bodies/struct.Inception.html
-// @has - '//code' 'impl Clone for Inception'
+// @has - '//h3[@class="code-header in-band"]' 'impl Clone for Inception'
pub struct Inception;
static _BAR: usize = {
}
// @has typedef/type.MyAlias.html
-// @has - '//*[@class="impl has-srclink"]//code' 'impl MyAlias'
-// @has - '//*[@class="impl has-srclink"]//code' 'impl MyTrait for MyAlias'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'impl MyAlias'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'impl MyTrait for MyAlias'
// @has - 'Alias docstring'
// @has - '//*[@class="sidebar"]//*[@class="location"]' 'Type Definition MyAlias'
// @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods'
fn function();
}
-// @has 'foo/struct.FooPublic.html' '//code' 'type Type'
-// @!has 'foo/struct.FooPublic.html' '//code' 'pub type Type'
+// @has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'type Type'
+// @!has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'pub type Type'
//
-// @has 'foo/struct.FooPublic.html' '//code' 'const CONST: usize'
-// @!has 'foo/struct.FooPublic.html' '//code' 'pub const CONST: usize'
+// @has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'const CONST: usize'
+// @!has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'pub const CONST: usize'
//
-// @has 'foo/struct.FooPublic.html' '//code' 'fn function()'
-// @!has 'foo/struct.FooPublic.html' '//code' 'pub fn function()'
+// @has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'fn function()'
+// @!has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'pub fn function()'
impl PubTrait for FooPublic {
type Type = usize;
pub struct Delta<D>(D);
-// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//code' \
+// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<D> Delta<D> where D: MyTrait"
impl<D> Delta<D> where D: MyTrait {
pub fn delta() {}
pub struct Echo<E>(E);
-// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//code' \
+// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<E> MyTrait for Echo<E> where E: MyTrait"
-// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//code' \
+// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
// "impl<E> MyTrait for Echo<E> where E: MyTrait"
impl<E> MyTrait for Echo<E> where E: MyTrait {}
pub enum Foxtrot<F> { Foxtrot1(F) }
-// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//code' \
+// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
-// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//code' \
+// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
// "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
impl<F> MyTrait for Foxtrot<F> where F: MyTrait {}
if !cx.sess().contains_name(attrs, $attr) {
cx.lint(CRATE_NOT_OKAY, |lint| {
let msg = format!("crate is not marked with #![{}]", $attr);
- lint.build(&msg).set_span(krate.item.inner).emit()
+ lint.build(&msg).set_span(krate.module().inner).emit()
});
}
)*
if !cx.sess().contains_name(attrs, Symbol::intern("crate_okay")) {
cx.lint(CRATE_NOT_OKAY, |lint| {
lint.build("crate is not marked with #![crate_okay]")
- .set_span(krate.item.inner)
+ .set_span(krate.module().inner)
.emit()
});
}
-error[E0038]: the trait `Bar` cannot be made into an object
- --> $DIR/issue-48027.rs:6:6
- |
-LL | impl dyn Bar {}
- | ^^^^^^^ `Bar` cannot be made into an object
- |
- = help: consider moving `X` to another trait
-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-48027.rs:2:11
- |
-LL | trait Bar {
- | --- this trait cannot be made into an object...
-LL | const X: usize;
- | ^ ...because it contains this associated `const`
-
error[E0283]: type annotations needed
--> $DIR/issue-48027.rs:3:32
|
LL | const X: usize;
| ^^^^^^^^^^^^^^^
+error[E0038]: the trait `Bar` cannot be made into an object
+ --> $DIR/issue-48027.rs:6:6
+ |
+LL | impl dyn Bar {}
+ | ^^^^^^^ `Bar` cannot be made into an object
+ |
+ = help: consider moving `X` to another trait
+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-48027.rs:2:11
+ |
+LL | trait Bar {
+ | --- this trait cannot be made into an object...
+LL | const X: usize;
+ | ^ ...because it contains this associated `const`
+
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0038, E0283.
impl Thing for AssocNoCopy {
type Out = Box<dyn Bar<Assoc: Copy>>;
//~^ ERROR the trait bound `String: Copy` is not satisfied
- //~| ERROR the trait bound `String: Copy` is not satisfied
fn func() -> Self::Out {
Box::new(AssocNoCopy)
LL | type Out = Box<dyn Bar<Assoc: Copy>>;
| ^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
-error[E0277]: the trait bound `String: Copy` is not satisfied
- --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:30:28
- |
-LL | type Out = Box<dyn Bar<Assoc: Copy>>;
- | ^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
error[E0277]: the trait bound `Self: Get` is not satisfied
- --> $DIR/associated-types-for-unimpl-trait.rs:10:8
+ --> $DIR/associated-types-for-unimpl-trait.rs:10:40
|
+LL | trait Get {
+ | --------- required by this bound in `Get`
+...
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:8
+ --> $DIR/associated-types-no-suitable-bound.rs:11:21
|
+LL | trait Get {
+ | --------- required by this bound in `Get`
+...
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:8
+ --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:40
|
+LL | trait Get {
+ | --------- required by this bound in `Get`
+...
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-no-suitable-supertrait.rs:17:8
+ --> $DIR/associated-types-no-suitable-supertrait.rs:17:40
|
+LL | trait Get {
+ | --------- required by this bound in `Get`
+...
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:8
+ --> $DIR/associated-types-no-suitable-supertrait.rs:22:40
|
+LL | trait Get {
+ | --------- required by this bound in `Get`
+...
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: aborting due to 2 previous errors
error[E0277]: the trait bound `Self: Get` is not satisfied
- --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:8
+ --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:40
|
+LL | trait Get {
+ | --------- required by this bound in `Get`
+...
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`
|
<&T as Clone>
error[E0277]: the trait bound `for<'b> <u16 as Z<'b, u16>>::W: Clone` is not satisfied
- --> $DIR/hr-associated-type-bound-param-2.rs:16:14
+ --> $DIR/hr-associated-type-bound-param-2.rs:4:8
|
LL | trait Z<'a, T: ?Sized>
| - required by a bound in this
+LL | where
+LL | T: Z<'a, u16>,
+ | ^^^^^^^^^^ the trait `for<'b> Clone` is not implemented for `<u16 as Z<'b, u16>>::W`
...
LL | for<'b> <T as Z<'b, u16>>::W: Clone,
| ----- required by this bound in `Z`
-...
-LL | type W = str;
- | ^^^ the trait `for<'b> Clone` is not implemented for `<u16 as Z<'b, u16>>::W`
|
= help: the following implementations were found:
<&T as Clone>
error[E0277]: the trait bound `for<'b> <u16 as Z<'b, u16>>::W: Clone` is not satisfied
- --> $DIR/hr-associated-type-bound-param-2.rs:4:8
+ --> $DIR/hr-associated-type-bound-param-2.rs:16:14
|
LL | trait Z<'a, T: ?Sized>
| - required by a bound in this
-LL | where
-LL | T: Z<'a, u16>,
- | ^^^^^^^^^^ the trait `for<'b> Clone` is not implemented for `<u16 as Z<'b, u16>>::W`
...
LL | for<'b> <T as Z<'b, u16>>::W: Clone,
| ----- required by this bound in `Z`
+...
+LL | type W = str;
+ | ^^^ the trait `for<'b> Clone` is not implemented for `<u16 as Z<'b, u16>>::W`
|
= help: the following implementations were found:
<&T as Clone>
}
impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
- //~^ ERROR the trait bound `<T as UnsafeCopy<'b, T>>::Item: Deref` is not satisfied
+ //~^ ERROR the trait bound `for<'b> <T as UnsafeCopy<'b, T>>::Item: Deref` is not satisfied
type Item = T;
//~^ ERROR the trait bound `for<'b> <T as UnsafeCopy<'b, T>>::Item: Deref
}
<&T as Deref>
<&mut T as Deref>
-error[E0277]: the trait bound `<T as UnsafeCopy<'b, T>>::Item: Deref` is not satisfied
+error[E0277]: the trait bound `for<'b> <T as UnsafeCopy<'b, T>>::Item: Deref` is not satisfied
--> $DIR/hr-associated-type-projection-1.rs:13:33
|
LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
- | ^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `<T as UnsafeCopy<'b, T>>::Item`
+ | ^^^^^^^^^^^^^^^^^ the trait `for<'b> Deref` is not implemented for `<T as UnsafeCopy<'b, T>>::Item`
|
help: consider further restricting the associated type
|
-LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T where <T as UnsafeCopy<'b, T>>::Item: Deref {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T where for<'b> <T as UnsafeCopy<'b, T>>::Item: Deref {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
--- /dev/null
+trait Foo {}
+
+trait Trait {
+ type Associated;
+}
+trait DerivedTrait: Trait {}
+trait GenericTrait<A> {
+ type Associated;
+}
+
+struct Impl;
+impl Foo for Impl {}
+impl Trait for Impl {
+ type Associated = ();
+}
+impl DerivedTrait for Impl {}
+impl<A> GenericTrait<A> for Impl {
+ type Associated = ();
+}
+
+fn returns_opaque() -> impl Trait + 'static {
+ Impl
+}
+fn returns_opaque_derived() -> impl DerivedTrait + 'static {
+ Impl
+}
+fn returns_opaque_foo() -> impl Trait + Foo {
+ Impl
+}
+fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo {
+ Impl
+}
+fn returns_opaque_generic() -> impl GenericTrait<()> + 'static {
+ Impl
+}
+fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo {
+ Impl
+}
+fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait<u8> {
+ Impl
+}
+
+fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+
+fn check_generics<A, B, C, D, E, F, G>(a: A, b: B, c: C, d: D, e: E, f: F, g: G)
+where
+ A: Trait + 'static,
+ B: DerivedTrait + 'static,
+ C: Trait + Foo,
+ D: DerivedTrait + Foo,
+ E: GenericTrait<()> + 'static,
+ F: GenericTrait<()> + Foo,
+ G: GenericTrait<()> + GenericTrait<u8>,
+{
+ accepts_trait(a);
+ //~^ ERROR type mismatch resolving `<A as Trait>::Associated == ()`
+
+ accepts_trait(b);
+ //~^ ERROR type mismatch resolving `<B as Trait>::Associated == ()`
+
+ accepts_trait(c);
+ //~^ ERROR type mismatch resolving `<C as Trait>::Associated == ()`
+
+ accepts_trait(d);
+ //~^ ERROR type mismatch resolving `<D as Trait>::Associated == ()`
+
+ accepts_generic_trait(e);
+ //~^ ERROR type mismatch resolving `<E as GenericTrait<()>>::Associated == ()`
+
+ accepts_generic_trait(f);
+ //~^ ERROR type mismatch resolving `<F as GenericTrait<()>>::Associated == ()`
+
+ accepts_generic_trait(g);
+ //~^ ERROR type mismatch resolving `<G as GenericTrait<()>>::Associated == ()`
+}
+
+fn main() {
+ accepts_trait(returns_opaque());
+ //~^ ERROR type mismatch resolving `<impl Trait as Trait>::Associated == ()`
+
+ accepts_trait(returns_opaque_derived());
+ //~^ ERROR type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
+
+ accepts_trait(returns_opaque_foo());
+ //~^ ERROR type mismatch resolving `<impl Trait+Foo as Trait>::Associated == ()`
+
+ accepts_trait(returns_opaque_derived_foo());
+ //~^ ERROR type mismatch resolving `<impl DerivedTrait+Foo as Trait>::Associated == ()`
+
+ accepts_generic_trait(returns_opaque_generic());
+ //~^ ERROR type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
+
+ accepts_generic_trait(returns_opaque_generic_foo());
+ //~^ ERROR type mismatch resolving `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated == ()`
+
+ accepts_generic_trait(returns_opaque_generic_duplicate());
+ //~^ ERROR type mismatch resolving `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
+}
--- /dev/null
+error[E0271]: type mismatch resolving `<A as Trait>::Associated == ()`
+ --> $DIR/issue-87261.rs:56:5
+ |
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+ | --------------- required by this bound in `accepts_trait`
+...
+LL | accepts_trait(a);
+ | ^^^^^^^^^^^^^ expected `()`, found associated type
+ |
+ = note: expected unit type `()`
+ found associated type `<A as Trait>::Associated`
+help: consider constraining the associated type `<A as Trait>::Associated` to `()`
+ |
+LL | A: Trait<Associated = ()> + 'static,
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<B as Trait>::Associated == ()`
+ --> $DIR/issue-87261.rs:59:5
+ |
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+ | --------------- required by this bound in `accepts_trait`
+...
+LL | accepts_trait(b);
+ | ^^^^^^^^^^^^^ expected `()`, found associated type
+ |
+ = note: expected unit type `()`
+ found associated type `<B as Trait>::Associated`
+ = help: consider constraining the associated type `<B as Trait>::Associated` to `()`
+ = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0271]: type mismatch resolving `<C as Trait>::Associated == ()`
+ --> $DIR/issue-87261.rs:62:5
+ |
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+ | --------------- required by this bound in `accepts_trait`
+...
+LL | accepts_trait(c);
+ | ^^^^^^^^^^^^^ expected `()`, found associated type
+ |
+ = note: expected unit type `()`
+ found associated type `<C as Trait>::Associated`
+help: consider constraining the associated type `<C as Trait>::Associated` to `()`
+ |
+LL | C: Trait<Associated = ()> + Foo,
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<D as Trait>::Associated == ()`
+ --> $DIR/issue-87261.rs:65:5
+ |
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+ | --------------- required by this bound in `accepts_trait`
+...
+LL | accepts_trait(d);
+ | ^^^^^^^^^^^^^ expected `()`, found associated type
+ |
+ = note: expected unit type `()`
+ found associated type `<D as Trait>::Associated`
+ = help: consider constraining the associated type `<D as Trait>::Associated` to `()`
+ = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0271]: type mismatch resolving `<E as GenericTrait<()>>::Associated == ()`
+ --> $DIR/issue-87261.rs:68:5
+ |
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+ | --------------- required by this bound in `accepts_generic_trait`
+...
+LL | accepts_generic_trait(e);
+ | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+ |
+ = note: expected unit type `()`
+ found associated type `<E as GenericTrait<()>>::Associated`
+help: consider constraining the associated type `<E as GenericTrait<()>>::Associated` to `()`
+ |
+LL | E: GenericTrait<(), Associated = ()> + 'static,
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<F as GenericTrait<()>>::Associated == ()`
+ --> $DIR/issue-87261.rs:71:5
+ |
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+ | --------------- required by this bound in `accepts_generic_trait`
+...
+LL | accepts_generic_trait(f);
+ | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+ |
+ = note: expected unit type `()`
+ found associated type `<F as GenericTrait<()>>::Associated`
+help: consider constraining the associated type `<F as GenericTrait<()>>::Associated` to `()`
+ |
+LL | F: GenericTrait<(), Associated = ()> + Foo,
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<G as GenericTrait<()>>::Associated == ()`
+ --> $DIR/issue-87261.rs:74:5
+ |
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+ | --------------- required by this bound in `accepts_generic_trait`
+...
+LL | accepts_generic_trait(g);
+ | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+ |
+ = note: expected unit type `()`
+ found associated type `<G as GenericTrait<()>>::Associated`
+ = help: consider constraining the associated type `<G as GenericTrait<()>>::Associated` to `()`
+ = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0271]: type mismatch resolving `<impl Trait as Trait>::Associated == ()`
+ --> $DIR/issue-87261.rs:79:5
+ |
+LL | fn returns_opaque() -> impl Trait + 'static {
+ | -------------------- the found opaque type
+...
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+ | --------------- required by this bound in `accepts_trait`
+...
+LL | accepts_trait(returns_opaque());
+ | ^^^^^^^^^^^^^ expected `()`, found associated type
+ |
+ = note: expected unit type `()`
+ found associated type `<impl Trait as Trait>::Associated`
+help: consider constraining the associated type `<impl Trait as Trait>::Associated` to `()`
+ |
+LL | fn returns_opaque() -> impl Trait<Associated = ()> + 'static {
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
+ --> $DIR/issue-87261.rs:82:5
+ |
+LL | fn returns_opaque_derived() -> impl DerivedTrait + 'static {
+ | --------------------------- the found opaque type
+...
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+ | --------------- required by this bound in `accepts_trait`
+...
+LL | accepts_trait(returns_opaque_derived());
+ | ^^^^^^^^^^^^^ expected `()`, found associated type
+ |
+ = note: expected unit type `()`
+ found associated type `<impl DerivedTrait as Trait>::Associated`
+help: consider constraining the associated type `<impl DerivedTrait as Trait>::Associated` to `()`
+ |
+LL | fn returns_opaque_derived() -> impl DerivedTrait<Associated = ()> + 'static {
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl Trait+Foo as Trait>::Associated == ()`
+ --> $DIR/issue-87261.rs:85:5
+ |
+LL | fn returns_opaque_foo() -> impl Trait + Foo {
+ | ---------------- the found opaque type
+...
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+ | --------------- required by this bound in `accepts_trait`
+...
+LL | accepts_trait(returns_opaque_foo());
+ | ^^^^^^^^^^^^^ expected `()`, found associated type
+ |
+ = note: expected unit type `()`
+ found associated type `<impl Trait+Foo as Trait>::Associated`
+help: consider constraining the associated type `<impl Trait+Foo as Trait>::Associated` to `()`
+ |
+LL | fn returns_opaque_foo() -> impl Trait<Associated = ()> + Foo {
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl DerivedTrait+Foo as Trait>::Associated == ()`
+ --> $DIR/issue-87261.rs:88:5
+ |
+LL | fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo {
+ | ----------------------- the found opaque type
+...
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+ | --------------- required by this bound in `accepts_trait`
+...
+LL | accepts_trait(returns_opaque_derived_foo());
+ | ^^^^^^^^^^^^^ expected `()`, found associated type
+ |
+ = note: expected unit type `()`
+ found associated type `<impl DerivedTrait+Foo as Trait>::Associated`
+ = help: consider constraining the associated type `<impl DerivedTrait+Foo as Trait>::Associated` to `()`
+ = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0271]: type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
+ --> $DIR/issue-87261.rs:91:5
+ |
+LL | fn returns_opaque_generic() -> impl GenericTrait<()> + 'static {
+ | ------------------------------- the found opaque type
+...
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+ | --------------- required by this bound in `accepts_generic_trait`
+...
+LL | accepts_generic_trait(returns_opaque_generic());
+ | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+ |
+ = note: expected unit type `()`
+ found associated type `<impl GenericTrait<()> as GenericTrait<()>>::Associated`
+help: consider constraining the associated type `<impl GenericTrait<()> as GenericTrait<()>>::Associated` to `()`
+ |
+LL | fn returns_opaque_generic() -> impl GenericTrait<(), Associated = ()> + 'static {
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated == ()`
+ --> $DIR/issue-87261.rs:94:5
+ |
+LL | fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo {
+ | --------------------------- the found opaque type
+...
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+ | --------------- required by this bound in `accepts_generic_trait`
+...
+LL | accepts_generic_trait(returns_opaque_generic_foo());
+ | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+ |
+ = note: expected unit type `()`
+ found associated type `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated`
+help: consider constraining the associated type `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated` to `()`
+ |
+LL | fn returns_opaque_generic_foo() -> impl GenericTrait<(), Associated = ()> + Foo {
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
+ --> $DIR/issue-87261.rs:97:5
+ |
+LL | fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait<u8> {
+ | ---------------------------------------- the found opaque type
+...
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+ | --------------- required by this bound in `accepts_generic_trait`
+...
+LL | accepts_generic_trait(returns_opaque_generic_duplicate());
+ | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+ |
+ = note: expected unit type `()`
+ found associated type `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated`
+ = help: consider constraining the associated type `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated` to `()`
+ = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
--- /dev/null
+// edition:2018
+
+use ::core::pin::Pin;
+use ::core::future::Future;
+use ::core::marker::Send;
+
+trait Foo {
+ fn bar<'me, 'async_trait, T: Send>(x: &'me T)
+ -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
+ where 'me: 'async_trait;
+}
+
+impl Foo for () {
+ fn bar<'me, 'async_trait, T: Send>(x: &'me T)
+ -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
+ where 'me:'async_trait {
+ Box::pin( //~ ERROR future cannot be sent between threads safely
+ async move {
+ let x = x;
+ }
+ )
+ }
+}
+
+fn main() { }
--- /dev/null
+error: future cannot be sent between threads safely
+ --> $DIR/issue-86507.rs:17:13
+ |
+LL | / Box::pin(
+LL | | async move {
+LL | | let x = x;
+LL | | }
+LL | | )
+ | |_____________^ future created by async block is not `Send`
+ |
+note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
+ --> $DIR/issue-86507.rs:19:29
+ |
+LL | let x = x;
+ | ^ has type `&T` which is not `Send`, because `T` is not `Sync`
+ = note: required for the cast to the object type `dyn Future<Output = ()> + Send`
+help: consider further restricting type parameter `T`
+ |
+LL | where 'me:'async_trait, T: std::marker::Sync {
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+error: moving 10024 bytes
+ --> $DIR/large_moves.rs:12:13
+ |
+LL | let x = async {
+ | _____________^
+LL | | let y = [0; 9999];
+LL | | dbg!(y);
+LL | | thing(&y).await;
+LL | | dbg!(y);
+LL | | };
+ | |_____^ value moved from here
+ |
+note: the lint level is defined here
+ --> $DIR/large_moves.rs:1:9
+ |
+LL | #![deny(large_assignments)]
+ | ^^^^^^^^^^^^^^^^^
+
+error: moving 10024 bytes
+ --> $DIR/large_moves.rs:18:14
+ |
+LL | let z = (x, 42);
+ | ^ value moved from here
+
+error: moving 10024 bytes
+ --> $DIR/large_moves.rs:18:13
+ |
+LL | let z = (x, 42);
+ | ^^^^^^^ value moved from here
+
+error: moving 10024 bytes
+ --> $DIR/large_moves.rs:20:13
+ |
+LL | let a = z.0;
+ | ^^^ value moved from here
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+error: moving 10024 bytes
+ --> $DIR/large_moves.rs:12:13
+ |
+LL | let x = async {
+ | _____________^
+LL | | let y = [0; 9999];
+LL | | dbg!(y);
+LL | | thing(&y).await;
+LL | | dbg!(y);
+LL | | };
+ | |_____^ value moved from here
+ |
+note: the lint level is defined here
+ --> $DIR/large_moves.rs:1:9
+ |
+LL | #![deny(large_assignments)]
+ | ^^^^^^^^^^^^^^^^^
+
+error: moving 10024 bytes
+ --> $DIR/large_moves.rs:18:14
+ |
+LL | let z = (x, 42);
+ | ^ value moved from here
+
+error: moving 10024 bytes
+ --> $DIR/large_moves.rs:18:13
+ |
+LL | let z = (x, 42);
+ | ^^^^^^^ value moved from here
+
+error: moving 10024 bytes
+ --> $DIR/large_moves.rs:20:13
+ |
+LL | let a = z.0;
+ | ^^^ value moved from here
+
+error: aborting due to 4 previous errors
+
#![deny(large_assignments)]
#![feature(large_assignments)]
-#![move_size_limit = "1000"]
+#![cfg_attr(attribute, move_size_limit = "1000")]
// build-fail
// only-x86_64
+// revisions: attribute option
+// [option]compile-flags: -Zmove-size-limit=1000
// edition:2018
+++ /dev/null
-error: moving 10024 bytes
- --> $DIR/large_moves.rs:10:13
- |
-LL | let x = async {
- | _____________^
-LL | | let y = [0; 9999];
-LL | | dbg!(y);
-LL | | thing(&y).await;
-LL | | dbg!(y);
-LL | | };
- | |_____^ value moved from here
- |
-note: the lint level is defined here
- --> $DIR/large_moves.rs:1:9
- |
-LL | #![deny(large_assignments)]
- | ^^^^^^^^^^^^^^^^^
-
-error: moving 10024 bytes
- --> $DIR/large_moves.rs:16:14
- |
-LL | let z = (x, 42);
- | ^ value moved from here
-
-error: moving 10024 bytes
- --> $DIR/large_moves.rs:16:13
- |
-LL | let z = (x, 42);
- | ^^^^^^^ value moved from here
-
-error: moving 10024 bytes
- --> $DIR/large_moves.rs:18:13
- |
-LL | let a = z.0;
- | ^^^ value moved from here
-
-error: aborting due to 4 previous errors
-
error: lifetime may not live long enough
- --> $DIR/ret-impl-trait-one.rs:10:80
+ --> $DIR/ret-impl-trait-one.rs:10:65
|
-LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
- | ________________________________--__--__________________________________________^
- | | | |
- | | | lifetime `'b` defined here
- | | lifetime `'a` defined here
-LL | |
-LL | | (a, b)
-LL | | }
- | |_^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
+ | -- -- ^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
+ | | |
+ | | lifetime `'b` defined here
+ | lifetime `'a` defined here
|
= help: consider adding the following bound: `'b: 'a`
//
// My heart aches in sorrow, for I know I am defeated. Let this be a warning
// to all those who come after. Here stands the bastion of the Turbofish.
+//
+// RIP Anna Harren, Guardian Angel of the Hallowed Turbofish. <3
// See https://github.com/rust-lang/rust/pull/53562
// and https://github.com/rust-lang/rfcs/pull/2527
+// and https://twitter.com/garblefart/status/1393236602856611843
// for context.
fn main() {
// Tests using a combination of pattern features has the expected borrow checking behavior
-#![feature(bindings_after_at)]
#![feature(box_patterns)]
enum Test {
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:37:9
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:36:9
|
LL | ref foo @ [.., ref mut bar] => (),
| -------^^^^^^^^-----------^
| immutable borrow, by `foo`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:121:9
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:120:9
|
LL | ref foo @ Some(box ref mut s) => (),
| -------^^^^^^^^^^^^---------^
| immutable borrow, by `foo`, occurs here
error[E0382]: borrow of moved value: `x`
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:19:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:18:5
|
LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) {
| - move occurs because `x` has type `[String; 4]`, which does not implement the `Copy` trait
| ^^ value borrowed here after move
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:29:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:28:5
|
LL | ref mut foo @ [.., _] => Some(foo),
| --------------------- mutable borrow occurs here
| - mutable borrow later used here
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:51:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:50:5
|
LL | [ref foo @ .., ref bar] => Some(foo),
| ------------ immutable borrow occurs here
| - immutable borrow later used here
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:63:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:62:5
|
LL | ref foo @ [.., ref bar] => Some(foo),
| ----------------------- immutable borrow occurs here
| - immutable borrow later used here
error[E0382]: borrow of moved value: `x`
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:77:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:76:5
|
LL | fn bindings_after_at_or_patterns_move(x: Option<Test>) {
| - move occurs because `x` has type `Option<Test>`, which does not implement the `Copy` trait
| ^^ value borrowed here after move
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:87:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:86:5
|
LL | ref foo @ Some(Test::Foo | Test::Bar) => Some(foo),
| ------------------------------------- immutable borrow occurs here
| - immutable borrow later used here
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:99:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:98:5
|
LL | ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo),
| ----------------------------------------- mutable borrow occurs here
| - mutable borrow later used here
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:113:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:112:5
|
LL | ref foo @ Some(box ref s) => Some(foo),
| ------------------------- immutable borrow occurs here
| - immutable borrow later used here
error[E0382]: borrow of moved value: `x`
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:135:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:134:5
|
LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4]) {
| - move occurs because `x` has type `[Option<Test>; 4]`, which does not implement the `Copy` trait
| ^^ value borrowed here after move
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:145:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:144:5
|
LL | ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a),
| ------------------------------------------------- immutable borrow occurs here
| - immutable borrow later used here
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:157:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:156:5
|
LL | ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b),
| ---------- immutable borrow occurs here
| - immutable borrow later used here
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:171:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:170:5
|
LL | [_, ref a @ Some(box ref b), ..] => Some(a),
| ----------------------- immutable borrow occurs here
| - immutable borrow later used here
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:187:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:186:5
|
LL | [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
| ------------------------------------------- immutable borrow occurs here
| - immutable borrow later used here
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:201:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:200:5
|
LL | [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
| ----------------------------------------------- mutable borrow occurs here
| - mutable borrow later used here
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
- --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:215:5
+ --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:214:5
|
LL | ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
| ------------------------------------------------------------ immutable borrow occurs here
// run-pass
// pretty-expanded FIXME #23616
-#![allow(dead_code)]
pub fn main() {
struct A {
*r = 0;
//~^ ERROR cannot assign to `*r`, which is behind a `&` reference
//~| NOTE `r` is a `&` reference, so the data it refers to cannot be written
+
+ #[rustfmt::skip]
+ let x: &usize = &mut{0};
+ //~^ HELP consider changing this to be a mutable reference
+ *x = 1;
+ //~^ ERROR cannot assign to `*x`, which is behind a `&` reference
+ //~| NOTE `x` is a `&` reference, so the data it refers to cannot be written
+
+ #[rustfmt::skip]
+ let y: &usize = &mut(0);
+ //~^ HELP consider changing this to be a mutable reference
+ *y = 1;
+ //~^ ERROR cannot assign to `*y`, which is behind a `&` reference
+ //~| NOTE `y` is a `&` reference, so the data it refers to cannot be written
}
LL | *r = 0;
| ^^^^^^ `r` is a `&` reference, so the data it refers to cannot be written
-error: aborting due to 2 previous errors
+error[E0594]: cannot assign to `*x`, which is behind a `&` reference
+ --> $DIR/issue-85765.rs:19:5
+ |
+LL | let x: &usize = &mut{0};
+ | - help: consider changing this to be a mutable reference: `&mut usize`
+LL |
+LL | *x = 1;
+ | ^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
+
+error[E0594]: cannot assign to `*y`, which is behind a `&` reference
+ --> $DIR/issue-85765.rs:26:5
+ |
+LL | let y: &usize = &mut(0);
+ | - help: consider changing this to be a mutable reference: `&mut usize`
+LL |
+LL | *y = 1;
+ | ^^^^^^ `y` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to 4 previous errors
Some errors have detailed explanations: E0594, E0596.
For more information about an error, try `rustc --explain E0594`.
--- /dev/null
+#![feature(rustc_attrs)]
+
+// edition:2021
+
+// Test that any precise capture on a union is truncated because it's unsafe to do so.
+
+union Union {
+ value: u64,
+}
+
+fn main() {
+ let u = Union { value: 42 };
+
+ let c = #[rustc_capture_analysis]
+ //~^ ERROR: attributes on expressions are experimental
+ //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+ || {
+ //~^ ERROR: First Pass analysis includes:
+ //~| ERROR: Min Capture analysis includes:
+ unsafe { u.value }
+ //~^ NOTE: Capturing u[(0, 0)] -> ImmBorrow
+ //~| NOTE: Min Capture u[] -> ImmBorrow
+ };
+
+ c();
+}
--- /dev/null
+error[E0658]: attributes on expressions are experimental
+ --> $DIR/issue-87378.rs:14:13
+ |
+LL | let c = #[rustc_capture_analysis]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+ = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error: First Pass analysis includes:
+ --> $DIR/issue-87378.rs:17:5
+ |
+LL | / || {
+LL | |
+LL | |
+LL | | unsafe { u.value }
+LL | |
+LL | |
+LL | | };
+ | |_____^
+ |
+note: Capturing u[(0, 0)] -> ImmBorrow
+ --> $DIR/issue-87378.rs:20:17
+ |
+LL | unsafe { u.value }
+ | ^^^^^^^
+
+error: Min Capture analysis includes:
+ --> $DIR/issue-87378.rs:17:5
+ |
+LL | / || {
+LL | |
+LL | |
+LL | | unsafe { u.value }
+LL | |
+LL | |
+LL | | };
+ | |_____^
+ |
+note: Min Capture u[] -> ImmBorrow
+ --> $DIR/issue-87378.rs:20:17
+ |
+LL | unsafe { u.value }
+ | ^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// edition:2021
+// check-pass
+
+union Union {
+ value: u64,
+}
+
+fn main() {
+ let u = Union { value: 42 };
+
+ let c = || {
+ unsafe { u.value }
+ };
+
+ c();
+}
| ^^------^
| | |
| | found signature of `fn(u16) -> _`
- | expected signature of `fn(<u32 as T<'x>>::V) -> _`
+ | expected signature of `for<'x> fn(<u32 as T<'x>>::V) -> _`
|
= note: required for the cast to the object type `dyn for<'x> Fn(<u32 as T<'x>>::V)`
-error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))`
+error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(for<'r> fn(&'r ()))`
--> $DIR/coherence-fn-covariant-bound-vs-static.rs:17:1
|
LL | impl Trait for for<'r> fn(fn(&'r ())) {}
| ------------------------------------- first implementation here
LL | impl<'a> Trait for fn(fn(&'a ())) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(fn(&'r ()))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(for<'r> fn(&'r ()))`
|
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+++ /dev/null
-#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(full, allow(incomplete_features))]
-
-pub struct Num<const N: usize>;
-
-// Braces around const expression causes crash
-impl Num<{5}> {
- pub fn five(&self) {
- }
-}
= help: more complex types are supported with `#![feature(const_generics)]`
error: `&'static u8` is forbidden as the type of a const generic parameter
- --> $DIR/const-param-elided-lifetime.rs:23:15
+ --> $DIR/const-param-elided-lifetime.rs:18:21
|
-LL | impl<const N: &u8> B for A<N> {}
- | ^^^
+LL | fn foo<const M: &u8>(&self) {}
+ | ^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: more complex types are supported with `#![feature(const_generics)]`
error: `&'static u8` is forbidden as the type of a const generic parameter
- --> $DIR/const-param-elided-lifetime.rs:27:17
+ --> $DIR/const-param-elided-lifetime.rs:23:15
|
-LL | fn bar<const N: &u8>() {}
- | ^^^
+LL | impl<const N: &u8> B for A<N> {}
+ | ^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: more complex types are supported with `#![feature(const_generics)]`
error: `&'static u8` is forbidden as the type of a const generic parameter
- --> $DIR/const-param-elided-lifetime.rs:18:21
+ --> $DIR/const-param-elided-lifetime.rs:27:17
|
-LL | fn foo<const M: &u8>(&self) {}
- | ^^^
+LL | fn bar<const N: &u8>() {}
+ | ^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: more complex types are supported with `#![feature(const_generics)]`
error[E0038]: the trait `Foo` cannot be made into an object
- --> $DIR/object-safety-err-ret.rs:17:15
+ --> $DIR/object-safety-err-ret.rs:17:16
|
LL | fn use_dyn(v: &dyn Foo) {
- | ^^^^^^^^ `Foo` cannot be made into an object
+ | ^^^^^^^ `Foo` cannot be made into an object
|
= help: consider moving `test` to another trait
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>
--- /dev/null
+#![feature(const_generics, const_evaluatable_checked, const_generics_defaults)]
+#![allow(incomplete_features)]
+
+struct Foo<const N: usize, const M: usize = { N + 1 }>;
+fn no_constraining() -> Foo<10> {
+ Foo::<10, 11>
+}
+
+pub fn different_than_default() -> Foo<10> {
+ Foo::<10, 12>
+ //~^ error: mismatched types
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/cec-concrete-default.rs:10:5
+ |
+LL | Foo::<10, 12>
+ | ^^^^^^^^^^^^^ expected `11_usize`, found `12_usize`
+ |
+ = note: expected type `11_usize`
+ found type `12_usize`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#![feature(const_generics, const_evaluatable_checked, const_generics_defaults)]
+#![allow(incomplete_features)]
+
+struct Foo<const N: usize, const M: usize = { N + 1 }>;
+fn should_unify<const N: usize>() -> Foo<N> where [(); { N + 1 }]: {
+ Foo::<N, { N + 1 }>
+}
+pub fn shouldnt_unify<const N: usize>() -> Foo<N>
+where
+ [(); { N + 1 }]:,
+ [(); { N + 2 }]:, {
+ Foo::<N, { N + 2 }>
+ //~^ error: mismatched types
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/cec-generic-default-mismatched-types.rs:12:5
+ |
+LL | Foo::<N, { N + 2 }>
+ | ^^^^^^^^^^^^^^^^^^^ expected `{ N + 1 }`, found `{ N + 2 }`
+ |
+ = note: expected type `{ N + 1 }`
+ found type `{ N + 2 }`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#![feature(const_evaluatable_checked, const_generics, const_generics_defaults)]
+#![allow(incomplete_features)]
+
+pub struct Foo<const N: usize, const M: usize = { N + 1 }>;
+pub fn needs_evaluatable_bound<const N1: usize>() -> Foo<N1> {
+ //~^ error: unconstrained generic constant
+ loop {}
+}
+pub fn has_evaluatable_bound<const N1: usize>() -> Foo<N1> where [(); N1 + 1]: {
+ loop {}
+}
+
+type FooAlias<const N: usize, const NP: usize = { N + 1 }> = [(); NP];
+fn needs_evaluatable_bound_alias<T, const N: usize>() -> FooAlias<N>
+{
+ //~^^ error: unconstrained generic constant
+ todo!()
+}
+fn has_evaluatable_bound_alias<const N: usize>() -> FooAlias<N>
+where [(); N + 1]: {
+ todo!()
+}
+
+fn main() {}
--- /dev/null
+error: unconstrained generic constant
+ --> $DIR/cec-generic-default.rs:5:54
+ |
+LL | pub fn needs_evaluatable_bound<const N1: usize>() -> Foo<N1> {
+ | ^^^^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:`
+
+error: unconstrained generic constant
+ --> $DIR/cec-generic-default.rs:14:58
+ |
+LL | fn needs_evaluatable_bound_alias<T, const N: usize>() -> FooAlias<N>
+ | ^^^^^^^^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:`
+
+error: aborting due to 2 previous errors
+
+++ /dev/null
-error: constant expression depends on a generic parameter
- --> $DIR/issue-61522-array-len-succ.rs:6:40
- |
-LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
- | ^^^^^^^^^^^^^^^
- |
- = note: this may fail depending on what value the parameter takes
-
-error: constant expression depends on a generic parameter
- --> $DIR/issue-61522-array-len-succ.rs:11:24
- |
-LL | fn inner(&self) -> &[u8; COUNT + 1] {
- | ^^^^^^^^^^^^^^^^
- |
- = note: this may fail depending on what value the parameter takes
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-error: generic parameters may not be used in const operations
- --> $DIR/issue-61522-array-len-succ.rs:6:45
- |
-LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
- | ^^^^^ cannot perform const operation using `COUNT`
- |
- = help: const parameters may only be used as standalone arguments, i.e. `COUNT`
- = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
-
-error: generic parameters may not be used in const operations
- --> $DIR/issue-61522-array-len-succ.rs:11:30
- |
-LL | fn inner(&self) -> &[u8; COUNT + 1] {
- | ^^^^^ cannot perform const operation using `COUNT`
- |
- = help: const parameters may only be used as standalone arguments, i.e. `COUNT`
- = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-// revisions: full min
-
-#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(full, allow(incomplete_features))]
-
-pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
-//[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters may not be used
-
-impl<const COUNT: usize> MyArray<COUNT> {
- fn inner(&self) -> &[u8; COUNT + 1] {
- //[full]~^ ERROR constant expression depends on a generic parameter
- //[min]~^^ ERROR generic parameters may not be used
- &self.0
- }
-}
-
-fn main() {}
+++ /dev/null
-error: `&'static str` is forbidden as the type of a const generic parameter
- --> $DIR/issue-66596-impl-trait-for-str-const-arg.rs:8:25
- |
-LL | trait Trait<const NAME: &'static str> {
- | ^^^^^^^^^^^^
- |
- = note: the only supported types are integers, `bool` and `char`
- = help: more complex types are supported with `#![feature(const_generics)]`
-
-error: aborting due to previous error
-
+++ /dev/null
-//[full] check-pass
-// revisions: full min
-
-#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(full, allow(incomplete_features))]
-
-
-trait Trait<const NAME: &'static str> {
-//[min]~^ ERROR `&'static str` is forbidden
- type Assoc;
-}
-
-impl Trait<"0"> for () {
- type Assoc = ();
-}
-
-fn main() {
- let _: <() as Trait<"0">>::Assoc = ();
-}
+++ /dev/null
-warning: cannot use constants which depend on generic parameters in types
- --> $DIR/issue-67375.rs:8:12
- |
-LL | inner: [(); { [|_: &T| {}; 0].len() }],
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: `#[warn(const_evaluatable_unchecked)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
-
-error[E0392]: parameter `T` is never used
- --> $DIR/issue-67375.rs:6:12
- |
-LL | struct Bug<T> {
- | ^ unused parameter
- |
- = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
- = help: if you intended `T` to be a const parameter, use `const T: usize` instead
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0392`.
+++ /dev/null
-error: generic parameters may not be used in const operations
- --> $DIR/issue-67375.rs:8:25
- |
-LL | inner: [(); { [|_: &T| {}; 0].len() }],
- | ^ cannot perform const operation using `T`
- |
- = note: type parameters may not be used in const expressions
- = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
-
-error[E0392]: parameter `T` is never used
- --> $DIR/issue-67375.rs:6:12
- |
-LL | struct Bug<T> {
- | ^ unused parameter
- |
- = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
- = help: if you intended `T` to be a const parameter, use `const T: usize` instead
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0392`.
+++ /dev/null
-// revisions: full min
-
-#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(full, feature(const_generics))]
-
-struct Bug<T> {
- //~^ ERROR parameter `T` is never used
- inner: [(); { [|_: &T| {}; 0].len() }],
- //[min]~^ ERROR generic parameters may not be used in const operations
- //[full]~^^ WARN cannot use constants which depend on generic parameters in types
- //[full]~^^^ WARN this was previously accepted by the compiler
-}
-
-fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-67945-1.rs:13:20
- |
-LL | struct Bug<S> {
- | - this type parameter
-...
-LL | let x: S = MaybeUninit::uninit();
- | - ^^^^^^^^^^^^^^^^^^^^^ expected type parameter `S`, found union `MaybeUninit`
- | |
- | expected due to this
- |
- = note: expected type parameter `S`
- found union `MaybeUninit<_>`
-
-error[E0392]: parameter `S` is never used
- --> $DIR/issue-67945-1.rs:10:12
- |
-LL | struct Bug<S> {
- | ^ unused parameter
- |
- = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
- = help: if you intended `S` to be a const parameter, use `const S: usize` instead
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0308, E0392.
-For more information about an error, try `rustc --explain E0308`.
+++ /dev/null
-error: generic parameters may not be used in const operations
- --> $DIR/issue-67945-1.rs:13:16
- |
-LL | let x: S = MaybeUninit::uninit();
- | ^ cannot perform const operation using `S`
- |
- = note: type parameters may not be used in const expressions
- = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
-
-error: generic parameters may not be used in const operations
- --> $DIR/issue-67945-1.rs:16:45
- |
-LL | let b = &*(&x as *const _ as *const S);
- | ^ cannot perform const operation using `S`
- |
- = note: type parameters may not be used in const expressions
- = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
-
-error[E0392]: parameter `S` is never used
- --> $DIR/issue-67945-1.rs:10:12
- |
-LL | struct Bug<S> {
- | ^ unused parameter
- |
- = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
- = help: if you intended `S` to be a const parameter, use `const S: usize` instead
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0392`.
+++ /dev/null
-// revisions: full min
-
-#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(full, feature(const_generics))]
-
-use std::marker::PhantomData;
-
-use std::mem::{self, MaybeUninit};
-
-struct Bug<S> {
- //~^ ERROR parameter `S` is never used
- A: [(); {
- let x: S = MaybeUninit::uninit();
- //[min]~^ ERROR generic parameters may not be used in const operations
- //[full]~^^ ERROR mismatched types
- let b = &*(&x as *const _ as *const S);
- //[min]~^ ERROR generic parameters may not be used in const operations
- 0
- }],
-}
-
-fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-67945-2.rs:11:20
- |
-LL | struct Bug<S> {
- | - this type parameter
-...
-LL | let x: S = MaybeUninit::uninit();
- | - ^^^^^^^^^^^^^^^^^^^^^ expected type parameter `S`, found union `MaybeUninit`
- | |
- | expected due to this
- |
- = note: expected type parameter `S`
- found union `MaybeUninit<_>`
-
-error[E0392]: parameter `S` is never used
- --> $DIR/issue-67945-2.rs:8:12
- |
-LL | struct Bug<S> {
- | ^ unused parameter
- |
- = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
- = help: if you intended `S` to be a const parameter, use `const S: usize` instead
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0308, E0392.
-For more information about an error, try `rustc --explain E0308`.
+++ /dev/null
-error: generic parameters may not be used in const operations
- --> $DIR/issue-67945-2.rs:11:16
- |
-LL | let x: S = MaybeUninit::uninit();
- | ^ cannot perform const operation using `S`
- |
- = note: type parameters may not be used in const expressions
- = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
-
-error: generic parameters may not be used in const operations
- --> $DIR/issue-67945-2.rs:14:45
- |
-LL | let b = &*(&x as *const _ as *const S);
- | ^ cannot perform const operation using `S`
- |
- = note: type parameters may not be used in const expressions
- = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
-
-error[E0392]: parameter `S` is never used
- --> $DIR/issue-67945-2.rs:8:12
- |
-LL | struct Bug<S> {
- | ^ unused parameter
- |
- = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
- = help: if you intended `S` to be a const parameter, use `const S: usize` instead
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0392`.
+++ /dev/null
-// revisions: full min
-
-#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(full, feature(const_generics))]
-
-use std::mem::MaybeUninit;
-
-struct Bug<S> {
- //~^ ERROR parameter `S` is never used
- A: [(); {
- let x: S = MaybeUninit::uninit();
- //[min]~^ ERROR generic parameters may not be used in const operations
- //[full]~^^ ERROR mismatched types
- let b = &*(&x as *const _ as *const S);
- //[min]~^ ERROR generic parameters may not be used in const operations
- 0
- }],
-}
-
-fn main() {}
+++ /dev/null
-error: constant expression depends on a generic parameter
- --> $DIR/issue-67945-3.rs:7:8
- |
-LL | A: [(); {
- | ________^
-LL | |
-LL | | let x: Option<Box<Self>> = None;
-LL | |
-LL | | 0
-LL | | }],
- | |______^
- |
- = note: this may fail depending on what value the parameter takes
-
-error: aborting due to previous error
-
+++ /dev/null
-error: generic `Self` types are currently not permitted in anonymous constants
- --> $DIR/issue-67945-3.rs:9:27
- |
-LL | let x: Option<Box<Self>> = None;
- | ^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-// revisions: full min
-
-#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(full, feature(const_generics))]
-
-struct Bug<S: ?Sized> {
- A: [(); {
- //[full]~^ ERROR constant expression depends on a generic parameter
- let x: Option<Box<Self>> = None;
- //[min]~^ ERROR generic `Self` types are currently not permitted in anonymous constants
- 0
- }],
- B: S
-}
-
-fn main() {}
+++ /dev/null
-// aux-build:impl-const.rs
-// run-pass
-// revisions: full min
-
-#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(full, allow(incomplete_features))]
-
-extern crate impl_const;
-
-use impl_const::*;
-
-pub fn main() {
- let n = Num::<5>;
- n.five();
-}
+++ /dev/null
-// build-pass
-// revisions: full min
-
-#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(full, allow(incomplete_features))]
-
-pub fn works() {
- let array/*: [_; _]*/ = default_array();
- let _: [_; 4] = array;
- Foo::foo(&array);
-}
-
-pub fn didnt_work() {
- let array/*: [_; _]*/ = default_array();
- Foo::foo(&array);
- let _: [_; 4] = array;
-}
-
-trait Foo {
- fn foo(&self) {}
-}
-
-impl Foo for [i32; 4] {}
-impl Foo for [i64; 8] {}
-
-// Only needed because `[_; _]` is not valid type syntax.
-fn default_array<T, const N: usize>() -> [T; N]
-where
- [T; N]: Default,
-{
- Default::default()
-}
-
-fn main() {
- works();
- didnt_work();
-}
+++ /dev/null
-// build-pass
-// revisions: full min
-
-#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(full, allow(incomplete_features))]
-
-fn works() {
- let array/*: [u8; _]*/ = default_byte_array();
- let _: [_; 4] = array;
- Foo::foo(&array);
-}
-
-fn didnt_work() {
- let array/*: [u8; _]*/ = default_byte_array();
- Foo::foo(&array);
- let _: [_; 4] = array;
-}
-
-trait Foo<T> {
- fn foo(&self) {}
-}
-
-impl Foo<i32> for [u8; 4] {}
-impl Foo<i64> for [u8; 8] {}
-
-// Only needed because `[u8; _]` is not valid type syntax.
-fn default_byte_array<const N: usize>() -> [u8; N]
-where
- [u8; N]: Default,
-{
- Default::default()
-}
-
-fn main() {
- works();
- didnt_work();
-}
+++ /dev/null
-// check-pass
-
-#![feature(const_generics)]
-#![allow(incomplete_features, const_evaluatable_unchecked)]
-
-use std::marker::PhantomData;
-
-struct DataHolder<T> {
- item: T,
-}
-
-impl<T: Copy> DataHolder<T> {
- const ITEM_IS_COPY: [(); 1 - {
- trait NotCopy {
- const VALUE: bool = false;
- }
-
- impl<__Type: ?Sized> NotCopy for __Type {}
-
- struct IsCopy<__Type: ?Sized>(PhantomData<__Type>);
-
- impl<__Type> IsCopy<__Type>
- where
- __Type: Sized + Copy,
- {
- const VALUE: bool = true;
- }
-
- <IsCopy<T>>::VALUE
- } as usize] = [];
-}
-
-fn main() {}
+++ /dev/null
-// check-pass
-// revisions: full min
-
-#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(full, allow(incomplete_features))]
-
-pub trait Foo<const B: bool> {}
-pub fn bar<T: Foo<{ true }>>() {}
-
-fn main() {}
+++ /dev/null
-// run-pass
-#![feature(const_evaluatable_checked)]
-#![feature(const_generics)]
-#![allow(incomplete_features)]
-
-trait Foo {}
-
-impl<const N: usize> Foo for [(); N] where Self: FooImpl<{ N == 0 }> {}
-
-trait FooImpl<const IS_ZERO: bool> {}
-
-impl FooImpl<{ 0u8 == 0u8 }> for [(); 0] {}
-
-impl<const N: usize> FooImpl<{ 0u8 != 0u8 }> for [(); N] {}
-
-fn foo<T: Foo>(_v: T) {}
-
-fn main() {
- foo([]);
- foo([()]);
-}
+++ /dev/null
-// edition:2018
-// check-pass
-// revisions: full min
-#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(full, allow(incomplete_features))]
-
-const SIZE: usize = 16;
-
-struct Bar<const H: usize> {}
-
-struct Foo<const H: usize> {}
-
-impl<const H: usize> Foo<H> {
- async fn biz(_: &[[u8; SIZE]]) -> Vec<()> {
- vec![]
- }
-
- pub async fn baz(&self) -> Bar<H> {
- Self::biz(&vec![]).await;
- Bar {}
- }
-}
-
-fn main() { }
+++ /dev/null
-// ignore-test
-// FIXME(const_generics): This test causes an ICE after reverting #76030.
-
-#![allow(incomplete_features)]
-#![feature(const_generics)]
-
-struct Bug<const S: &'static str>;
-
-fn main() {
- let b: Bug::<{
- unsafe {
- // FIXME(const_generics): Decide on how to deal with invalid values as const params.
- std::mem::transmute::<&[u8], &str>(&[0xC0, 0xC1, 0xF5])
- }
- }>;
-}
+++ /dev/null
-#![feature(const_generics, const_evaluatable_checked)]
-#![allow(incomplete_features)]
-
-// This test is a minimized reproduction for #79518 where
-// during error handling for the type mismatch we would try
-// to evaluate std::mem::size_of::<Self::Assoc> causing an ICE
-
-trait Foo {
- type Assoc: PartialEq;
- const AssocInstance: Self::Assoc;
-
- fn foo()
- where
- [(); std::mem::size_of::<Self::Assoc>()]: ,
- {
- Self::AssocInstance == [(); std::mem::size_of::<Self::Assoc>()];
- //~^ Error: mismatched types
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-79518-default_trait_method_normalization.rs:16:32
- |
-LL | Self::AssocInstance == [(); std::mem::size_of::<Self::Assoc>()];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found array `[(); _]`
- |
- = note: expected associated type `<Self as Foo>::Assoc`
- found array `[(); _]`
- = help: consider constraining the associated type `<Self as Foo>::Assoc` to `[(); _]` or calling a method that returns `<Self as Foo>::Assoc`
- = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// check-pass
-#![feature(const_generics, const_evaluatable_checked)]
-#![allow(incomplete_features)]
-
-// This tests that the correct `param_env` is used so that
-// attempting to normalize `Self::N` does not cause an ICE.
-
-pub struct Foo<const N: usize>;
-
-impl<const N: usize> Foo<N> {
- pub fn foo() {}
-}
-
-pub trait Bar {
- const N: usize;
- fn bar()
- where
- [(); Self::N]: ,
- {
- Foo::<{ Self::N }>::foo();
- }
-}
-
-fn main() {}
+++ /dev/null
-// Regression test for the ICE described in #86820.
-
-#![allow(unused,dead_code)]
-use std::ops::BitAnd;
-
-const C: fn() = || is_set();
-fn is_set() {
- 0xffu8.bit::<0>();
-}
-
-trait Bits {
- fn bit<const I : u8>(self) -> bool;
- //~^ NOTE: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8`
-}
-
-impl Bits for u8 {
- fn bit<const I : usize>(self) -> bool {
- //~^ ERROR: method `bit` has an incompatible const parameter type for trait [E0053]
- let i = 1 << I;
- let mask = u8::from(i);
- mask & self == mask
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0053]: method `bit` has an incompatible const parameter type for trait
- --> $DIR/issue-86820.rs:17:18
- |
-LL | fn bit<const I : usize>(self) -> bool {
- | ^
- |
-note: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8`
- --> $DIR/issue-86820.rs:12:18
- |
-LL | fn bit<const I : u8>(self) -> bool;
- | ^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0053`.
--- /dev/null
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+
+pub struct Num<const N: usize>;
+
+// Braces around const expression causes crash
+impl Num<{5}> {
+ pub fn five(&self) {
+ }
+}
--- /dev/null
+error: constant expression depends on a generic parameter
+ --> $DIR/issue-61522-array-len-succ.rs:6:40
+ |
+LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+ --> $DIR/issue-61522-array-len-succ.rs:11:24
+ |
+LL | fn inner(&self) -> &[u8; COUNT + 1] {
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-61522-array-len-succ.rs:6:45
+ |
+LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
+ | ^^^^^ cannot perform const operation using `COUNT`
+ |
+ = help: const parameters may only be used as standalone arguments, i.e. `COUNT`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
+
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-61522-array-len-succ.rs:11:30
+ |
+LL | fn inner(&self) -> &[u8; COUNT + 1] {
+ | ^^^^^ cannot perform const operation using `COUNT`
+ |
+ = help: const parameters may only be used as standalone arguments, i.e. `COUNT`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+
+pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
+//[full]~^ ERROR constant expression depends on a generic parameter
+//[min]~^^ ERROR generic parameters may not be used
+
+impl<const COUNT: usize> MyArray<COUNT> {
+ fn inner(&self) -> &[u8; COUNT + 1] {
+ //[full]~^ ERROR constant expression depends on a generic parameter
+ //[min]~^^ ERROR generic parameters may not be used
+ &self.0
+ }
+}
+
+fn main() {}
--- /dev/null
+error: `&'static str` is forbidden as the type of a const generic parameter
+ --> $DIR/issue-66596-impl-trait-for-str-const-arg.rs:8:25
+ |
+LL | trait Trait<const NAME: &'static str> {
+ | ^^^^^^^^^^^^
+ |
+ = note: the only supported types are integers, `bool` and `char`
+ = help: more complex types are supported with `#![feature(const_generics)]`
+
+error: aborting due to previous error
+
--- /dev/null
+//[full] check-pass
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+
+
+trait Trait<const NAME: &'static str> {
+//[min]~^ ERROR `&'static str` is forbidden
+ type Assoc;
+}
+
+impl Trait<"0"> for () {
+ type Assoc = ();
+}
+
+fn main() {
+ let _: <() as Trait<"0">>::Assoc = ();
+}
--- /dev/null
+warning: cannot use constants which depend on generic parameters in types
+ --> $DIR/issue-67375.rs:8:12
+ |
+LL | inner: [(); { [|_: &T| {}; 0].len() }],
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(const_evaluatable_unchecked)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
+
+error[E0392]: parameter `T` is never used
+ --> $DIR/issue-67375.rs:6:12
+ |
+LL | struct Bug<T> {
+ | ^ unused parameter
+ |
+ = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `T` to be a const parameter, use `const T: usize` instead
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0392`.
--- /dev/null
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-67375.rs:8:25
+ |
+LL | inner: [(); { [|_: &T| {}; 0].len() }],
+ | ^ cannot perform const operation using `T`
+ |
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
+
+error[E0392]: parameter `T` is never used
+ --> $DIR/issue-67375.rs:6:12
+ |
+LL | struct Bug<T> {
+ | ^ unused parameter
+ |
+ = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `T` to be a const parameter, use `const T: usize` instead
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
--- /dev/null
+// revisions: full min
+
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(full, feature(const_generics))]
+
+struct Bug<T> {
+ //~^ ERROR parameter `T` is never used
+ inner: [(); { [|_: &T| {}; 0].len() }],
+ //[min]~^ ERROR generic parameters may not be used in const operations
+ //[full]~^^ WARN cannot use constants which depend on generic parameters in types
+ //[full]~^^^ WARN this was previously accepted by the compiler
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-67945-1.rs:13:20
+ |
+LL | struct Bug<S> {
+ | - this type parameter
+...
+LL | let x: S = MaybeUninit::uninit();
+ | - ^^^^^^^^^^^^^^^^^^^^^ expected type parameter `S`, found union `MaybeUninit`
+ | |
+ | expected due to this
+ |
+ = note: expected type parameter `S`
+ found union `MaybeUninit<_>`
+
+error[E0392]: parameter `S` is never used
+ --> $DIR/issue-67945-1.rs:10:12
+ |
+LL | struct Bug<S> {
+ | ^ unused parameter
+ |
+ = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `S` to be a const parameter, use `const S: usize` instead
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0392.
+For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-67945-1.rs:13:16
+ |
+LL | let x: S = MaybeUninit::uninit();
+ | ^ cannot perform const operation using `S`
+ |
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
+
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-67945-1.rs:16:45
+ |
+LL | let b = &*(&x as *const _ as *const S);
+ | ^ cannot perform const operation using `S`
+ |
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
+
+error[E0392]: parameter `S` is never used
+ --> $DIR/issue-67945-1.rs:10:12
+ |
+LL | struct Bug<S> {
+ | ^ unused parameter
+ |
+ = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `S` to be a const parameter, use `const S: usize` instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
--- /dev/null
+// revisions: full min
+
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(full, feature(const_generics))]
+
+use std::marker::PhantomData;
+
+use std::mem::{self, MaybeUninit};
+
+struct Bug<S> {
+ //~^ ERROR parameter `S` is never used
+ A: [(); {
+ let x: S = MaybeUninit::uninit();
+ //[min]~^ ERROR generic parameters may not be used in const operations
+ //[full]~^^ ERROR mismatched types
+ let b = &*(&x as *const _ as *const S);
+ //[min]~^ ERROR generic parameters may not be used in const operations
+ 0
+ }],
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-67945-2.rs:11:20
+ |
+LL | struct Bug<S> {
+ | - this type parameter
+...
+LL | let x: S = MaybeUninit::uninit();
+ | - ^^^^^^^^^^^^^^^^^^^^^ expected type parameter `S`, found union `MaybeUninit`
+ | |
+ | expected due to this
+ |
+ = note: expected type parameter `S`
+ found union `MaybeUninit<_>`
+
+error[E0392]: parameter `S` is never used
+ --> $DIR/issue-67945-2.rs:8:12
+ |
+LL | struct Bug<S> {
+ | ^ unused parameter
+ |
+ = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `S` to be a const parameter, use `const S: usize` instead
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0392.
+For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-67945-2.rs:11:16
+ |
+LL | let x: S = MaybeUninit::uninit();
+ | ^ cannot perform const operation using `S`
+ |
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
+
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-67945-2.rs:14:45
+ |
+LL | let b = &*(&x as *const _ as *const S);
+ | ^ cannot perform const operation using `S`
+ |
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
+
+error[E0392]: parameter `S` is never used
+ --> $DIR/issue-67945-2.rs:8:12
+ |
+LL | struct Bug<S> {
+ | ^ unused parameter
+ |
+ = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `S` to be a const parameter, use `const S: usize` instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
--- /dev/null
+// revisions: full min
+
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(full, feature(const_generics))]
+
+use std::mem::MaybeUninit;
+
+struct Bug<S> {
+ //~^ ERROR parameter `S` is never used
+ A: [(); {
+ let x: S = MaybeUninit::uninit();
+ //[min]~^ ERROR generic parameters may not be used in const operations
+ //[full]~^^ ERROR mismatched types
+ let b = &*(&x as *const _ as *const S);
+ //[min]~^ ERROR generic parameters may not be used in const operations
+ 0
+ }],
+}
+
+fn main() {}
--- /dev/null
+error: constant expression depends on a generic parameter
+ --> $DIR/issue-67945-3.rs:7:8
+ |
+LL | A: [(); {
+ | ________^
+LL | |
+LL | | let x: Option<Box<Self>> = None;
+LL | |
+LL | | 0
+LL | | }],
+ | |______^
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error
+
--- /dev/null
+error: generic `Self` types are currently not permitted in anonymous constants
+ --> $DIR/issue-67945-3.rs:9:27
+ |
+LL | let x: Option<Box<Self>> = None;
+ | ^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// revisions: full min
+
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(full, feature(const_generics))]
+
+struct Bug<S: ?Sized> {
+ A: [(); {
+ //[full]~^ ERROR constant expression depends on a generic parameter
+ let x: Option<Box<Self>> = None;
+ //[min]~^ ERROR generic `Self` types are currently not permitted in anonymous constants
+ 0
+ }],
+ B: S
+}
+
+fn main() {}
--- /dev/null
+// aux-build:impl-const.rs
+// run-pass
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+
+extern crate impl_const;
+
+use impl_const::*;
+
+pub fn main() {
+ let n = Num::<5>;
+ n.five();
+}
--- /dev/null
+// build-pass
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+
+pub fn works() {
+ let array/*: [_; _]*/ = default_array();
+ let _: [_; 4] = array;
+ Foo::foo(&array);
+}
+
+pub fn didnt_work() {
+ let array/*: [_; _]*/ = default_array();
+ Foo::foo(&array);
+ let _: [_; 4] = array;
+}
+
+trait Foo {
+ fn foo(&self) {}
+}
+
+impl Foo for [i32; 4] {}
+impl Foo for [i64; 8] {}
+
+// Only needed because `[_; _]` is not valid type syntax.
+fn default_array<T, const N: usize>() -> [T; N]
+where
+ [T; N]: Default,
+{
+ Default::default()
+}
+
+fn main() {
+ works();
+ didnt_work();
+}
--- /dev/null
+// build-pass
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+
+fn works() {
+ let array/*: [u8; _]*/ = default_byte_array();
+ let _: [_; 4] = array;
+ Foo::foo(&array);
+}
+
+fn didnt_work() {
+ let array/*: [u8; _]*/ = default_byte_array();
+ Foo::foo(&array);
+ let _: [_; 4] = array;
+}
+
+trait Foo<T> {
+ fn foo(&self) {}
+}
+
+impl Foo<i32> for [u8; 4] {}
+impl Foo<i64> for [u8; 8] {}
+
+// Only needed because `[u8; _]` is not valid type syntax.
+fn default_byte_array<const N: usize>() -> [u8; N]
+where
+ [u8; N]: Default,
+{
+ Default::default()
+}
+
+fn main() {
+ works();
+ didnt_work();
+}
--- /dev/null
+// check-pass
+
+#![feature(const_generics)]
+#![allow(incomplete_features, const_evaluatable_unchecked)]
+
+use std::marker::PhantomData;
+
+struct DataHolder<T> {
+ item: T,
+}
+
+impl<T: Copy> DataHolder<T> {
+ const ITEM_IS_COPY: [(); 1 - {
+ trait NotCopy {
+ const VALUE: bool = false;
+ }
+
+ impl<__Type: ?Sized> NotCopy for __Type {}
+
+ struct IsCopy<__Type: ?Sized>(PhantomData<__Type>);
+
+ impl<__Type> IsCopy<__Type>
+ where
+ __Type: Sized + Copy,
+ {
+ const VALUE: bool = true;
+ }
+
+ <IsCopy<T>>::VALUE
+ } as usize] = [];
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+
+pub trait Foo<const B: bool> {}
+pub fn bar<T: Foo<{ true }>>() {}
+
+fn main() {}
--- /dev/null
+// run-pass
+#![feature(const_evaluatable_checked)]
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+trait Foo {}
+
+impl<const N: usize> Foo for [(); N] where Self: FooImpl<{ N == 0 }> {}
+
+trait FooImpl<const IS_ZERO: bool> {}
+
+impl FooImpl<{ 0u8 == 0u8 }> for [(); 0] {}
+
+impl<const N: usize> FooImpl<{ 0u8 != 0u8 }> for [(); N] {}
+
+fn foo<T: Foo>(_v: T) {}
+
+fn main() {
+ foo([]);
+ foo([()]);
+}
--- /dev/null
+// edition:2018
+// check-pass
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+
+const SIZE: usize = 16;
+
+struct Bar<const H: usize> {}
+
+struct Foo<const H: usize> {}
+
+impl<const H: usize> Foo<H> {
+ async fn biz(_: &[[u8; SIZE]]) -> Vec<()> {
+ vec![]
+ }
+
+ pub async fn baz(&self) -> Bar<H> {
+ Self::biz(&vec![]).await;
+ Bar {}
+ }
+}
+
+fn main() { }
--- /dev/null
+// ignore-test
+// FIXME(const_generics): This test causes an ICE after reverting #76030.
+
+#![allow(incomplete_features)]
+#![feature(const_generics)]
+
+struct Bug<const S: &'static str>;
+
+fn main() {
+ let b: Bug::<{
+ unsafe {
+ // FIXME(const_generics): Decide on how to deal with invalid values as const params.
+ std::mem::transmute::<&[u8], &str>(&[0xC0, 0xC1, 0xF5])
+ }
+ }>;
+}
--- /dev/null
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+// This test is a minimized reproduction for #79518 where
+// during error handling for the type mismatch we would try
+// to evaluate std::mem::size_of::<Self::Assoc> causing an ICE
+
+trait Foo {
+ type Assoc: PartialEq;
+ const AssocInstance: Self::Assoc;
+
+ fn foo()
+ where
+ [(); std::mem::size_of::<Self::Assoc>()]: ,
+ {
+ Self::AssocInstance == [(); std::mem::size_of::<Self::Assoc>()];
+ //~^ Error: mismatched types
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-79518-default_trait_method_normalization.rs:16:32
+ |
+LL | Self::AssocInstance == [(); std::mem::size_of::<Self::Assoc>()];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found array `[(); _]`
+ |
+ = note: expected associated type `<Self as Foo>::Assoc`
+ found array `[(); _]`
+ = help: consider constraining the associated type `<Self as Foo>::Assoc` to `[(); _]` or calling a method that returns `<Self as Foo>::Assoc`
+ = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// check-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+// This tests that the correct `param_env` is used so that
+// attempting to normalize `Self::N` does not cause an ICE.
+
+pub struct Foo<const N: usize>;
+
+impl<const N: usize> Foo<N> {
+ pub fn foo() {}
+}
+
+pub trait Bar {
+ const N: usize;
+ fn bar()
+ where
+ [(); Self::N]: ,
+ {
+ Foo::<{ Self::N }>::foo();
+ }
+}
+
+fn main() {}
--- /dev/null
+// Regression test for the ICE described in #86820.
+
+#![allow(unused,dead_code)]
+use std::ops::BitAnd;
+
+const C: fn() = || is_set();
+fn is_set() {
+ 0xffu8.bit::<0>();
+}
+
+trait Bits {
+ fn bit<const I : u8>(self) -> bool;
+ //~^ NOTE: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8`
+}
+
+impl Bits for u8 {
+ fn bit<const I : usize>(self) -> bool {
+ //~^ ERROR: method `bit` has an incompatible const parameter type for trait [E0053]
+ let i = 1 << I;
+ let mask = u8::from(i);
+ mask & self == mask
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0053]: method `bit` has an incompatible const parameter type for trait
+ --> $DIR/issue-86820.rs:17:18
+ |
+LL | fn bit<const I : usize>(self) -> bool {
+ | ^
+ |
+note: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8`
+ --> $DIR/issue-86820.rs:12:18
+ |
+LL | fn bit<const I : u8>(self) -> bool;
+ | ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
--- /dev/null
+// build-pass
+
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+#[derive(PartialEq, Eq)]
+pub struct UnitDims {
+ pub time: u8,
+ pub length: u8,
+}
+
+pub struct UnitValue<const DIMS: UnitDims>;
+
+impl<const DIMS: UnitDims> UnitValue<DIMS> {
+ fn crash() {}
+}
+
+fn main() {
+ UnitValue::<{ UnitDims { time: 1, length: 2 } }>::crash();
+}
// compile-flags: --target x86_64-unknown-uefi
// needs-llvm-components: x86
// rustc-env:CARGO=/usr/bin/cargo
-// rustc-env:RUSTUP_HOME=/home/bors/.rustup
#![no_core]
extern crate core;
//~^ ERROR can't find crate for `core`
error[E0463]: can't find crate for `core`
- --> $DIR/missing-std.rs:6:1
+ --> $DIR/missing-std.rs:5:1
|
LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^ can't find crate
LL | #[rustc_then_this_would_need(trait_def)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error: OK
+ --> $DIR/dep-graph-struct-signature.rs:31:9
+ |
+LL | #[rustc_then_this_would_need(fn_sig)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
error: OK
--> $DIR/dep-graph-struct-signature.rs:35:5
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error: OK
+ --> $DIR/dep-graph-struct-signature.rs:47:9
+ |
+LL | #[rustc_then_this_would_need(fn_sig)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: OK
+ --> $DIR/dep-graph-struct-signature.rs:48:9
+ |
+LL | #[rustc_then_this_would_need(typeck)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
error: OK
--> $DIR/dep-graph-struct-signature.rs:52:5
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error: OK
+ --> $DIR/dep-graph-struct-signature.rs:54:9
+ |
+LL | #[rustc_then_this_would_need(fn_sig)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: OK
+ --> $DIR/dep-graph-struct-signature.rs:55:9
+ |
+LL | #[rustc_then_this_would_need(typeck)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
error: OK
--> $DIR/dep-graph-struct-signature.rs:60:9
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error: no path from `WillChange` to `fn_sig`
+ --> $DIR/dep-graph-struct-signature.rs:76:9
+ |
+LL | #[rustc_then_this_would_need(fn_sig)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
error: no path from `WillChange` to `fn_sig`
--> $DIR/dep-graph-struct-signature.rs:80:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: OK
- --> $DIR/dep-graph-struct-signature.rs:31:9
- |
-LL | #[rustc_then_this_would_need(fn_sig)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: no path from `WillChange` to `fn_sig`
- --> $DIR/dep-graph-struct-signature.rs:76:9
- |
-LL | #[rustc_then_this_would_need(fn_sig)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: OK
- --> $DIR/dep-graph-struct-signature.rs:47:9
- |
-LL | #[rustc_then_this_would_need(fn_sig)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: OK
- --> $DIR/dep-graph-struct-signature.rs:48:9
- |
-LL | #[rustc_then_this_would_need(typeck)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: OK
- --> $DIR/dep-graph-struct-signature.rs:54:9
- |
-LL | #[rustc_then_this_would_need(fn_sig)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: OK
- --> $DIR/dep-graph-struct-signature.rs:55:9
- |
-LL | #[rustc_then_this_would_need(typeck)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
error: aborting due to 22 previous errors
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error: OK
+ --> $DIR/dep-graph-type-alias.rs:35:5
+ |
+LL | #[rustc_then_this_would_need(fn_sig)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
error: no path from `TypeAlias` to `type_of`
--> $DIR/dep-graph-type-alias.rs:41:1
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error: OK
+ --> $DIR/dep-graph-type-alias.rs:43:5
+ |
+LL | #[rustc_then_this_would_need(fn_sig)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: OK
+ --> $DIR/dep-graph-type-alias.rs:44:5
+ |
+LL | #[rustc_then_this_would_need(typeck)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
error: OK
--> $DIR/dep-graph-type-alias.rs:48:1
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: OK
- --> $DIR/dep-graph-type-alias.rs:35:5
- |
-LL | #[rustc_then_this_would_need(fn_sig)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: OK
- --> $DIR/dep-graph-type-alias.rs:43:5
- |
-LL | #[rustc_then_this_would_need(fn_sig)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: OK
- --> $DIR/dep-graph-type-alias.rs:44:5
- |
-LL | #[rustc_then_this_would_need(typeck)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
error: aborting due to 12 previous errors
// ignore-wasm32-bare compiled with panic=abort by default
#![feature(generators, generator_trait)]
-#![feature(bindings_after_at)]
#![allow(unused_assignments)]
#![allow(unused_variables)]
error[E0038]: the trait `Trait` cannot be made into an object
- --> $DIR/E0038.rs:5:16
+ --> $DIR/E0038.rs:5:20
|
LL | fn call_foo(x: Box<dyn Trait>) {
- | ^^^^^^^^^^^^^^ `Trait` cannot be made into an object
+ | ^^^^^^^^^ `Trait` cannot be made into an object
|
= help: consider moving `foo` to another trait
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>
-error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature
- --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:9:18
+error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types` feature
+ --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:4:18
|
-LL | fn bar(self: *const Self);
+LL | fn foo(self: *const Self) {}
| ^^^^^^^^^^^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
= help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
-error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types` feature
- --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:4:18
+error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature
+ --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:9:18
|
-LL | fn foo(self: *const Self) {}
+LL | fn bar(self: *const Self);
| ^^^^^^^^^^^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
error[E0038]: the trait `NonObjectSafe1` cannot be made into an object
- --> $DIR/feature-gate-object_safe_for_dispatch.rs:18:38
+ --> $DIR/feature-gate-object_safe_for_dispatch.rs:18:39
|
LL | fn takes_non_object_safe_ref<T>(obj: &dyn NonObjectSafe1) {
- | ^^^^^^^^^^^^^^^^^^^ `NonObjectSafe1` cannot be made into an object
+ | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe1` 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/feature-gate-object_safe_for_dispatch.rs:4:23
| ^^^^^^^^^^^^^^^^^
error[E0038]: the trait `NonObjectSafe3` cannot be made into an object
- --> $DIR/feature-gate-object_safe_for_dispatch.rs:27:35
+ --> $DIR/feature-gate-object_safe_for_dispatch.rs:27:39
|
LL | fn takes_non_object_safe_box(obj: Box<dyn NonObjectSafe3>) {
- | ^^^^^^^^^^^^^^^^^^^^^^^ `NonObjectSafe3` cannot be made into an object
+ | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe3` cannot be made into an object
|
= help: consider moving `foo` to another trait
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>
error[E0038]: the trait `Foo` cannot be made into an object
- --> $DIR/gat-in-trait-path.rs:21:13
+ --> $DIR/gat-in-trait-path.rs:21:17
|
LL | fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
|
= help: consider moving `A` to another trait
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>
error[E0038]: the trait `X` cannot be made into an object
- --> $DIR/issue-67510-pass.rs:7:19
+ --> $DIR/issue-67510-pass.rs:7:23
|
LL | fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+ | ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
|
= help: consider moving `Y` to another trait
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>
--- /dev/null
+// build-pass
+
+#![feature(generic_associated_types)]
+
+trait Trait {
+ type Ref<'a>;
+}
+
+impl Trait for () {
+ type Ref<'a> = &'a i8;
+}
+
+struct RefRef<'a, T: Trait>(&'a <T as Trait>::Ref<'a>);
+
+fn wrap<'a, T: Trait>(reff: &'a <T as Trait>::Ref<'a>) -> RefRef<'a, T> {
+ RefRef(reff)
+}
+
+fn main() {}
error[E0038]: the trait `StreamingIterator` cannot be made into an object
- --> $DIR/trait-objects.rs:10:16
+ --> $DIR/trait-objects.rs:10:21
|
LL | fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object
|
= help: consider moving `Item` to another trait
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>
fn cycle1() -> impl Clone {
//~^ ERROR cycle detected
send(cycle2().clone());
- //~^ ERROR cannot be sent between threads safely
Rc::new(Cell::new(5))
}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
note: ...which requires computing type of `cycle2::{opaque#0}`...
- --> $DIR/auto-trait-leak.rs:20:16
+ --> $DIR/auto-trait-leak.rs:19:16
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^
note: ...which requires borrow-checking `cycle2`...
- --> $DIR/auto-trait-leak.rs:20:1
+ --> $DIR/auto-trait-leak.rs:19:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle2`...
- --> $DIR/auto-trait-leak.rs:20:1
+ --> $DIR/auto-trait-leak.rs:19:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing MIR for `cycle2`...
- --> $DIR/auto-trait-leak.rs:20:1
+ --> $DIR/auto-trait-leak.rs:19:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `cycle2`...
- --> $DIR/auto-trait-leak.rs:20:1
+ --> $DIR/auto-trait-leak.rs:19:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for `cycle2`...
- --> $DIR/auto-trait-leak.rs:20:1
+ --> $DIR/auto-trait-leak.rs:19:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle2`...
- --> $DIR/auto-trait-leak.rs:20:1
+ --> $DIR/auto-trait-leak.rs:19:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
LL | | }
| |_^
-error[E0277]: `Rc<String>` cannot be sent between threads safely
- --> $DIR/auto-trait-leak.rs:14:5
- |
-LL | fn send<T: Send>(_: T) {}
- | ---- required by this bound in `send`
-...
-LL | send(cycle2().clone());
- | ^^^^ `Rc<String>` cannot be sent between threads safely
-...
-LL | fn cycle2() -> impl Clone {
- | ---------- within this `impl Clone`
- |
- = help: within `impl Clone`, the trait `Send` is not implemented for `Rc<String>`
- = note: required because it appears within the type `impl Clone`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0277, E0391.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0391`.
--- /dev/null
+#![feature(min_type_alias_impl_trait)]
+
+type X<'a, 'b> = impl std::fmt::Debug;
+
+fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) {
+ //~^ ERROR concrete type differs from previous defining opaque type use
+ (a, a)
+}
+
+fn main() {}
--- /dev/null
+error: concrete type differs from previous defining opaque type use
+ --> $DIR/issue-86465.rs:5:1
+ |
+LL | fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&'a u32`, got `&'b u32`
+ |
+note: previous use here
+ --> $DIR/issue-86465.rs:5:1
+ |
+LL | fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+use std::fmt::Debug;
+
+fn main() {
+ let x: Option<impl Debug> = Some(44_u32);
+ //~^ `impl Trait` not allowed outside of function and method return types
+ println!("{:?}", x);
+}
--- /dev/null
+error[E0562]: `impl Trait` not allowed outside of function and method return types
+ --> $DIR/issue-54600.rs:4:19
+ |
+LL | let x: Option<impl Debug> = Some(44_u32);
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0562`.
--- /dev/null
+use std::ops::Add;
+
+fn main() {
+ let i: i32 = 0;
+ let j: &impl Add = &i;
+ //~^ `impl Trait` not allowed outside of function and method return types
+}
--- /dev/null
+error[E0562]: `impl Trait` not allowed outside of function and method return types
+ --> $DIR/issue-54840.rs:5:13
+ |
+LL | let j: &impl Add = &i;
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0562`.
--- /dev/null
+#![feature(generators, generator_trait, never_type)]
+
+use std::ops::Generator;
+
+fn mk_gen() -> impl Generator<Return=!, Yield=()> {
+ || { loop { yield; } }
+}
+
+fn main() {
+ let gens: [impl Generator<Return=!, Yield=()>;2] = [ mk_gen(), mk_gen() ];
+ //~^ `impl Trait` not allowed outside of function and method return types
+}
--- /dev/null
+error[E0562]: `impl Trait` not allowed outside of function and method return types
+ --> $DIR/issue-58504.rs:10:16
+ |
+LL | let gens: [impl Generator<Return=!, Yield=()>;2] = [ mk_gen(), mk_gen() ];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0562`.
--- /dev/null
+trait Lam {}
+
+pub struct B;
+impl Lam for B {}
+pub struct Wrap<T>(T);
+
+const _A: impl Lam = {
+ //~^ `impl Trait` not allowed outside of function and method return types
+ let x: Wrap<impl Lam> = Wrap(B);
+ //~^ `impl Trait` not allowed outside of function and method return types
+ x.0
+};
+
+fn main() {}
--- /dev/null
+error[E0562]: `impl Trait` not allowed outside of function and method return types
+ --> $DIR/issue-58956.rs:7:11
+ |
+LL | const _A: impl Lam = {
+ | ^^^^^^^^
+
+error[E0562]: `impl Trait` not allowed outside of function and method return types
+ --> $DIR/issue-58956.rs:9:17
+ |
+LL | let x: Wrap<impl Lam> = Wrap(B);
+ | ^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0562`.
--- /dev/null
+fn main() {
+ let x : (impl Copy,) = (true,);
+ //~^ `impl Trait` not allowed outside of function and method return types
+}
--- /dev/null
+error[E0562]: `impl Trait` not allowed outside of function and method return types
+ --> $DIR/issue-70971.rs:2:14
+ |
+LL | let x : (impl Copy,) = (true,);
+ | ^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0562`.
--- /dev/null
+struct Bug {
+ V1: [(); {
+ let f: impl core::future::Future<Output = u8> = async { 1 };
+ //~^ `impl Trait` not allowed outside of function and method return types
+ //~| expected identifier
+ 1
+ }],
+}
+
+fn main() {}
--- /dev/null
+error: expected identifier, found `1`
+ --> $DIR/issue-79099.rs:3:65
+ |
+LL | let f: impl core::future::Future<Output = u8> = async { 1 };
+ | ----- ^ expected identifier
+ | |
+ | `async` blocks are only allowed in Rust 2018 or later
+ |
+ = help: set `edition = "2018"` in `Cargo.toml`
+ = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0562]: `impl Trait` not allowed outside of function and method return types
+ --> $DIR/issue-79099.rs:3:16
+ |
+LL | let f: impl core::future::Future<Output = u8> = async { 1 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0562`.
--- /dev/null
+trait Trait {}
+impl Trait for () {}
+
+fn foo<'a: 'a>() {
+ let _x: impl Trait = ();
+ //~^ `impl Trait` not allowed outside of function and method return types
+}
+
+fn main() {}
--- /dev/null
+error[E0562]: `impl Trait` not allowed outside of function and method return types
+ --> $DIR/issue-84919.rs:5:13
+ |
+LL | let _x: impl Trait = ();
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0562`.
--- /dev/null
+#![feature(unboxed_closures)]
+#![feature(min_type_alias_impl_trait)]
+
+type FunType = impl Fn<()>;
+//~^ could not find defining uses
+static STATIC_FN: FunType = some_fn;
+//~^ mismatched types
+
+fn some_fn() {}
+
+fn main() {
+ let _: <FunType as FnOnce<()>>::Output = STATIC_FN();
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-86201.rs:6:29
+ |
+LL | type FunType = impl Fn<()>;
+ | ----------- the expected opaque type
+LL |
+LL | static STATIC_FN: FunType = some_fn;
+ | ^^^^^^^ expected opaque type, found fn item
+ |
+ = note: expected opaque type `impl Fn<()>`
+ found fn item `fn() {some_fn}`
+
+error: could not find defining uses
+ --> $DIR/issue-86201.rs:4:16
+ |
+LL | type FunType = impl Fn<()>;
+ | ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+static x: impl Fn(&str) -> Result<&str, ()> = move |source| {
+ //~^ `impl Trait` not allowed outside of function and method return types
+ let res = (move |source| Ok(source))(source);
+ let res = res.or((move |source| Ok(source))(source));
+ res
+};
+
+fn main() {}
--- /dev/null
+error[E0562]: `impl Trait` not allowed outside of function and method return types
+ --> $DIR/issue-86642.rs:1:11
+ |
+LL | static x: impl Fn(&str) -> Result<&str, ()> = move |source| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0562`.
--- /dev/null
+trait Trait {
+ type Output;
+}
+impl Trait for () {
+ type Output = i32;
+}
+
+struct Struct<F>(F);
+impl<F> Struct<F> {
+ pub fn new(_: F) -> Self {
+ todo!()
+ }
+}
+
+fn main() {
+ let _do_not_waste: Struct<impl Trait<Output = i32>> = Struct::new(());
+ //~^ `impl Trait` not allowed outside of function and method return types
+}
--- /dev/null
+error[E0562]: `impl Trait` not allowed outside of function and method return types
+ --> $DIR/issue-87295.rs:16:31
+ |
+LL | let _do_not_waste: Struct<impl Trait<Output = i32>> = Struct::new(());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0562`.
error[E0277]: the trait bound `isize: HasState` is not satisfied
- --> $DIR/issue-18611.rs:1:4
+ --> $DIR/issue-18611.rs:1:18
|
LL | fn add_state(op: <isize as HasState>::State) {
- | ^^^^^^^^^ the trait `HasState` is not implemented for `isize`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize`
+...
+LL | trait HasState {
+ | -------------- required by this bound in `HasState`
error: aborting due to previous error
error[E0038]: the trait `Bar` cannot be made into an object
- --> $DIR/issue-18959.rs:11:11
+ --> $DIR/issue-18959.rs:11:12
|
LL | fn foo(b: &dyn Bar) {
- | ^^^^^^^^ `Bar` cannot be made into an object
+ | ^^^^^^^ `Bar` cannot be made into an object
|
= help: consider moving `foo` to another trait
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>
error[E0038]: the trait `Qiz` cannot be made into an object
- --> $DIR/issue-19380.rs:11:9
+ --> $DIR/issue-19380.rs:11:29
|
LL | foos: &'static [&'static (dyn Qiz + 'static)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Qiz` cannot be made into an object
+ | ^^^^^^^^^^^^^^^^^ `Qiz` 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-19380.rs:2:6
= note: 127 redundant requirements hidden
= note: required because of the requirements on the impl of `Foo` for `NoData<T>`
+error[E0275]: overflow evaluating the requirement `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo`
+ --> $DIR/issue-20413.rs:8:36
+ |
+LL | trait Foo {
+ | --------- required by this bound in `Foo`
+...
+LL | impl<T> Foo for T where NoData<T>: Foo {
+ | ^^^
+ |
+ = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`)
+note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+ --> $DIR/issue-20413.rs:8:9
+ |
+LL | impl<T> Foo for T where NoData<T>: Foo {
+ | ^^^ ^
+ = note: 127 redundant requirements hidden
+ = note: required because of the requirements on the impl of `Foo` for `NoData<T>`
+
error[E0275]: overflow evaluating the requirement `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Baz`
--> $DIR/issue-20413.rs:28:42
|
= note: 126 redundant requirements hidden
= note: required because of the requirements on the impl of `Baz` for `EvenLessData<T>`
-error[E0275]: overflow evaluating the requirement `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Bar`
- --> $DIR/issue-20413.rs:36:42
- |
-LL | trait Bar {
- | --------- required by this bound in `Bar`
-...
-LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
- | ^^^
- |
- = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`)
-note: required because of the requirements on the impl of `Baz` for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- --> $DIR/issue-20413.rs:36:9
- |
-LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
- | ^^^ ^
-note: required because of the requirements on the impl of `Bar` for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- --> $DIR/issue-20413.rs:28:9
- |
-LL | impl<T> Bar for T where EvenLessData<T>: Baz {
- | ^^^ ^
- = note: 126 redundant requirements hidden
- = note: required because of the requirements on the impl of `Bar` for `AlmostNoData<T>`
-
-error[E0275]: overflow evaluating the requirement `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo`
- --> $DIR/issue-20413.rs:8:36
- |
-LL | trait Foo {
- | --------- required by this bound in `Foo`
-...
-LL | impl<T> Foo for T where NoData<T>: Foo {
- | ^^^
- |
- = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`)
-note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- --> $DIR/issue-20413.rs:8:9
- |
-LL | impl<T> Foo for T where NoData<T>: Foo {
- | ^^^ ^
- = note: 127 redundant requirements hidden
- = note: required because of the requirements on the impl of `Foo` for `NoData<T>`
-
error[E0275]: overflow evaluating the requirement `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Baz`
--> $DIR/issue-20413.rs:28:42
|
= note: 126 redundant requirements hidden
= note: required because of the requirements on the impl of `Bar` for `AlmostNoData<T>`
+error[E0275]: overflow evaluating the requirement `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Bar`
+ --> $DIR/issue-20413.rs:36:42
+ |
+LL | trait Bar {
+ | --------- required by this bound in `Bar`
+...
+LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
+ | ^^^
+ |
+ = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`)
+note: required because of the requirements on the impl of `Baz` for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+ --> $DIR/issue-20413.rs:36:9
+ |
+LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
+ | ^^^ ^
+note: required because of the requirements on the impl of `Bar` for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+ --> $DIR/issue-20413.rs:28:9
+ |
+LL | impl<T> Bar for T where EvenLessData<T>: Baz {
+ | ^^^ ^
+ = note: 126 redundant requirements hidden
+ = note: required because of the requirements on the impl of `Bar` for `AlmostNoData<T>`
+
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0275, E0392.
error[E0463]: can't find crate for `std`
|
= note: the `thumbv6m-none-eabi` target may not be installed
+ = help: consider downloading the target with `rustup target add thumbv6m-none-eabi`
+ = help: consider building the standard library from source with `cargo build -Zbuild-std`
error: aborting due to previous error
LL | break_me::<Type, fn(_)>;
| ^^^^^^^^^^^^^^^^^^^^^^^
| |
- | expected signature of `fn(<Type as Trait<'b>>::Assoc) -> _`
+ | expected signature of `for<'b> fn(<Type as Trait<'b>>::Assoc) -> _`
| found signature of `fn(()) -> _`
error: aborting due to previous error
error[E0463]: can't find crate for `core`
|
= note: the `thumbv7em-none-eabihf` target may not be installed
+ = help: consider downloading the target with `rustup target add thumbv7em-none-eabihf`
+ = help: consider building the standard library from source with `cargo build -Zbuild-std`
error: aborting due to previous error
LL | foo((), drop)
| ^^^^
| |
- | expected signature of `fn(<() as Trait<'a>>::Item) -> _`
+ | expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _`
| found signature of `fn(()) -> _`
error[E0277]: the size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time
--- /dev/null
+trait Foo<T, T = T> {}
+//~^ ERROR the name `T` is already used for a generic parameter in this item's generic parameters
+
+fn eq<A, B>() {
+ eq::<dyn, Foo>
+ //~^ ERROR cannot find type `dyn` in this scope
+ //~| ERROR missing generics for trait `Foo`
+ //~| WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
+}
+
+fn main() {}
--- /dev/null
+error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters
+ --> $DIR/issue-86756.rs:1:14
+ |
+LL | trait Foo<T, T = T> {}
+ | - ^ already used
+ | |
+ | first use of `T`
+
+error[E0412]: cannot find type `dyn` in this scope
+ --> $DIR/issue-86756.rs:5:10
+ |
+LL | fn eq<A, B>() {
+ | - help: you might be missing a type parameter: `, dyn`
+LL | eq::<dyn, Foo>
+ | ^^^ not found in this scope
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/issue-86756.rs:5:15
+ |
+LL | eq::<dyn, Foo>
+ | ^^^ help: use `dyn`: `dyn Foo`
+ |
+ = note: `#[warn(bare_trait_objects)]` on by default
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+error[E0107]: missing generics for trait `Foo`
+ --> $DIR/issue-86756.rs:5:15
+ |
+LL | eq::<dyn, Foo>
+ | ^^^ expected at least 1 generic argument
+ |
+note: trait defined here, with at least 1 generic parameter: `T`
+ --> $DIR/issue-86756.rs:1:7
+ |
+LL | trait Foo<T, T = T> {}
+ | ^^^ -
+help: add missing generic argument
+ |
+LL | eq::<dyn, Foo<T>>
+ | ^^^^^^
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0107, E0403, E0412.
+For more information about an error, try `rustc --explain E0107`.
--- /dev/null
+// Regression test for issue #87199, where attempting to relax a bound
+// other than the only supported `?Sized` would still cause the compiler
+// to assume that the `Sized` bound was relaxed.
+
+// check-fail
+
+// Check that these function definitions only emit warnings, not errors
+fn arg<T: ?Send>(_: T) {}
+//~^ warning: default bound relaxed for a type parameter, but this does nothing
+fn ref_arg<T: ?Send>(_: &T) {}
+//~^ warning: default bound relaxed for a type parameter, but this does nothing
+fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
+//~^ warning: default bound relaxed for a type parameter, but this does nothing
+
+// Check that there's no `?Sized` relaxation!
+fn main() {
+ ref_arg::<i32>(&5);
+ ref_arg::<[i32]>(&[5]);
+ //~^ the size for values of type `[i32]` cannot be known
+}
--- /dev/null
+warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported
+ --> $DIR/issue-87199.rs:8:8
+ |
+LL | fn arg<T: ?Send>(_: T) {}
+ | ^
+
+warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported
+ --> $DIR/issue-87199.rs:10:12
+ |
+LL | fn ref_arg<T: ?Send>(_: &T) {}
+ | ^
+
+warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported
+ --> $DIR/issue-87199.rs:12:13
+ |
+LL | fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
+ --> $DIR/issue-87199.rs:18:22
+ |
+LL | fn ref_arg<T: ?Send>(_: &T) {}
+ | - required by this bound in `ref_arg`
+...
+LL | ref_arg::<[i32]>(&[5]);
+ | ^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[i32]`
+help: consider relaxing the implicit `Sized` restriction
+ |
+LL | fn ref_arg<T: ?Send + ?Sized>(_: &T) {}
+ | ^^^^^^^^
+
+error: aborting due to previous error; 3 warnings emitted
+
+For more information about this error, try `rustc --explain E0277`.
LL | extern fn foo() {}
| ^^^^^^^^^^^^^^^ ABI should be specified here
|
- = note: requested on the command line with `--force-warns missing-abi`
+ = note: requested on the command line with `--force-warn missing-abi`
= help: the default ABI is C
warning: 1 warning emitted
//
//[warn_deny] compile-flags: --warn missing_abi --deny missing_abi
//[forbid_warn] compile-flags: --warn missing_abi --forbid missing_abi
-//[force_warn_deny] compile-flags: -Z unstable-options --force-warns missing_abi --allow missing_abi
+//[force_warn_deny] compile-flags: -Z unstable-options --force-warn missing_abi --allow missing_abi
//[force_warn_deny] check-pass
// Checks that rustc correctly errors when passed an invalid lint with
-// `--force-warns`. This is a regression test for issue #86958.
+// `--force-warn`. This is a regression test for issue #86958.
//
-// compile-flags: -Z unstable-options --force-warns foo-qux
+// compile-flags: -Z unstable-options --force-warn foo-qux
// error-pattern: unknown lint: `foo_qux`
fn main() {}
error[E0602]: unknown lint: `foo_qux`
|
- = note: requested on the command line with `--force-warns foo_qux`
+ = note: requested on the command line with `--force-warn foo_qux`
error[E0602]: unknown lint: `foo_qux`
|
- = note: requested on the command line with `--force-warns foo_qux`
+ = note: requested on the command line with `--force-warn foo_qux`
error[E0602]: unknown lint: `foo_qux`
|
- = note: requested on the command line with `--force-warns foo_qux`
+ = note: requested on the command line with `--force-warn foo_qux`
error: aborting due to 3 previous errors
// Test that dead code warnings are issued for superfluous assignments of
// fields or variables to themselves (issue #75356).
+// ignore-test FIXME(81658, 83171)
+
// check-pass
#![allow(unused_assignments)]
#![warn(dead_code)]
+++ /dev/null
-#![deny(dead_code)]
-
-struct S {
- f: i32, //~ ERROR: field is never read
- sub: Sub, //~ ERROR: field is never read
-}
-
-struct Sub {
- f: i32, //~ ERROR: field is never read
-}
-
-fn field_write(s: &mut S) {
- s.f = 1;
- s.sub.f = 2;
-}
-
-fn main() {
- let mut s = S { f: 0, sub: Sub { f: 0 } };
- field_write(&mut s);
-
- auto_deref();
- nested_boxes();
-}
-
-fn auto_deref() {
- struct E {
- x: bool,
- y: bool, //~ ERROR: field is never read
- }
-
- struct P<'a> {
- e: &'a mut E
- }
-
- impl P<'_> {
- fn f(&mut self) {
- self.e.x = true;
- self.e.y = true;
- }
- }
-
- let mut e = E { x: false, y: false };
- let mut p = P { e: &mut e };
- p.f();
- assert!(e.x);
-}
-
-fn nested_boxes() {
- struct A {
- b: Box<B>,
- }
-
- struct B {
- c: Box<C>,
- }
-
- struct C {
- u: u32, //~ ERROR: field is never read
- v: u32, //~ ERROR: field is never read
- }
-
- let mut a = A {
- b: Box::new(B {
- c: Box::new(C { u: 0, v: 0 }),
- }),
- };
- a.b.c.v = 10;
- a.b.c = Box::new(C { u: 1, v: 2 });
-}
+++ /dev/null
-error: field is never read: `f`
- --> $DIR/write-only-field.rs:4:5
- |
-LL | f: i32,
- | ^^^^^^
- |
-note: the lint level is defined here
- --> $DIR/write-only-field.rs:1:9
- |
-LL | #![deny(dead_code)]
- | ^^^^^^^^^
-
-error: field is never read: `sub`
- --> $DIR/write-only-field.rs:5:5
- |
-LL | sub: Sub,
- | ^^^^^^^^
-
-error: field is never read: `f`
- --> $DIR/write-only-field.rs:9:5
- |
-LL | f: i32,
- | ^^^^^^
-
-error: field is never read: `y`
- --> $DIR/write-only-field.rs:28:9
- |
-LL | y: bool,
- | ^^^^^^^
-
-error: field is never read: `u`
- --> $DIR/write-only-field.rs:58:9
- |
-LL | u: u32,
- | ^^^^^^
-
-error: field is never read: `v`
- --> $DIR/write-only-field.rs:59:9
- |
-LL | v: u32,
- | ^^^^^^
-
-error: aborting due to 6 previous errors
-
-// compile-flags: --force-warns elided_lifetimes_in_paths -Zunstable-options
+// compile-flags: --force-warn elided_lifetimes_in_paths -Zunstable-options
// check-pass
struct Foo<'a> {
LL | fn foo(x: &Foo) {}
| ^^^- help: indicate the anonymous lifetime: `<'_>`
|
- = note: requested on the command line with `--force-warns elided-lifetimes-in-paths`
+ = note: requested on the command line with `--force-warn elided-lifetimes-in-paths`
warning: 1 warning emitted
-// compile-flags: --force-warns const_err -Zunstable-options
+// compile-flags: --force-warn const_err -Zunstable-options
// check-pass
#![allow(const_err)]
| |
| attempt to divide `1_i32` by zero
|
- = note: requested on the command line with `--force-warns const-err`
+ = note: requested on the command line with `--force-warn const-err`
= 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
-// compile-flags: --force-warns dead_code -Zunstable-options
+// compile-flags: --force-warn dead_code -Zunstable-options
// check-pass
#![allow(dead_code)]
LL | fn dead_function() {}
| ^^^^^^^^^^^^^
|
- = note: requested on the command line with `--force-warns dead-code`
+ = note: requested on the command line with `--force-warn dead-code`
warning: 1 warning emitted
-// compile-flags: --force-warns const_err -Zunstable-options
+// compile-flags: --force-warn const_err -Zunstable-options
// check-pass
const C: i32 = 1 / 0;
| |
| attempt to divide `1_i32` by zero
|
- = note: requested on the command line with `--force-warns const-err`
+ = note: requested on the command line with `--force-warn const-err`
= 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
-// compile-flags: --force-warns dead_code -Zunstable-options
+// compile-flags: --force-warn dead_code -Zunstable-options
// check-pass
#![allow(warnings)]
LL | fn dead_function() {}
| ^^^^^^^^^^^^^
|
- = note: requested on the command line with `--force-warns dead-code`
+ = note: requested on the command line with `--force-warn dead-code`
warning: 1 warning emitted
-// compile-flags: --force-warns nonstandard_style -Zunstable-options
+// compile-flags: --force-warn nonstandard_style -Zunstable-options
// check-pass
#![allow(warnings)]
LL | pub fn FUNCTION() {}
| ^^^^^^^^ help: convert the identifier to snake case: `function`
|
- = note: `--force-warns non-snake-case` implied by `--force-warns nonstandard-style`
+ = note: `--force-warn non-snake-case` implied by `--force-warn nonstandard-style`
warning: 1 warning emitted
-// compile-flags: --force-warns bare_trait_objects -Zunstable-options
+// compile-flags: --force-warn bare_trait_objects -Zunstable-options
// check-pass
#![allow(rust_2018_idioms)]
LL | pub fn function(_x: Box<SomeTrait>) {}
| ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
|
- = note: requested on the command line with `--force-warns bare-trait-objects`
+ = note: requested on the command line with `--force-warn bare-trait-objects`
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
--- /dev/null
+// compile-flags: --cap-lints allow --force-warn bare_trait_objects -Zunstable-options
+// check-pass
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
+
+fn main() {}
--- /dev/null
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/force-warn-cap-lints-allow.rs:6:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ |
+ = note: requested on the command line with `--force-warn bare-trait-objects`
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
-// compile-flags: --cap-lints warn --force-warns rust-2021-compatibility -Zunstable-options
+// compile-flags: --cap-lints warn --force-warn rust-2021-compatibility -Zunstable-options
// check-pass
#![allow(ellipsis_inclusive_range_patterns)]
LL | 0...100 => true,
| ^^^ help: use `..=` for an inclusive range
|
- = note: `--force-warns ellipsis-inclusive-range-patterns` implied by `--force-warns rust-2021-compatibility`
+ = note: `--force-warn ellipsis-inclusive-range-patterns` implied by `--force-warn rust-2021-compatibility`
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
-// compile-flags: --force-warns rust-2018-idioms -Zunstable-options
+// compile-flags: --force-warn rust-2018-idioms -Zunstable-options
// check-pass
#![allow(bare_trait_objects)]
LL | pub fn function(_x: Box<SomeTrait>) {}
| ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
|
- = note: `--force-warns bare-trait-objects` implied by `--force-warns rust-2018-idioms`
+ = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
-// compile-flags: --force-warns rust_2018_idioms -Zunstable-options
+// compile-flags: --force-warn rust_2018_idioms -Zunstable-options
// check-pass
#![allow(rust_2018_idioms)]
LL | pub fn function(_x: Box<SomeTrait>) {}
| ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
|
- = note: `--force-warns bare-trait-objects` implied by `--force-warns rust-2018-idioms`
+ = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+++ /dev/null
-// compile-flags: --cap-lints allow --force-warns bare_trait_objects -Zunstable-options
-// check-pass
-
-pub trait SomeTrait {}
-
-pub fn function(_x: Box<SomeTrait>) {}
-//~^ WARN trait objects without an explicit `dyn` are deprecated
-//~| WARN this is accepted in the current edition
-
-fn main() {}
+++ /dev/null
-warning: trait objects without an explicit `dyn` are deprecated
- --> $DIR/force-warns-cap-lints-allow.rs:6:25
- |
-LL | pub fn function(_x: Box<SomeTrait>) {}
- | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
- |
- = note: requested on the command line with `--force-warns bare-trait-objects`
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
-
-warning: 1 warning emitted
-
--- /dev/null
+// check-pass
+
+#![warn(unused)]
+
+macro_rules! foo {
+ () => {}
+}
+
+fn main() {
+ #[inline] foo!(); //~ WARN unused attribute `inline`
+
+ // This does nothing, since `#[allow(warnings)]` is itself
+ // an inert attribute on a macro call
+ #[allow(warnings)] #[inline] foo!(); //~ WARN unused attribute `allow`
+ //~^ WARN unused attribute `inline`
+
+ // This does work, since the attribute is on a parent
+ // of the macro invocation.
+ #[allow(warnings)] { #[inline] foo!(); }
+}
--- /dev/null
+warning: unused attribute `inline`
+ --> $DIR/inert-attr-macro.rs:10:5
+ |
+LL | #[inline] foo!();
+ | ^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/inert-attr-macro.rs:3:9
+ |
+LL | #![warn(unused)]
+ | ^^^^^^
+ = note: `#[warn(unused_attributes)]` implied by `#[warn(unused)]`
+note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo`
+ --> $DIR/inert-attr-macro.rs:10:15
+ |
+LL | #[inline] foo!();
+ | ^^^
+
+warning: unused attribute `allow`
+ --> $DIR/inert-attr-macro.rs:14:5
+ |
+LL | #[allow(warnings)] #[inline] foo!();
+ | ^^^^^^^^^^^^^^^^^^
+ |
+note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo`
+ --> $DIR/inert-attr-macro.rs:14:34
+ |
+LL | #[allow(warnings)] #[inline] foo!();
+ | ^^^
+
+warning: unused attribute `inline`
+ --> $DIR/inert-attr-macro.rs:14:24
+ |
+LL | #[allow(warnings)] #[inline] foo!();
+ | ^^^^^^^^^
+ |
+note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo`
+ --> $DIR/inert-attr-macro.rs:14:34
+ |
+LL | #[allow(warnings)] #[inline] foo!();
+ | ^^^
+
+warning: 3 warnings emitted
+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= 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 #79813 <https://github.com/rust-lang/rust/issues/79813>
+ = note: macro invocations at the end of a block are treated as expressions
+ = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo`
= note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: trailing semicolon in macro used in expression position
--- /dev/null
+// run-rustfix
+// Parser should know when a semicolon is missing.
+// https://github.com/rust-lang/rust/issues/87197
+
+fn main() {
+ let x = 100; //~ ERROR: expected `;`
+ println!("{}", x); //~ ERROR: expected `;`
+ let y = 200; //~ ERROR: expected `;`
+ println!("{}", y);
+}
--- /dev/null
+// run-rustfix
+// Parser should know when a semicolon is missing.
+// https://github.com/rust-lang/rust/issues/87197
+
+fn main() {
+ let x = 100 //~ ERROR: expected `;`
+ println!("{}", x) //~ ERROR: expected `;`
+ let y = 200 //~ ERROR: expected `;`
+ println!("{}", y);
+}
--- /dev/null
+error: expected `;`, found `println`
+ --> $DIR/issue-87197-missing-semicolon.rs:6:16
+ |
+LL | let x = 100
+ | ^ help: add `;` here
+LL | println!("{}", x)
+ | ------- unexpected token
+
+error: expected `;`, found keyword `let`
+ --> $DIR/issue-87197-missing-semicolon.rs:7:22
+ |
+LL | println!("{}", x)
+ | ^ help: add `;` here
+LL | let y = 200
+ | --- unexpected token
+
+error: expected `;`, found `println`
+ --> $DIR/issue-87197-missing-semicolon.rs:8:16
+ |
+LL | let y = 200
+ | ^ help: add `;` here
+LL | println!("{}", y);
+ | ------- unexpected token
+
+error: aborting due to 3 previous errors
+
fn main() {
- assert_eq!(1, 2)
- assert_eq!(3, 4) //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `assert_eq`
+ assert_eq!(1, 2) //~ ERROR: expected `;`
+ assert_eq!(3, 4) //~ ERROR: expected `;`
println!("hello");
}
-error: expected one of `.`, `;`, `?`, `}`, or an operator, found `assert_eq`
- --> $DIR/macros-no-semicolon.rs:3:5
+error: expected `;`, found `assert_eq`
+ --> $DIR/macros-no-semicolon.rs:2:21
|
LL | assert_eq!(1, 2)
- | - expected one of `.`, `;`, `?`, `}`, or an operator
+ | ^ help: add `;` here
LL | assert_eq!(3, 4)
- | ^^^^^^^^^ unexpected token
+ | --------- unexpected token
-error: aborting due to previous error
+error: expected `;`, found `println`
+ --> $DIR/macros-no-semicolon.rs:3:21
+ |
+LL | assert_eq!(3, 4)
+ | ^ help: add `;` here
+LL | println!("hello");
+ | ------- unexpected token
+
+error: aborting due to 2 previous errors
// Test copy
-#![feature(bindings_after_at)]
-
struct A { a: i32, b: i32 }
struct B { a: i32, b: C }
struct D { a: i32, d: C }
// It checks that you cannot use an AND-pattern (`binding @ pat`)
// where one side is by-ref and the other is by-move.
-#![feature(bindings_after_at)]
-
struct X {
x: (),
}
error: cannot move out of value because it is borrowed
- --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:14:14
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14
|
LL | Some(ref _y @ _z) => {}
| ------^^^--
| value borrowed, by `_y`, here
error: borrow of moved value
- --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:21:14
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:19:14
|
LL | Some(_z @ ref _y) => {}
| --^^^------
| move occurs because `_z` has type `X` which does not implement the `Copy` trait
error: cannot move out of value because it is borrowed
- --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:28:14
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14
|
LL | Some(ref mut _y @ _z) => {}
| ----------^^^--
| value borrowed, by `_y`, here
error: borrow of moved value
- --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:14
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:33:14
|
LL | Some(_z @ ref mut _y) => {}
| --^^^----------
| move occurs because `_z` has type `X` which does not implement the `Copy` trait
error[E0382]: borrow of moved value
- --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:14:14
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14
|
LL | Some(ref _y @ _z) => {}
| ^^^^^^^^^--
| ^^^
error[E0382]: borrow of moved value
- --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:28:14
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14
|
LL | Some(ref mut _y @ _z) => {}
| ^^^^^^^^^^^^^--
// See issue #12534.
-#![feature(bindings_after_at)]
-
fn main() {}
struct A(Box<u8>);
error[E0382]: use of partially moved value
- --> $DIR/bind-by-move-no-subbindings-fun-param.rs:9:6
+ --> $DIR/bind-by-move-no-subbindings-fun-param.rs:7:6
|
LL | fn f(a @ A(u): A) -> Box<u8> {
| ^^^^^^-^
// Test that moving on both sides of an `@` pattern is not allowed.
-#![feature(bindings_after_at)]
-
fn main() {
struct U; // Not copy!
error[E0382]: use of moved value
- --> $DIR/borrowck-move-and-move.rs:13:9
+ --> $DIR/borrowck-move-and-move.rs:11:9
|
LL | let a @ b = U;
| ^^^^- - move occurs because value has type `U`, which does not implement the `Copy` trait
| value used here after move
error[E0382]: use of partially moved value
- --> $DIR/borrowck-move-and-move.rs:15:9
+ --> $DIR/borrowck-move-and-move.rs:13:9
|
LL | let a @ (b, c) = (U, U);
| ^^^^^^^^-^
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
error[E0382]: use of partially moved value
- --> $DIR/borrowck-move-and-move.rs:17:9
+ --> $DIR/borrowck-move-and-move.rs:15:9
|
LL | let a @ (b, c) = (u(), u());
| ^^^^^^^^-^
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
error[E0382]: use of moved value
- --> $DIR/borrowck-move-and-move.rs:20:16
+ --> $DIR/borrowck-move-and-move.rs:18:16
|
LL | match Ok(U) {
| ----- move occurs because value has type `Result<U, U>`, which does not implement the `Copy` trait
| value moved here
error[E0382]: use of moved value
- --> $DIR/borrowck-move-and-move.rs:20:29
+ --> $DIR/borrowck-move-and-move.rs:18:29
|
LL | match Ok(U) {
| ----- move occurs because value has type `Result<U, U>`, which does not implement the `Copy` trait
| value moved here
error[E0382]: use of partially moved value
- --> $DIR/borrowck-move-and-move.rs:27:9
+ --> $DIR/borrowck-move-and-move.rs:25:9
|
LL | xs @ [a, .., b] => {}
| ^^^^^^^^^^^^^-^
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
error[E0382]: use of partially moved value
- --> $DIR/borrowck-move-and-move.rs:31:9
+ --> $DIR/borrowck-move-and-move.rs:29:9
|
LL | xs @ [_, ys @ .., _] => {}
| ^^^^^^^^^-------^^^^
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
error[E0382]: use of moved value
- --> $DIR/borrowck-move-and-move.rs:24:12
+ --> $DIR/borrowck-move-and-move.rs:22:12
|
LL | fn fun(a @ b: U) {}
| ^^^^-
// Test `@` patterns combined with `box` patterns.
-#![feature(bindings_after_at)]
#![feature(box_patterns)]
#[derive(Copy, Clone)]
// Test `@` patterns combined with `box` patterns.
-#![feature(bindings_after_at)]
#![feature(box_patterns)]
#[derive(Copy, Clone)]
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-at-and-box.rs:32:9
+ --> $DIR/borrowck-pat-at-and-box.rs:31:9
|
LL | let ref a @ box b = Box::new(NC);
| -----^^^^^^^-
| value borrowed, by `a`, here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-at-and-box.rs:35:9
+ --> $DIR/borrowck-pat-at-and-box.rs:34:9
|
LL | let ref a @ box ref mut b = Box::new(nc());
| -----^^^^^^^---------
| immutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-at-and-box.rs:37:9
+ --> $DIR/borrowck-pat-at-and-box.rs:36:9
|
LL | let ref a @ box ref mut b = Box::new(NC);
| -----^^^^^^^---------
| immutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-at-and-box.rs:39:9
+ --> $DIR/borrowck-pat-at-and-box.rs:38:9
|
LL | let ref a @ box ref mut b = Box::new(NC);
| -----^^^^^^^---------
| immutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-at-and-box.rs:43:9
+ --> $DIR/borrowck-pat-at-and-box.rs:42:9
|
LL | let ref a @ box ref mut b = Box::new(NC);
| -----^^^^^^^---------
| immutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-at-and-box.rs:49:9
+ --> $DIR/borrowck-pat-at-and-box.rs:48:9
|
LL | let ref mut a @ box ref b = Box::new(NC);
| ---------^^^^^^^-----
| mutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-at-and-box.rs:63:9
+ --> $DIR/borrowck-pat-at-and-box.rs:62:9
|
LL | ref mut a @ box ref b => {
| ---------^^^^^^^-----
| mutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-at-and-box.rs:55:11
+ --> $DIR/borrowck-pat-at-and-box.rs:54:11
|
LL | fn f5(ref mut a @ box ref b: Box<NC>) {
| ---------^^^^^^^-----
| mutable borrow, by `a`, occurs here
error[E0382]: borrow of moved value
- --> $DIR/borrowck-pat-at-and-box.rs:32:9
+ --> $DIR/borrowck-pat-at-and-box.rs:31:9
|
LL | let ref a @ box b = Box::new(NC);
| ^^^^^^^^^^^^-
= note: move occurs because value has type `NC`, which does not implement the `Copy` trait
error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-at-and-box.rs:39:9
+ --> $DIR/borrowck-pat-at-and-box.rs:38:9
|
LL | let ref a @ box ref mut b = Box::new(NC);
| ^^^^^^^^^^^^---------
| ------- mutable borrow later used here
error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-at-and-box.rs:43:9
+ --> $DIR/borrowck-pat-at-and-box.rs:42:9
|
LL | let ref a @ box ref mut b = Box::new(NC);
| ^^^^^^^^^^^^---------
| ------- mutable borrow later used here
error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-at-and-box.rs:49:9
+ --> $DIR/borrowck-pat-at-and-box.rs:48:9
|
LL | let ref mut a @ box ref b = Box::new(NC);
| ^^^^^^^^^^^^^^^^-----
| - immutable borrow later used here
error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-at-and-box.rs:63:9
+ --> $DIR/borrowck-pat-at-and-box.rs:62:9
|
LL | ref mut a @ box ref b => {
| ^^^^^^^^^^^^^^^^-----
| - immutable borrow later used here
error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-at-and-box.rs:55:11
+ --> $DIR/borrowck-pat-at-and-box.rs:54:11
|
LL | fn f5(ref mut a @ box ref b: Box<NC>) {
| ^^^^^^^^^^^^^^^^-----
// Test `Copy` bindings in the rhs of `@` patterns.
-#![feature(bindings_after_at)]
-
#[derive(Copy, Clone)]
struct C;
// Test that `by_move_binding @ pat_with_by_ref_bindings` is prevented even with promotion.
// Currently this logic exists in THIR match checking as opposed to borrowck.
-#![feature(bindings_after_at)]
-
fn main() {
struct U;
let a @ ref b = U; //~ ERROR borrow of moved value
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:8:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:6:9
|
LL | let a @ ref b = U;
| -^^^-----
// Test that `by_move_binding @ pat_with_by_ref_bindings` is prevented.
-#![feature(bindings_after_at)]
-
fn main() {
struct U;
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:22:9
|
LL | let a @ ref b = U;
| -^^^-----
| move occurs because `a` has type `U` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:26:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
|
LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
| -^^^^^^^^^^^^---------^^^^^^-----^
| move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:26:14
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:14
|
LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
| -----^^^---------
| move occurs because `b` has type `U` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:26:33
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:33
|
LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
| -^^^-----
| move occurs because `d` has type `U` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:29:9
|
LL | let a @ [ref mut b, ref c] = [U, U];
| -^^^^---------^^-----^
| move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9
|
LL | let a @ ref b = u();
| -^^^-----
| move occurs because `a` has type `U` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:35:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
|
LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
| -^^^^^^^^^^^^---------^^^^^^-----^
| move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:35:14
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:14
|
LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
| -----^^^---------
| move occurs because `b` has type `U` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:35:33
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:33
|
LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
| -^^^-----
| move occurs because `d` has type `U` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:40:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9
|
LL | let a @ [ref mut b, ref c] = [u(), u()];
| -^^^^---------^^-----^
| move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:42:9
|
LL | a @ Some(ref b) => {}
| -^^^^^^^^-----^
| move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:49:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:9
|
LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
| -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^
| move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:49:19
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:19
|
LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
| -----^^^---------
| move occurs because `b` has type `U` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:49:38
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38
|
LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
| -^^^-----
| move occurs because `d` has type `U` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:57:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:9
|
LL | mut a @ Some([ref b, ref mut c]) => {}
| -----^^^^^^^^^-----^^---------^^
| move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:63:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9
|
LL | a @ Some(ref b) => {}
| -^^^^^^^^-----^
| move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:69:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:9
|
LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
| -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^
| move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:69:19
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:19
|
LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
| -----^^^---------
| move occurs because `b` has type `U` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:69:38
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38
|
LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
| -^^^-----
| move occurs because `d` has type `U` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:9
|
LL | mut a @ Some([ref b, ref mut c]) => {}
| -----^^^^^^^^^-----^^---------^^
| move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:13:11
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:11:11
|
LL | fn f1(a @ ref b: U) {}
| -^^^-----
| move occurs because `a` has type `U` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:16:11
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11
|
LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
| -----^^^^^^^^-----^^^^^^^^^^-----^
| move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:16:20
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:20
|
LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
| -^^^-----
| move occurs because `b` has type `U` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:16:31
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:31
|
LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
| -----^^^-----
| move occurs because `d` has type `U` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:21:11
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:19:11
|
LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {}
| -^^^^---------^^-----^
| move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
error[E0382]: use of partially moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:26:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
|
LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
| ^^^^^^^^^^^^^^^^^^^^^^^^---------^
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
error[E0382]: use of partially moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:35:9
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
|
LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
| ^^^^^^^^^^^^^^^^^^^^^^^^---------^
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
error[E0382]: use of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:49:38
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38
|
LL | match Some((U, U)) {
| ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
| value moved here
error[E0382]: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:57:30
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:30
|
LL | match Some([U, U]) {
| ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
| value moved here
error[E0382]: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:63:18
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:18
|
LL | match Some(u()) {
| --------- move occurs because value has type `Option<U>`, which does not implement the `Copy` trait
| value moved here
error[E0382]: use of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:69:38
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38
|
LL | match Some((u(), u())) {
| ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
| value moved here
error[E0382]: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:30
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:30
|
LL | match Some([u(), u()]) {
| ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
| value moved here
error[E0382]: use of partially moved value
- --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:16:11
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11
|
LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
| ^^^^^^^^^^^^^^^^^^^^-------------^
// Test that `ref mut? @ pat_with_by_move_bindings` is prevented.
-#![feature(bindings_after_at)]
-
fn main() {
struct U;
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:26:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:24:9
|
LL | let ref a @ b = U;
| -----^^^-
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:28:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:26:9
|
LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
| -----^^^^^^^^^^^^-----^^^^^^^^^^-^
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:28:18
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:26:18
|
LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
| -----^^^-----
| value borrowed, by `b`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:28:33
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:26:33
|
LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
| -----^^^-
| value borrowed, by `d`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:32:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
|
LL | let ref mut a @ [b, mut c] = [U, U];
| ---------^^^^-^^-----^
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:35:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
|
LL | let ref a @ b = u();
| -----^^^-
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:38:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:9
|
LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
| -----^^^^^^^^^^^^-----^^^^^^^^^^-^
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:38:18
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18
|
LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
| -----^^^-----
| value borrowed, by `b`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:38:33
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33
|
LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
| -----^^^-
| value borrowed, by `d`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:44:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9
|
LL | let ref mut a @ [b, mut c] = [u(), u()];
| ---------^^^^-^^-----^
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:49:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:47:9
|
LL | ref a @ Some(b) => {}
| -----^^^^^^^^-^
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:54:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:52:9
|
LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
| -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:54:23
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:52:23
|
LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
| -----^^^-----
| value borrowed, by `b`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:54:38
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:52:38
|
LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
| -----^^^-
| value borrowed, by `d`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:61:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:59:9
|
LL | ref mut a @ Some([b, mut c]) => {}
| ---------^^^^^^^^^-^^-----^^
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:66:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:64:9
|
LL | ref a @ Some(b) => {}
| -----^^^^^^^^-^
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:71:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9
|
LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
| -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:71:23
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23
|
LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
| -----^^^-----
| value borrowed, by `b`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:71:38
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38
|
LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
| -----^^^-
| value borrowed, by `d`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:80:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:78:9
|
LL | ref mut a @ Some([b, mut c]) => {}
| ---------^^^^^^^^^-^^-----^^
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:13:11
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11
|
LL | fn f1(ref a @ b: U) {}
| -----^^^-
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:16:11
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:11
|
LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
| -----^^^^^^^^^^^^-----^^^^^^^^^^-^
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:16:20
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20
|
LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
| -----^^^-----
| value borrowed, by `b`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:16:35
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35
|
LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
| -----^^^-
| value borrowed, by `d`, here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-by-move-and-ref.rs:22:11
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11
|
LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
| ---------^^^^-^^-----^
| value borrowed, by `a`, here
error[E0382]: borrow of partially moved value
- --> $DIR/borrowck-pat-by-move-and-ref.rs:32:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
|
LL | let ref mut a @ [b, mut c] = [U, U];
| ^^^^^^^^^^^^^^^^-----^
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref.rs:35:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
|
LL | let ref a @ b = u();
| ^^^^^^^^- --- move occurs because value has type `U`, which does not implement the `Copy` trait
| value borrowed here after move
error[E0382]: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref.rs:38:18
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18
|
LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
| ^^^^^^^^-----
= note: move occurs because value has type `U`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref.rs:38:33
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33
|
LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
| ^^^^^^^^-
= note: move occurs because value has type `U`, which does not implement the `Copy` trait
error[E0382]: borrow of partially moved value
- --> $DIR/borrowck-pat-by-move-and-ref.rs:44:9
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9
|
LL | let ref mut a @ [b, mut c] = [u(), u()];
| ^^^^^^^^^^^^^^^^-----^
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref.rs:71:23
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23
|
LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
| ^^^^^^^^-----
| ^^^
error[E0382]: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref.rs:71:38
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38
|
LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
| ^^^^^^^^-
| ^^^
error[E0382]: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref.rs:13:11
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11
|
LL | fn f1(ref a @ b: U) {}
| ^^^^^^^^-
| move occurs because value has type `U`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref.rs:16:20
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20
|
LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
| ^^^^^^^^-----
= note: move occurs because value has type `U`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value
- --> $DIR/borrowck-pat-by-move-and-ref.rs:16:35
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35
|
LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
| ^^^^^^^^-
= note: move occurs because value has type `U`, which does not implement the `Copy` trait
error[E0382]: borrow of partially moved value
- --> $DIR/borrowck-pat-by-move-and-ref.rs:22:11
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11
|
LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
| ^^^^^^^^^^^^^^^^-----^
// Test that `ref` patterns may be used on both sides
// of an `@` pattern according to NLL borrowck.
-#![feature(bindings_after_at)]
-
fn main() {
struct U; // Not copy!
-#![feature(bindings_after_at)]
-
enum Option<T> {
None,
Some(T),
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:10:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:9
|
LL | ref mut z @ &mut Some(ref a) => {
| ---------^^^^^^^^^^^^^-----^
| mutable borrow, by `z`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:35:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:9
|
LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
| ---------^^^^-----------------^
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:35:22
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:22
|
LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
| -----^^^---------
| immutable borrow, by `b`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:37:9
|
LL | let ref a @ ref mut b = U;
| -----^^^---------
| immutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9
|
LL | let ref mut a @ ref b = U;
| ---------^^^-----
| mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9
|
LL | let ref a @ (ref mut b, ref mut c) = (U, U);
| -----^^^^---------^^---------^
| immutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:45:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9
|
LL | let ref mut a @ (ref b, ref c) = (U, U);
| ---------^^^^-----^^-----^
| mutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:48:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9
|
LL | let ref mut a @ ref b = u();
| ---------^^^-----
| mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:53:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9
|
LL | let ref a @ ref mut b = u();
| -----^^^---------
| immutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:59:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:57:9
|
LL | let ref mut a @ ref b = U;
| ---------^^^-----
| mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:63:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:61:9
|
LL | let ref a @ ref mut b = U;
| -----^^^---------
| immutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:69:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:9
|
LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
| ---------^^^^^^-----^
| mutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:69:33
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:33
|
LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
| ---------^^^^^^^-----^
| mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:9
|
LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
| -----^^^^^^---------^
| immutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:33
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:33
|
LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
| -----^^^^^^^---------^
| immutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:9
|
LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
| -----^^^^^^---------^
| immutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:33
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:33
|
LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
| -----^^^^^^^---------^
| immutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:9
|
LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
| ---------^^^^^^-----^
| mutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:33
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:33
|
LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
| ---------^^^^^^^-----^
| mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:9
|
LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
| -----^^^^^^---------^
| immutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:33
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:33
|
LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
| -----^^^^^^^---------^
| immutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:9
|
LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
| ---------^^^^^^-----^
| mutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:33
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:33
|
LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
| ---------^^^^^^^-----^
| mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:119:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9
|
LL | let ref a @ (ref mut b, ref mut c) = (U, U);
| -----^^^^---------^^---------^
| immutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:125:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9
|
LL | let ref a @ (ref mut b, ref mut c) = (U, U);
| -----^^^^---------^^---------^
| immutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9
|
LL | let ref a @ (ref mut b, ref mut c) = (U, U);
| -----^^^^---------^^---------^
| immutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:136:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:134:9
|
LL | let ref mut a @ (ref b, ref c) = (U, U);
| ---------^^^^-----^^-----^
| mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:22:11
|
LL | fn f1(ref a @ ref mut b: U) {}
| -----^^^---------
| immutable borrow, by `a`, occurs here
error: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11
|
LL | fn f2(ref mut a @ ref b: U) {}
| ---------^^^-----
| mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:11
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11
|
LL | fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {}
| -----^^^^^^^^^^^----------------^^^^^^^^
| immutable borrow, by `a`, occurs here
error: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:30:22
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:22
|
LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {}
| -----^^^-------------
| immutable borrow, by `a`, occurs here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:30:30
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30
|
LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {}
| ---------^^^-
| value borrowed, by `b`, here
error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:10:31
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:31
|
LL | ref mut z @ &mut Some(ref a) => {
| ----------------------^^^^^-
| ---------- mutable borrow later used here
error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:48:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9
|
LL | let ref mut a @ ref b = u();
| ^^^^^^^^^^^^-----
| - immutable borrow later used here
error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:53:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9
|
LL | let ref a @ ref mut b = u();
| ^^^^^^^^---------
| -------- mutable borrow later used here
error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:20
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:20
|
LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
| -----------^^^^^^^^^-
| - immutable borrow later used here
error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:45
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:45
|
LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
| ------------^^^^^^^^^-
| - immutable borrow later used here
error[E0594]: cannot assign to `*b`, as it is immutable for the pattern guard
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:61
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:61
|
LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
| ^^^^^^ cannot assign
= note: variables bound in patterns are immutable until the end of the pattern guard
error[E0594]: cannot assign to `*a`, as it is immutable for the pattern guard
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:61
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:61
|
LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
| ^^^^^^^^^^^ cannot assign
= note: variables bound in patterns are immutable until the end of the pattern guard
error[E0507]: cannot move out of `b` in pattern guard
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:66
|
LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
| ^ move occurs because `b` has type `&mut U`, 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[E0507]: cannot move out of `b` in pattern guard
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:66
|
LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
| ^ move occurs because `b` has type `&mut U`, 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[E0507]: cannot move out of `a` in pattern guard
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:66
|
LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
| ^ move occurs because `a` has type `&mut Result<U, U>`, 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[E0507]: cannot move out of `a` in pattern guard
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:66
|
LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
| ^ move occurs because `a` has type `&mut Result<U, U>`, 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[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:119:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9
|
LL | let ref a @ (ref mut b, ref mut c) = (U, U);
| ^^^^^^^^^---------^^^^^^^^^^^^
| ------ mutable borrow later used here
error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:125:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9
|
LL | let ref a @ (ref mut b, ref mut c) = (U, U);
| ^^^^^^^^^---------^^^^^^^^^^^^
| ------ mutable borrow later used here
error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:9
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9
|
LL | let ref a @ (ref mut b, ref mut c) = (U, U);
| ^^^^^^^^^---------^^^^^^^^^^^^
| ------ mutable borrow later used here
error[E0382]: borrow of moved value
- --> $DIR/borrowck-pat-ref-mut-and-ref.rs:30:30
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30
|
LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {}
| --------^^^^^^^^^^^^-
// Test that `ref mut x @ ref mut y` and varieties of that are not allowed.
-#![feature(bindings_after_at)]
-
fn main() {
struct U;
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:28:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:26:9
|
LL | let ref mut a @ ref mut b = U;
| ---------^^^---------
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:31:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
|
LL | let ref mut a @ ref mut b = U;
| ---------^^^---------
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:35:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:33:9
|
LL | let ref mut a @ ref mut b = U;
| ---------^^^---------
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:38:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:36:9
|
LL | let ref mut a @ ref mut b = U;
| ---------^^^---------
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:41:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9
|
LL | let ref mut a @ ref mut b = U;
| ---------^^^---------
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:46:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:44:9
|
LL | let ref mut a @ (
| ^--------
| |_____^
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:56:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:54:9
|
LL | let ref mut a @ (
| ^--------
| |_________^
error: borrow of moved value
- --> $DIR/borrowck-pat-ref-mut-twice.rs:66:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:64:9
|
LL | let a @ (ref mut b, ref mut c) = (U, U);
| -^^^^---------^^---------^
| move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-ref-mut-twice.rs:69:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:67:9
|
LL | let a @ (b, [c, d]) = &mut val; // Same as ^--
| -^^^^-^^^-^^-^^
| move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-ref-mut-twice.rs:72:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9
|
LL | let a @ &mut ref mut b = &mut U;
| -^^^^^^^^---------
| move occurs because `a` has type `&mut U` which does not implement the `Copy` trait
error: borrow of moved value
- --> $DIR/borrowck-pat-ref-mut-twice.rs:74:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:72:9
|
LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
| -^^^^^^^^^---------^^---------^
| move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:78:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:76:9
|
LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
| ---------^^^^^^---------^
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:78:37
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:76:37
|
LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
| ---------^^^^^^^---------^
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:84:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9
|
LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
| ---------^^^^^^---------^
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:84:37
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37
|
LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
| ---------^^^^^^^---------^
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:91:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:89:9
|
LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
| ---------^^^^^^---------^
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:91:37
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:89:37
|
LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
| ---------^^^^^^^---------^
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:103:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:101:9
|
LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
| ---------^^^^^^---------^
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:103:37
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:101:37
|
LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
| ---------^^^^^^^---------^
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:8:11
|
LL | fn f1(ref mut a @ ref mut b: U) {}
| ---------^^^---------
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:12:11
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11
|
LL | fn f2(ref mut a @ ref mut b: U) {}
| ---------^^^---------
| first mutable borrow, by `a`, occurs here
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:15:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:13:9
|
LL | ref mut a @ [
| ^--------
| |_________^
error: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:23:22
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:21:22
|
LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
| ---------^^^-------------
| first mutable borrow, by `a`, occurs here
error: cannot move out of value because it is borrowed
- --> $DIR/borrowck-pat-ref-mut-twice.rs:23:34
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34
|
LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
| ---------^^^-
| value borrowed, by `b`, here
error[E0499]: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:31:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
|
LL | let ref mut a @ ref mut b = U;
| ^^^^^^^^^^^^---------
| - first borrow later used here
error[E0499]: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:41:9
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9
|
LL | let ref mut a @ ref mut b = U;
| ^^^^^^^^^^^^---------
| ------ first borrow later used here
error[E0499]: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:91:24
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:89:24
|
LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
| ---------------^^^^^^^^^-
| ----------- first borrow later used here
error[E0499]: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:91:53
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:89:53
|
LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
| ----------------^^^^^^^^^-
| ----------- first borrow later used here
error[E0499]: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:103:24
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:101:24
|
LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
| ---------------^^^^^^^^^-
| - first borrow later used here
error[E0499]: cannot borrow value as mutable more than once at a time
- --> $DIR/borrowck-pat-ref-mut-twice.rs:103:53
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:101:53
|
LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
| ----------------^^^^^^^^^-
| - first borrow later used here
error[E0382]: borrow of moved value
- --> $DIR/borrowck-pat-ref-mut-twice.rs:23:34
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34
|
LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
| ------------^^^^^^^^^^^^-
// run-pass
-#![feature(bindings_after_at)]
#![feature(box_patterns)]
#[derive(Debug, PartialEq)]
// Test that mixing `Copy` and non-`Copy` types in `@` patterns is forbidden.
-#![feature(bindings_after_at)]
-
#[derive(Copy, Clone)]
struct C;
error[E0382]: use of partially moved value
- --> $DIR/copy-and-move-mixed.rs:14:9
+ --> $DIR/copy-and-move-mixed.rs:12:9
|
LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
| ^^^^^^^^^^------------^
// If `binding` is allowed to influence `subpat`,
// this would create problems for the generalization aforementioned.
-#![feature(bindings_after_at)]
fn main() {
struct NotCopy;
error: cannot move out of value because it is borrowed
- --> $DIR/default-binding-modes-both-sides-independent.rs:27:9
+ --> $DIR/default-binding-modes-both-sides-independent.rs:26:9
|
LL | let ref a @ b = NotCopy;
| -----^^^-
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/default-binding-modes-both-sides-independent.rs:30:9
+ --> $DIR/default-binding-modes-both-sides-independent.rs:29:9
|
LL | let ref mut a @ b = NotCopy;
| ---------^^^-
| value borrowed, by `a`, here
error: cannot move out of value because it is borrowed
- --> $DIR/default-binding-modes-both-sides-independent.rs:35:12
+ --> $DIR/default-binding-modes-both-sides-independent.rs:34:12
|
LL | Ok(ref a @ b) | Err(b @ ref a) => {
| -----^^^-
| value borrowed, by `a`, here
error: borrow of moved value
- --> $DIR/default-binding-modes-both-sides-independent.rs:35:29
+ --> $DIR/default-binding-modes-both-sides-independent.rs:34:29
|
LL | Ok(ref a @ b) | Err(b @ ref a) => {
| -^^^-----
| move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait
error: cannot move out of value because it is borrowed
- --> $DIR/default-binding-modes-both-sides-independent.rs:43:9
+ --> $DIR/default-binding-modes-both-sides-independent.rs:42:9
|
LL | ref a @ b => {
| -----^^^-
| value borrowed, by `a`, here
error[E0382]: borrow of moved value
- --> $DIR/default-binding-modes-both-sides-independent.rs:30:9
+ --> $DIR/default-binding-modes-both-sides-independent.rs:29:9
|
LL | let ref mut a @ b = NotCopy;
| ^^^^^^^^^^^^- ------- move occurs because value has type `NotCopy`, which does not implement the `Copy` trait
+++ /dev/null
-fn main() {
- let x @ y = 0; //~ ERROR pattern bindings after an `@` are unstable
-}
+++ /dev/null
-error[E0658]: pattern bindings after an `@` are unstable
- --> $DIR/feature-gate-bindings_after_at.rs:2:13
- |
-LL | let x @ y = 0;
- | ^
- |
- = note: see issue #65490 <https://github.com/rust-lang/rust/issues/65490> for more information
- = help: add `#![feature(bindings_after_at)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
// check-pass
-#![feature(bindings_after_at)]
#![deny(unused_mut)]
fn main() {
-#![feature(bindings_after_at)]
-
fn main() {
let mut is_mut @ not_mut = 42;
&mut is_mut;
error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable
- --> $DIR/nested-binding-modes-mut.rs:6:5
+ --> $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`
| ^^^^^^^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable
- --> $DIR/nested-binding-modes-mut.rs:11:5
+ --> $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`
-#![feature(bindings_after_at)]
-
fn main() {
let ref is_ref @ is_val = 42;
*is_ref;
error[E0614]: type `{integer}` cannot be dereferenced
- --> $DIR/nested-binding-modes-ref.rs:6:5
+ --> $DIR/nested-binding-modes-ref.rs:4:5
|
LL | *is_val;
| ^^^^^^^
error[E0614]: type `{integer}` cannot be dereferenced
- --> $DIR/nested-binding-modes-ref.rs:11:5
+ --> $DIR/nested-binding-modes-ref.rs:9:5
|
LL | *is_val;
| ^^^^^^^
// run-pass
-#![feature(bindings_after_at)]
struct A { a: u8, b: u8 }
// Here we check that type ascription is syntactically invalid when
// not in the top position of a ascribing a let binding or function parameter.
-#![feature(bindings_after_at)]
// This has no effect.
// We include it to demonstrate that this is the case:
error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `@`
- --> $DIR/nested-type-ascription-syntactically-invalid.rs:19:15
+ --> $DIR/nested-type-ascription-syntactically-invalid.rs:18:15
|
LL | let a: u8 @ b = 0;
| ^ expected one of 7 possible tokens
error: expected one of `)`, `,`, `@`, or `|`, found `:`
- --> $DIR/nested-type-ascription-syntactically-invalid.rs:25:15
+ --> $DIR/nested-type-ascription-syntactically-invalid.rs:24:15
|
LL | let a @ (b: u8);
| ^ expected one of `)`, `,`, `@`, or `|`
error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `)`
- --> $DIR/nested-type-ascription-syntactically-invalid.rs:25:19
+ --> $DIR/nested-type-ascription-syntactically-invalid.rs:24:19
|
LL | let a @ (b: u8);
| ^ expected one of 7 possible tokens
error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `@`
- --> $DIR/nested-type-ascription-syntactically-invalid.rs:32:15
+ --> $DIR/nested-type-ascription-syntactically-invalid.rs:31:15
|
LL | let a: T1 @ Outer(b: T2);
| ^ expected one of 7 possible tokens
// run-pass
-#![feature(bindings_after_at)]
#![feature(box_patterns)]
#[derive(Debug, PartialEq)]
// run-pass
-#![feature(bindings_after_at)]
#[derive(Debug, PartialEq)]
enum MatchArm {
// run-pass
-#![feature(bindings_after_at)]
#[derive(Debug, PartialEq)]
enum MatchArm {
// Test that `binding @ subpat` acts as a product context with respect to duplicate binding names.
// The code that is tested here lives in resolve (see `resolve_pattern_inner`).
-#![feature(bindings_after_at)]
fn main() {
fn f(a @ a @ a: ()) {}
error[E0415]: identifier `a` is bound more than once in this parameter list
- --> $DIR/pat-at-same-name-both.rs:7:14
+ --> $DIR/pat-at-same-name-both.rs:6:14
|
LL | fn f(a @ a @ a: ()) {}
| ^ used as parameter more than once
error[E0415]: identifier `a` is bound more than once in this parameter list
- --> $DIR/pat-at-same-name-both.rs:7:18
+ --> $DIR/pat-at-same-name-both.rs:6:18
|
LL | fn f(a @ a @ a: ()) {}
| ^ used as parameter more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
- --> $DIR/pat-at-same-name-both.rs:12:20
+ --> $DIR/pat-at-same-name-both.rs:11:20
|
LL | Ok(a @ b @ a)
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
- --> $DIR/pat-at-same-name-both.rs:14:23
+ --> $DIR/pat-at-same-name-both.rs:13:23
|
LL | | Err(a @ b @ a)
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
- --> $DIR/pat-at-same-name-both.rs:19:13
+ --> $DIR/pat-at-same-name-both.rs:18:13
|
LL | let a @ a @ a = ();
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
- --> $DIR/pat-at-same-name-both.rs:19:17
+ --> $DIR/pat-at-same-name-both.rs:18:17
|
LL | let a @ a @ a = ();
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
- --> $DIR/pat-at-same-name-both.rs:22:21
+ --> $DIR/pat-at-same-name-both.rs:21:21
|
LL | let ref a @ ref a = ();
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
- --> $DIR/pat-at-same-name-both.rs:24:29
+ --> $DIR/pat-at-same-name-both.rs:23:29
|
LL | let ref mut a @ ref mut a = ();
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
- --> $DIR/pat-at-same-name-both.rs:27:17
+ --> $DIR/pat-at-same-name-both.rs:26:17
|
LL | let a @ (Ok(a) | Err(a)) = Ok(());
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
- --> $DIR/pat-at-same-name-both.rs:27:26
+ --> $DIR/pat-at-same-name-both.rs:26:26
|
LL | let a @ (Ok(a) | Err(a)) = Ok(());
| ^ used in a pattern more than once
// run-pass
-#![feature(bindings_after_at)]
#[derive(Debug, PartialEq)]
enum MatchArm {
// check-pass
-#![feature(bindings_after_at)]
-
fn main() {
return;
// general; this test is relying on that.)
two_fifty_six_variant_enum!(Visible2, N8);
- #[repr(no_niche)]
- two_fifty_six_variant_enum!(Cloaked2, N8);
+ two_fifty_six_variant_enum!(#[repr(no_niche)] Cloaked2, N8);
}
mod enum_param {
// here as above (assuming `T` is instantiated with `NonZeroU8`).
two_fifty_six_variant_enum!(Visible2<T>);
- #[repr(no_niche)]
- two_fifty_six_variant_enum!(Cloaked2<T>);
+ two_fifty_six_variant_enum!(#[repr(no_niche)] Cloaked2<T>);
}
fn main() {
}
macro two_fifty_six_variant_enum {
- ($name:ident<$param:ident>) => {
- #[derive(Debug)]
+ ($(#[$attr:meta])* $name:ident<$param:ident>) => {
+ #[derive(Debug)] $(#[$attr])*
pub enum $name<$param> {
_V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param),
_V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param),
}
},
- ($name:ident, $param:ty) => {
- #[derive(Debug)]
+ ($(#[$attr:meta])* $name:ident, $param:ty) => {
+ #[derive(Debug)] $(#[$attr])*
pub enum $name {
_V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param),
_V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param),
error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:48
+ --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:37
|
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
- | - ^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+ | - ^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
| |
| let's call the lifetime of this reference `'1`
|
-error[E0277]: the size for values of type `T` cannot be known at compilation time
- --> $DIR/adt-param-with-implicit-sized-bound.rs:25:9
- |
-LL | struct X<T>(T);
- | - required by this bound in `X`
-...
-LL | struct Struct5<T: ?Sized>{
- | - this type parameter needs to be `std::marker::Sized`
-LL | _t: X<T>,
- | ^^^^ doesn't have a size known at compile-time
- |
-help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
- --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10
- |
-LL | struct X<T>(T);
- | ^ - ...if indirection were used here: `Box<T>`
- | |
- | this could be changed to `T: ?Sized`...
-
error[E0277]: the size for values of type `Self` cannot be known at compilation time
--> $DIR/adt-param-with-implicit-sized-bound.rs:2:19
|
LL | struct Struct4<T: ?Sized>{
| ^^^^^^^^
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+ --> $DIR/adt-param-with-implicit-sized-bound.rs:25:9
+ |
+LL | struct X<T>(T);
+ | - required by this bound in `X`
+...
+LL | struct Struct5<T: ?Sized>{
+ | - this type parameter needs to be `std::marker::Sized`
+LL | _t: X<T>,
+ | ^^^^ doesn't have a size known at compile-time
+ |
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+ --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10
+ |
+LL | struct X<T>(T);
+ | ^ - ...if indirection were used here: `Box<T>`
+ | |
+ | this could be changed to `T: ?Sized`...
+
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0277`.
error[E0038]: the trait `Trait` cannot be made into an object
- --> $DIR/object-unsafe-trait-references-self.rs:6:11
+ --> $DIR/object-unsafe-trait-references-self.rs:6:12
|
LL | fn bar(x: &dyn Trait) {}
- | ^^^^^^^^^^ `Trait` cannot be made into an object
+ | ^^^^^^^^^ `Trait` cannot be made into an object
|
= help: consider moving `baz` to another trait
= help: consider moving `bat` to another trait
| ^^^^ ...because method `bat` references the `Self` type in its return type
error[E0038]: the trait `Other` cannot be made into an object
- --> $DIR/object-unsafe-trait-references-self.rs:10:11
+ --> $DIR/object-unsafe-trait-references-self.rs:10:12
|
LL | fn foo(x: &dyn Other) {}
- | ^^^^^^^^^^ `Other` cannot be made into an object
+ | ^^^^^^^^^ `Other` 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/object-unsafe-trait-references-self.rs:8:14
+error[E0307]: invalid `self` parameter type: ()
+ --> $DIR/object-unsafe-trait-should-use-where-sized.rs:6:18
+ |
+LL | fn bar(self: ()) {}
+ | ^^
+ |
+ = note: type of `self` must be `Self` or a type that dereferences to it
+ = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
error[E0038]: the trait `Trait` cannot be made into an object
- --> $DIR/object-unsafe-trait-should-use-where-sized.rs:9:11
+ --> $DIR/object-unsafe-trait-should-use-where-sized.rs:9:12
|
LL | fn bar(x: &dyn Trait) {}
- | ^^^^^^^^^^ `Trait` cannot be made into an object
+ | ^^^^^^^^^ `Trait` 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/object-unsafe-trait-should-use-where-sized.rs:5:8
LL | fn bar(self: &Self) {}
| ^^^^^
-error[E0307]: invalid `self` parameter type: ()
- --> $DIR/object-unsafe-trait-should-use-where-sized.rs:6:18
- |
-LL | fn bar(self: ()) {}
- | ^^
- |
- = note: type of `self` must be `Self` or a type that dereferences to it
- = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
-
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0038, E0307.
--- /dev/null
+// build-fail
+#![feature(rustc_attrs)]
+
+#[rustc_dump_vtable]
+trait A {
+ fn foo_a(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait B: A {
+ fn foo_b(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait C: A {
+ //~^ error Vtable
+ fn foo_c(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait D: B + C {
+ //~^ error Vtable
+ fn foo_d(&self) {}
+}
+
+struct S;
+
+impl A for S {}
+impl B for S {}
+impl C for S {}
+impl D for S {}
+
+fn foo(d: &dyn D) {
+ d.foo_d();
+}
+
+fn main() {
+ foo(&S);
+}
--- /dev/null
+error: Vtable entries for `<S as D>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as A>::foo_a),
+ Method(<S as B>::foo_b),
+ Method(<S as C>::foo_c),
+ TraitVPtr(<S as C>),
+ Method(<S as D>::foo_d),
+]
+ --> $DIR/vtable-diamond.rs:21:1
+ |
+LL | / trait D: B + C {
+LL | |
+LL | | fn foo_d(&self) {}
+LL | | }
+ | |_^
+
+error: Vtable entries for `<S as C>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as A>::foo_a),
+ Method(<S as C>::foo_c),
+]
+ --> $DIR/vtable-diamond.rs:15:1
+ |
+LL | / trait C: A {
+LL | |
+LL | | fn foo_c(&self) {}
+LL | | }
+ | |_^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// build-fail
+#![feature(rustc_attrs)]
+
+// O --> G --> C --> A
+// \ \ \-> B
+// | |-> F --> D
+// | \-> E
+// |-> N --> J --> H
+// \ \-> I
+// |-> M --> K
+// \-> L
+
+#[rustc_dump_vtable]
+trait A {
+ fn foo_a(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait B {
+ //~^ error Vtable
+ fn foo_b(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait C: A + B {
+ fn foo_c(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait D {
+ //~^ error Vtable
+ fn foo_d(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait E {
+ //~^ error Vtable
+ fn foo_e(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait F: D + E {
+ //~^ error Vtable
+ fn foo_f(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait G: C + F {
+ fn foo_g(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait H {
+ //~^ error Vtable
+ fn foo_h(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait I {
+ //~^ error Vtable
+ fn foo_i(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait J: H + I {
+ //~^ error Vtable
+ fn foo_j(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait K {
+ //~^ error Vtable
+ fn foo_k(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait L {
+ //~^ error Vtable
+ fn foo_l(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait M: K + L {
+ //~^ error Vtable
+ fn foo_m(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait N: J + M {
+ //~^ error Vtable
+ fn foo_n(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait O: G + N {
+ //~^ error Vtable
+ fn foo_o(&self) {}
+}
+
+struct S;
+
+impl A for S {}
+impl B for S {}
+impl C for S {}
+impl D for S {}
+impl E for S {}
+impl F for S {}
+impl G for S {}
+impl H for S {}
+impl I for S {}
+impl J for S {}
+impl K for S {}
+impl L for S {}
+impl M for S {}
+impl N for S {}
+impl O for S {}
+
+fn foo(_: &dyn O) {}
+
+fn main() {
+ foo(&S);
+}
--- /dev/null
+error: Vtable entries for `<S as O>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as A>::foo_a),
+ Method(<S as B>::foo_b),
+ TraitVPtr(<S as B>),
+ Method(<S as C>::foo_c),
+ Method(<S as D>::foo_d),
+ TraitVPtr(<S as D>),
+ Method(<S as E>::foo_e),
+ TraitVPtr(<S as E>),
+ Method(<S as F>::foo_f),
+ TraitVPtr(<S as F>),
+ Method(<S as G>::foo_g),
+ Method(<S as H>::foo_h),
+ TraitVPtr(<S as H>),
+ Method(<S as I>::foo_i),
+ TraitVPtr(<S as I>),
+ Method(<S as J>::foo_j),
+ TraitVPtr(<S as J>),
+ Method(<S as K>::foo_k),
+ TraitVPtr(<S as K>),
+ Method(<S as L>::foo_l),
+ TraitVPtr(<S as L>),
+ Method(<S as M>::foo_m),
+ TraitVPtr(<S as M>),
+ Method(<S as N>::foo_n),
+ TraitVPtr(<S as N>),
+ Method(<S as O>::foo_o),
+]
+ --> $DIR/vtable-multi-level.rs:95:1
+ |
+LL | / trait O: G + N {
+LL | |
+LL | | fn foo_o(&self) {}
+LL | | }
+ | |_^
+
+error: Vtable entries for `<S as B>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as B>::foo_b),
+]
+ --> $DIR/vtable-multi-level.rs:19:1
+ |
+LL | / trait B {
+LL | |
+LL | | fn foo_b(&self) {}
+LL | | }
+ | |_^
+
+error: Vtable entries for `<S as D>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as D>::foo_d),
+]
+ --> $DIR/vtable-multi-level.rs:30:1
+ |
+LL | / trait D {
+LL | |
+LL | | fn foo_d(&self) {}
+LL | | }
+ | |_^
+
+error: Vtable entries for `<S as E>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as E>::foo_e),
+]
+ --> $DIR/vtable-multi-level.rs:36:1
+ |
+LL | / trait E {
+LL | |
+LL | | fn foo_e(&self) {}
+LL | | }
+ | |_^
+
+error: Vtable entries for `<S as F>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as D>::foo_d),
+ Method(<S as E>::foo_e),
+ TraitVPtr(<S as E>),
+ Method(<S as F>::foo_f),
+]
+ --> $DIR/vtable-multi-level.rs:42:1
+ |
+LL | / trait F: D + E {
+LL | |
+LL | | fn foo_f(&self) {}
+LL | | }
+ | |_^
+
+error: Vtable entries for `<S as H>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as H>::foo_h),
+]
+ --> $DIR/vtable-multi-level.rs:53:1
+ |
+LL | / trait H {
+LL | |
+LL | | fn foo_h(&self) {}
+LL | | }
+ | |_^
+
+error: Vtable entries for `<S as I>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as I>::foo_i),
+]
+ --> $DIR/vtable-multi-level.rs:59:1
+ |
+LL | / trait I {
+LL | |
+LL | | fn foo_i(&self) {}
+LL | | }
+ | |_^
+
+error: Vtable entries for `<S as J>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as H>::foo_h),
+ Method(<S as I>::foo_i),
+ TraitVPtr(<S as I>),
+ Method(<S as J>::foo_j),
+]
+ --> $DIR/vtable-multi-level.rs:65:1
+ |
+LL | / trait J: H + I {
+LL | |
+LL | | fn foo_j(&self) {}
+LL | | }
+ | |_^
+
+error: Vtable entries for `<S as K>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as K>::foo_k),
+]
+ --> $DIR/vtable-multi-level.rs:71:1
+ |
+LL | / trait K {
+LL | |
+LL | | fn foo_k(&self) {}
+LL | | }
+ | |_^
+
+error: Vtable entries for `<S as L>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as L>::foo_l),
+]
+ --> $DIR/vtable-multi-level.rs:77:1
+ |
+LL | / trait L {
+LL | |
+LL | | fn foo_l(&self) {}
+LL | | }
+ | |_^
+
+error: Vtable entries for `<S as M>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as K>::foo_k),
+ Method(<S as L>::foo_l),
+ TraitVPtr(<S as L>),
+ Method(<S as M>::foo_m),
+]
+ --> $DIR/vtable-multi-level.rs:83:1
+ |
+LL | / trait M: K + L {
+LL | |
+LL | | fn foo_m(&self) {}
+LL | | }
+ | |_^
+
+error: Vtable entries for `<S as N>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as H>::foo_h),
+ Method(<S as I>::foo_i),
+ TraitVPtr(<S as I>),
+ Method(<S as J>::foo_j),
+ Method(<S as K>::foo_k),
+ TraitVPtr(<S as K>),
+ Method(<S as L>::foo_l),
+ TraitVPtr(<S as L>),
+ Method(<S as M>::foo_m),
+ TraitVPtr(<S as M>),
+ Method(<S as N>::foo_n),
+]
+ --> $DIR/vtable-multi-level.rs:89:1
+ |
+LL | / trait N: J + M {
+LL | |
+LL | | fn foo_n(&self) {}
+LL | | }
+ | |_^
+
+error: aborting due to 12 previous errors
+
--- /dev/null
+// build-fail
+#![feature(rustc_attrs)]
+
+#[rustc_dump_vtable]
+trait A {
+ fn foo_a(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait B {
+ //~^ error Vtable
+ fn foo_b(&self) {}
+}
+
+#[rustc_dump_vtable]
+trait C: A + B {
+ //~^ error Vtable
+ fn foo_c(&self) {}
+}
+
+struct S;
+
+impl A for S {}
+impl B for S {}
+impl C for S {}
+
+fn foo(c: &dyn C) {}
+
+fn main() {
+ foo(&S);
+}
--- /dev/null
+error: Vtable entries for `<S as C>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as A>::foo_a),
+ Method(<S as B>::foo_b),
+ TraitVPtr(<S as B>),
+ Method(<S as C>::foo_c),
+]
+ --> $DIR/vtable-multiple.rs:16:1
+ |
+LL | / trait C: A + B {
+LL | |
+LL | | fn foo_c(&self) {}
+LL | | }
+ | |_^
+
+error: Vtable entries for `<S as B>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as B>::foo_b),
+]
+ --> $DIR/vtable-multiple.rs:10:1
+ |
+LL | / trait B {
+LL | |
+LL | | fn foo_b(&self) {}
+LL | | }
+ | |_^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// build-fail
+#![feature(rustc_attrs)]
+
+// B --> A
+
+#[rustc_dump_vtable]
+trait A {
+ fn foo_a1(&self) {}
+ fn foo_a2(&self) where Self: Sized {}
+}
+
+#[rustc_dump_vtable]
+trait B: A {
+ //~^ error Vtable
+ fn foo_b1(&self) {}
+ fn foo_b2() where Self: Sized {}
+}
+
+struct S;
+
+impl A for S {}
+impl B for S {}
+
+fn foo(_: &dyn B) {}
+
+fn main() {
+ foo(&S);
+}
--- /dev/null
+error: Vtable entries for `<S as B>`: [
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Method(<S as A>::foo_a1),
+ Vacant,
+ Method(<S as B>::foo_b1),
+ Vacant,
+]
+ --> $DIR/vtable-vacant.rs:13:1
+ |
+LL | / trait B: A {
+LL | |
+LL | | fn foo_b1(&self) {}
+LL | | fn foo_b2() where Self: Sized {}
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
found opaque type `impl Sized`
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/generic_type_does_not_live_long_enough.rs:17:30
+ --> $DIR/generic_type_does_not_live_long_enough.rs:16:30
|
LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
| ^^^^^^^^^^^^^^^
LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
| - help: consider adding an explicit lifetime bound...: `T: 'static`
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/generic_type_does_not_live_long_enough.rs:12:24
- |
-LL | type WrongGeneric<T> = impl 'static;
- | ^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'static`...
- = note: ...so that the type `T` will meet its required lifetime bounds
-
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 3 previous errors; 1 warning emitted
Some errors have detailed explanations: E0308, E0310.
For more information about an error, try `rustc --explain E0308`.
found opaque type `impl Sized`
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/generic_type_does_not_live_long_enough.rs:17:30
+ --> $DIR/generic_type_does_not_live_long_enough.rs:16:30
|
LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
| ^^^^^^^^^^^^^^^
LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
| - help: consider adding an explicit lifetime bound...: `T: 'static`
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/generic_type_does_not_live_long_enough.rs:12:24
- |
-LL | type WrongGeneric<T> = impl 'static;
- | ^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: 'static`...
- = note: ...so that the type `T` will meet its required lifetime bounds
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
Some errors have detailed explanations: E0308, E0310.
For more information about an error, try `rustc --explain E0308`.
type WrongGeneric<T> = impl 'static;
//~^ ERROR the parameter type `T` may not live long enough
-//~| ERROR the parameter type `T` may not live long enough
//~| ERROR: at least one trait must be specified
fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
= note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
error: higher-ranked subtype error
- --> $DIR/issue-57611-trait-alias.rs:28:9
+ --> $DIR/issue-57611-trait-alias.rs:24:9
|
LL | |x| x
| ^^^^^
error: higher-ranked subtype error
- --> $DIR/issue-57611-trait-alias.rs:28:9
+ --> $DIR/issue-57611-trait-alias.rs:24:9
|
LL | |x| x
| ^^^^^
= note: expected type `for<'r> Fn<(&'r X,)>`
found type `Fn<(&'static X,)>`
note: this closure does not fulfill the lifetime requirements
- --> $DIR/issue-57611-trait-alias.rs:28:9
+ --> $DIR/issue-57611-trait-alias.rs:24:9
|
LL | |x| x
| ^^^^^
= note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
-error[E0308]: mismatched types
- --> $DIR/issue-57611-trait-alias.rs:20:16
- |
-LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
- |
- = note: expected type `for<'r> Fn<(&'r X,)>`
- found type `Fn<(&'<empty> X,)>`
-note: this closure does not fulfill the lifetime requirements
- --> $DIR/issue-57611-trait-alias.rs:28:9
- |
-LL | |x| x
- | ^^^^^
-
-error: implementation of `FnOnce` is not general enough
- --> $DIR/issue-57611-trait-alias.rs:20:16
- |
-LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
- |
- = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
- = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
-
-error[E0308]: mismatched types
- --> $DIR/issue-57611-trait-alias.rs:20:16
- |
-LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
- |
- = note: expected type `for<'r> Fn<(&'r X,)>`
- found type `Fn<(&'<empty> X,)>`
-note: this closure does not fulfill the lifetime requirements
- --> $DIR/issue-57611-trait-alias.rs:28:9
- |
-LL | |x| x
- | ^^^^^
-
-error: implementation of `FnOnce` is not general enough
- --> $DIR/issue-57611-trait-alias.rs:20:16
- |
-LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
- |
- = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
- = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
-
-error: aborting due to 5 previous errors; 1 warning emitted
+error: aborting due to previous error; 1 warning emitted
-For more information about this error, try `rustc --explain E0308`.
error: higher-ranked subtype error
- --> $DIR/issue-57611-trait-alias.rs:28:9
+ --> $DIR/issue-57611-trait-alias.rs:24:9
|
LL | |x| x
| ^^^^^
error: higher-ranked subtype error
- --> $DIR/issue-57611-trait-alias.rs:28:9
+ --> $DIR/issue-57611-trait-alias.rs:24:9
|
LL | |x| x
| ^^^^^
= note: expected type `for<'r> Fn<(&'r X,)>`
found type `Fn<(&'static X,)>`
note: this closure does not fulfill the lifetime requirements
- --> $DIR/issue-57611-trait-alias.rs:28:9
+ --> $DIR/issue-57611-trait-alias.rs:24:9
|
LL | |x| x
| ^^^^^
= note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
-error[E0308]: mismatched types
- --> $DIR/issue-57611-trait-alias.rs:20:16
- |
-LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
- |
- = note: expected type `for<'r> Fn<(&'r X,)>`
- found type `Fn<(&'<empty> X,)>`
-note: this closure does not fulfill the lifetime requirements
- --> $DIR/issue-57611-trait-alias.rs:28:9
- |
-LL | |x| x
- | ^^^^^
-
-error: implementation of `FnOnce` is not general enough
- --> $DIR/issue-57611-trait-alias.rs:20:16
- |
-LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
- |
- = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
- = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
-
-error[E0308]: mismatched types
- --> $DIR/issue-57611-trait-alias.rs:20:16
- |
-LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
- |
- = note: expected type `for<'r> Fn<(&'r X,)>`
- found type `Fn<(&'<empty> X,)>`
-note: this closure does not fulfill the lifetime requirements
- --> $DIR/issue-57611-trait-alias.rs:28:9
- |
-LL | |x| x
- | ^^^^^
-
-error: implementation of `FnOnce` is not general enough
- --> $DIR/issue-57611-trait-alias.rs:20:16
- |
-LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
- |
- = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
- = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
-
-error: aborting due to 5 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0308`.
impl Foo for X {
type Bar = impl Baz<Self, Self>;
//~^ ERROR implementation of `FnOnce` is not general enough
- //~| ERROR implementation of `FnOnce` is not general enough
- //~| ERROR implementation of `FnOnce` is not general enough
- //~| ERROR mismatched types
- //~| ERROR mismatched types
fn bar(&self) -> Self::Bar {
|x| x
impl Bug for &() {
type Item = impl Bug; //~ ERROR `impl Trait` in type aliases is unstable
//~^ ERROR the trait bound `(): Bug` is not satisfied
- //~^^ ERROR the trait bound `(): Bug` is not satisfied
const FUN: fn() -> Self::Item = || ();
//~^ ERROR type alias impl trait is not permitted here
= help: add `#![feature(min_type_alias_impl_trait)]` to the crate attributes to enable
error[E0658]: type alias impl trait is not permitted here
- --> $DIR/issue-60371.rs:14:40
+ --> $DIR/issue-60371.rs:13:40
|
LL | const FUN: fn() -> Self::Item = || ();
| ^
= help: the following implementations were found:
<&() as Bug>
-error[E0277]: the trait bound `(): Bug` is not satisfied
- --> $DIR/issue-60371.rs:10:17
- |
-LL | type Item = impl Bug;
- | ^^^^^^^^ the trait `Bug` is not implemented for `()`
- |
- = help: the following implementations were found:
- <&() as Bug>
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
Some errors have detailed explanations: E0277, E0658.
For more information about an error, try `rustc --explain E0277`.
--- /dev/null
+#![feature(member_constraints)]
+#![feature(type_alias_impl_trait)]
+//~^ WARN incomplete
+
+pub trait A {
+ type B;
+ fn f(&self) -> Self::B;
+}
+impl<'a, 'b> A for () {
+ //~^ ERROR the lifetime parameter `'a` is not constrained
+ //~| ERROR the lifetime parameter `'b` is not constrained
+ type B = impl core::fmt::Debug;
+ //~^ ERROR is unstable
+
+
+ fn f(&self) -> Self::B {}
+}
+
+fn main() {}
--- /dev/null
+error[E0658]: `impl Trait` in type aliases is unstable
+ --> $DIR/issue-74761-2.rs:12:14
+ |
+LL | type B = impl core::fmt::Debug;
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
+ = help: add `#![feature(min_type_alias_impl_trait)]` to the crate attributes to enable
+
+warning: the feature `type_alias_impl_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-74761-2.rs:2:12
+ |
+LL | #![feature(type_alias_impl_trait)]
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
+
+error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
+ --> $DIR/issue-74761-2.rs:9:6
+ |
+LL | impl<'a, 'b> A for () {
+ | ^^ unconstrained lifetime parameter
+
+error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates
+ --> $DIR/issue-74761-2.rs:9:10
+ |
+LL | impl<'a, 'b> A for () {
+ | ^^ unconstrained lifetime parameter
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0207, E0658.
+For more information about an error, try `rustc --explain E0207`.
#![feature(min_type_alias_impl_trait)]
type X<A: ToString + Clone, B: ToString + Clone> = impl ToString;
-//~^ ERROR could not find defining uses
fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<B, A>) {
+ //~^ ERROR concrete type differs from previous defining opaque type
(a.clone(), a)
}
-error: could not find defining uses
- --> $DIR/multiple-def-uses-in-one-fn2.rs:7:52
+error: concrete type differs from previous defining opaque type use
+ --> $DIR/multiple-def-uses-in-one-fn2.rs:9:1
|
-LL | type X<A: ToString + Clone, B: ToString + Clone> = impl ToString;
- | ^^^^^^^^^^^^^
+LL | fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<B, A>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `A`, got `B`
+ |
+note: previous use here
+ --> $DIR/multiple-def-uses-in-one-fn2.rs:9:1
+ |
+LL | fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<B, A>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
}
fn g<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) {
+ //~^ ERROR concrete type differs from previous defining opaque type
(a, b)
//~^ ERROR mismatched types
}
error[E0308]: mismatched types
- --> $DIR/multiple-def-uses-in-one-fn3.rs:14:9
+ --> $DIR/multiple-def-uses-in-one-fn3.rs:15:9
|
LL | fn g<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) {
| - - found type parameter
| |
| expected type parameter
+LL |
LL | (a, b)
| ^ expected type parameter `A`, found type parameter `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
-error: aborting due to previous error
+error: concrete type differs from previous defining opaque type use
+ --> $DIR/multiple-def-uses-in-one-fn3.rs:13:1
+ |
+LL | fn g<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `A`, got `[type error]`
+ |
+note: previous use here
+ --> $DIR/multiple-def-uses-in-one-fn3.rs:9:1
+ |
+LL | fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<B, A>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// Regression test for the ICE described in #83693.
+
+#![feature(fn_traits)]
+#![crate_type="lib"]
+
+impl F {
+//~^ ERROR: cannot find type `F` in this scope [E0412]
+ fn call() {
+ <Self as Fn(&TestResult)>::call
+ //~^ ERROR: cannot find type `TestResult` in this scope [E0412]
+ //~| associated type bindings are not allowed here [E0229]
+ }
+}
+
+fn call() {
+ <x as Fn(&usize)>::call
+ //~^ ERROR: cannot find type `x` in this scope [E0412]
+ //~| ERROR: associated type bindings are not allowed here [E0229]
+}
--- /dev/null
+error[E0412]: cannot find type `F` in this scope
+ --> $DIR/issue-83693.rs:6:6
+ |
+LL | impl F {
+ | ^ help: a trait with a similar name exists: `Fn`
+ |
+ ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+ |
+LL | pub trait Fn<Args>: FnMut<Args> {
+ | ------------------------------- similarly named trait `Fn` defined here
+
+error[E0412]: cannot find type `TestResult` in this scope
+ --> $DIR/issue-83693.rs:9:22
+ |
+LL | <Self as Fn(&TestResult)>::call
+ | ^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `x` in this scope
+ --> $DIR/issue-83693.rs:16:6
+ |
+LL | <x as Fn(&usize)>::call
+ | ^ not found in this scope
+
+error[E0229]: associated type bindings are not allowed here
+ --> $DIR/issue-83693.rs:9:18
+ |
+LL | <Self as Fn(&TestResult)>::call
+ | ^^^^^^^^^^^^^^^ associated type not allowed here
+
+error[E0229]: associated type bindings are not allowed here
+ --> $DIR/issue-83693.rs:16:11
+ |
+LL | <x as Fn(&usize)>::call
+ | ^^^^^^^^^^ associated type not allowed here
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0229, E0412.
+For more information about an error, try `rustc --explain E0229`.
--- /dev/null
+// Regression test for the ICE described in #84768.
+
+#![feature(fn_traits)]
+#![crate_type="lib"]
+
+fn transform_mut<F>(f: F) where F: for<'b> FnOnce(&'b mut u8) {
+ <F as FnOnce(&mut u8)>::call_once(f, 1)
+ //~^ ERROR: associated type bindings are not allowed here [E0229]
+ //~| ERROR: mismatched types [E0308]
+}
--- /dev/null
+error[E0229]: associated type bindings are not allowed here
+ --> $DIR/issue-84768.rs:7:11
+ |
+LL | <F as FnOnce(&mut u8)>::call_once(f, 1)
+ | ^^^^^^^^^^^^^^^ associated type not allowed here
+
+error[E0308]: mismatched types
+ --> $DIR/issue-84768.rs:7:42
+ |
+LL | <F as FnOnce(&mut u8)>::call_once(f, 1)
+ | ^ expected tuple, found integer
+ |
+ = note: expected tuple `(&mut u8,)`
+ found type `{integer}`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0229, E0308.
+For more information about an error, try `rustc --explain E0229`.
fn assign_noncopy_union_field(mut u: URefCell) {
// FIXME(thir-unsafeck)
- u.a = (RefCell::new(0), 1); //[mir]~ ERROR assignment to union field that might need dropping
- u.a.0 = RefCell::new(0); //[mir]~ ERROR assignment to union field that might need dropping
+ u.a = (RefCell::new(0), 1); //~ ERROR assignment to union field that might need dropping
+ u.a.0 = RefCell::new(0); //~ ERROR assignment to union field that might need dropping
u.a.1 = 1; // OK
}
|
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:39:5
+ |
+LL | u.a = (RefCell::new(0), 1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
+ |
+ = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
+
+error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
+ --> $DIR/union-unsafe.rs:40:5
+ |
+LL | u.a.0 = RefCell::new(0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
+ |
+ = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
+
error[E0133]: access to union field is unsafe and requires unsafe function or block
--> $DIR/union-unsafe.rs:47:6
|
|
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
-error: aborting due to 9 previous errors
+error: aborting due to 11 previous errors
For more information about this error, try `rustc --explain E0133`.
error[E0277]: the trait bound `(): Foo` is not satisfied
- --> $DIR/wf-foreign-fn-decl-ret.rs:11:12
+ --> $DIR/wf-foreign-fn-decl-ret.rs:11:25
|
+LL | pub trait Foo {
+ | ------------- required by this bound in `Foo`
+...
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[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/wf-in-fn-arg.rs:10:14
+ --> $DIR/wf-in-fn-arg.rs:10:15
|
LL | struct MustBeCopy<T:Copy> {
| ---- required by this bound in `MustBeCopy`
...
LL | fn bar<T>(_: &MustBeCopy<T>)
- | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
+ | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
|
help: consider restricting type parameter `T`
|
error[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/wf-in-fn-type-arg.rs:9:8
+ --> $DIR/wf-in-fn-type-arg.rs:9:11
|
LL | struct MustBeCopy<T:Copy> {
| ---- required by this bound in `MustBeCopy`
...
LL | x: fn(MustBeCopy<T>)
- | ^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
+ | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
|
help: consider restricting type parameter `T`
|
error[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/wf-in-fn-type-ret.rs:9:8
+ --> $DIR/wf-in-fn-type-ret.rs:9:16
|
LL | struct MustBeCopy<T:Copy> {
| ---- required by this bound in `MustBeCopy`
...
LL | x: fn() -> MustBeCopy<T>
- | ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
+ | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
|
help: consider restricting type parameter `T`
|
error[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/wf-in-obj-type-trait.rs:11:8
+ --> $DIR/wf-in-obj-type-trait.rs:11:19
|
LL | struct MustBeCopy<T:Copy> {
| ---- required by this bound in `MustBeCopy`
...
LL | x: dyn Object<MustBeCopy<T>>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
+ | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
|
help: consider restricting type parameter `T`
|
error[E0277]: the trait bound `Self: Eq` is not satisfied
- --> $DIR/wf-trait-default-fn-arg.rs:11:22
+ --> $DIR/wf-trait-default-fn-arg.rs:11:23
|
LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
| -- required by this bound in `Bar`
...
LL | fn bar(&self, x: &Bar<Self>) {
- | ^^^^^^^^^^ the trait `Eq` is not implemented for `Self`
+ | ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
|
help: consider further restricting `Self`
|
error[E0277]: the trait bound `Self: Eq` is not satisfied
- --> $DIR/wf-trait-fn-arg.rs:10:22
+ --> $DIR/wf-trait-fn-arg.rs:10:23
|
LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
| -- required by this bound in `Bar`
...
LL | fn bar(&self, x: &Bar<Self>);
- | ^^^^^^^^^^ the trait `Eq` is not implemented for `Self`
+ | ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
|
help: consider further restricting `Self`
|
-Subproject commit 27277d966b3cfa454d6dea7f724cb961c036251c
+Subproject commit cebef2951ee69617852844894164b54ed478a7da
fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) {
let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
- self.check_missing_docs_attrs(cx, attrs, krate.item.inner, "the", "crate");
+ self.check_missing_docs_attrs(cx, attrs, krate.module().inner, "the", "crate");
}
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ^^ has type `std::rc::Rc<[u8]>` which is not `Send`
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
-note: captured value is not `Send`
+note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
--> $DIR/future_not_send.rs:20:40
|
LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
- | ^^^^ has type `&std::cell::Cell<usize>` which is not `Send`
+ | ^^^^ has type `&std::cell::Cell<usize>` which is not `Send`, because `std::cell::Cell<usize>` is not `Sync`
= note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
// a proc-macro and needs `#![crate_type = "proc-macro"]`. This ensures
// that the aux file is compiled as a `proc-macro` and not as a `dylib`.
pub no_prefer_dynamic: bool,
- // Run --pretty expanded when running pretty printing tests
+ // Run -Zunpretty expanded when running pretty printing tests
pub pretty_expanded: bool,
// Which pretty mode are we testing with, default to 'normal'
pub pretty_mode: String,
return;
}
- // additionally, run `--pretty expanded` and try to build it.
+ // additionally, run `-Zunpretty=expanded` and try to build it.
let proc_res = self.print_source(ReadFrom::Path, "expanded");
if !proc_res.status.success() {
self.fatal_proc_rec("pretty-printing (expanded) failed", &proc_res);
"MISSING_ENDTAG_BEFORE",
"INSERTING_TAG",
"DISCARDING_UNEXPECTED",
+ // This error is caused by nesting the Notable Traits tooltip within an <h4> tag.
+ // The solution is to avoid doing that, but we need to have the <h4> tags for accessibility
+ // reasons, and we need the Notable Traits tooltip to help everyone understand the Iterator
+ // combinators
+ "TAG_NOT_ALLOWED_IN",
];
let to_mute_s = to_mute.join(",");
let mut command = Command::new("tidy");
-Subproject commit 517e9d62c095a04fa497d6b6d3c63b31696a88b4
+Subproject commit a82a0527057eab59c24a0452add35ccb39584e80
-Subproject commit fe00358888a24c64878abc15f09b0e60e16db9d6
+Subproject commit ea105f9396a9dab68e71efb06016b7c76c83ba7c
[target.'cfg(windows)'.dependencies.winapi]
version = "0.3"
features = [
- "aclapi",
"accctrl",
+ "aclapi",
"basetsd",
+ "cfg",
"consoleapi",
"errhandlingapi",
+ "evntrace",
"fibersapi",
+ "in6addr",
+ "inaddr",
"ioapiset",
"jobapi",
"jobapi2",
"memoryapi",
"minschannel",
"minwinbase",
+ "mstcpip",
+ "mswsock",
"namedpipeapi",
"ntdef",
"ntsecapi",
"winbase",
"wincon",
"wincrypt",
+ "windef",
+ "winioctl",
"winsock2",
"ws2def",
"ws2ipdef",
const EXCEPTIONS: &[(&str, &str)] = &[
("mdbook", "MPL-2.0"), // mdbook
("openssl", "Apache-2.0"), // cargo, mdbook
- ("fuchsia-zircon-sys", "BSD-3-Clause"), // rustdoc, rustc, cargo
- ("fuchsia-zircon", "BSD-3-Clause"), // rustdoc, rustc, cargo (jobserver & tempdir)
- ("colored", "MPL-2.0"), // rustfmt
- ("ordslice", "Apache-2.0"), // rls
- ("ryu", "Apache-2.0 OR BSL-1.0"), // rls/cargo/... (because of serde)
- ("bytesize", "Apache-2.0"), // cargo
- ("im-rc", "MPL-2.0+"), // cargo
- ("sized-chunks", "MPL-2.0+"), // cargo via im-rc
- ("bitmaps", "MPL-2.0+"), // cargo via im-rc
+ ("colored", "MPL-2.0"), // rustfmt
+ ("ordslice", "Apache-2.0"), // rls
+ ("ryu", "Apache-2.0 OR BSL-1.0"), // rls/cargo/... (because of serde)
+ ("bytesize", "Apache-2.0"), // cargo
+ ("im-rc", "MPL-2.0+"), // cargo
+ ("sized-chunks", "MPL-2.0+"), // cargo via im-rc
+ ("bitmaps", "MPL-2.0+"), // cargo via im-rc
("crossbeam-queue", "MIT/Apache-2.0 AND BSD-2-Clause"), // rls via rayon
- ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot
- ("snap", "BSD-3-Clause"), // rustc
+ ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot
+ ("snap", "BSD-3-Clause"), // rustc
// FIXME: this dependency violates the documentation comment above:
("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
];
"fixedbitset",
"flate2",
"fortanix-sgx-abi",
- "fuchsia-zircon",
- "fuchsia-zircon-sys",
"generic-array",
"getopts",
"getrandom",
"itertools",
"itoa",
"jobserver",
- "kernel32-sys",
"lazy_static",
"libc",
"libz-sys",
"version_check",
"wasi",
"winapi",
- "winapi-build",
"winapi-i686-pc-windows-gnu",
"winapi-util",
"winapi-x86_64-pc-windows-gnu",
"""
message_on_remove = "Issue #{number}'s nomination request has been removed."
+[notify-zulip."A-edition-2021"]
+required_labels = ["C-bug"]
+zulip_stream = 268952 # #edition 2021
+topic = "Edition Bugs"
+message_on_add = """\
+Issue #{number} "{title}" has been added.
+"""
+
[github-releases]
format = "rustc"
project-name = "Rust"