mirror of
https://git.proxmox.com/git/rustc
synced 2025-12-04 08:38:45 +00:00
New upstream version 1.77.2+dfsg1
This commit is contained in:
parent
4b01247206
commit
c0240ec034
313
Cargo.lock
generated
313
Cargo.lock
generated
@ -119,6 +119,16 @@ dependencies = [
|
||||
"yansi-term",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "annotate-snippets"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a433302f833baa830c0092100c481c7ea768c5981a3c36f549517a502f246dd"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
@ -202,9 +212,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.12.0"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47cbc3cf73fa8d9833727bbee4835ba5c421a0d65b72daf9a7b5d0e0f9cfb57e"
|
||||
checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
"askama_escape",
|
||||
@ -212,14 +222,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.12.1"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c22fbe0413545c098358e56966ff22cdd039e10215ae213cfbd65032b119fc94"
|
||||
checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83"
|
||||
dependencies = [
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"nom",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
@ -232,6 +242,15 @@ version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
@ -285,9 +304,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
@ -363,9 +382,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
@ -537,7 +556,7 @@ checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
|
||||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.76"
|
||||
version = "0.1.77"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"clippy_config",
|
||||
@ -565,7 +584,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy_config"
|
||||
version = "0.1.76"
|
||||
version = "0.1.77"
|
||||
dependencies = [
|
||||
"rustc-semver",
|
||||
"serde",
|
||||
@ -577,21 +596,21 @@ dependencies = [
|
||||
name = "clippy_dev"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"aho-corasick 0.7.20",
|
||||
"aho-corasick 1.0.2",
|
||||
"clap",
|
||||
"indoc",
|
||||
"itertools",
|
||||
"opener 0.5.2",
|
||||
"opener",
|
||||
"shell-escape",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.76"
|
||||
version = "0.1.77"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"cargo_metadata 0.15.4",
|
||||
"cargo_metadata 0.18.0",
|
||||
"clippy_config",
|
||||
"clippy_utils",
|
||||
"declare_clippy_lint",
|
||||
@ -613,7 +632,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.76"
|
||||
version = "0.1.77"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"clippy_config",
|
||||
@ -704,9 +723,9 @@ checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335"
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.103"
|
||||
version = "0.1.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3b73c3443a5fd2438d7ba4853c64e4c8efc2404a9e28a9234cc2d5eebc6c242"
|
||||
checksum = "3686cc48897ce1950aa70fd595bd2dc9f767a3c4cca4cd17b2cb52a2d37e6eb4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"rustc-std-workspace-core",
|
||||
@ -868,12 +887,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ctrlc"
|
||||
version = "3.4.0"
|
||||
version = "3.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e"
|
||||
checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -984,7 +1003,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
|
||||
|
||||
[[package]]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.76"
|
||||
version = "0.1.77"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"quote",
|
||||
@ -1249,7 +1268,6 @@ name = "error_index_generator"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"mdbook",
|
||||
"rustc_error_codes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2072,9 +2090,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.27"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
|
||||
checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@ -2177,16 +2195,6 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.1"
|
||||
@ -2342,7 +2350,7 @@ dependencies = [
|
||||
"log",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"opener 0.6.1",
|
||||
"opener",
|
||||
"pathdiff",
|
||||
"pulldown-cmark",
|
||||
"regex",
|
||||
@ -2356,9 +2364,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "measureme"
|
||||
version = "10.1.2"
|
||||
version = "11.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45e381dcdad44c3c435f8052b08c5c4a1449c48ab56f312345eae12d7a693dbe"
|
||||
checksum = "dfa4a40f09af7aa6faef38285402a78847d0d72bf8827006cd2a332e1e6e4a8d"
|
||||
dependencies = [
|
||||
"log",
|
||||
"memmap2",
|
||||
@ -2465,16 +2473,16 @@ dependencies = [
|
||||
"ctrlc",
|
||||
"env_logger",
|
||||
"getrandom",
|
||||
"jemalloc-sys",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"libffi",
|
||||
"libloading 0.8.1",
|
||||
"libloading",
|
||||
"log",
|
||||
"measureme",
|
||||
"rand",
|
||||
"regex",
|
||||
"rustc_version",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"ui_test",
|
||||
]
|
||||
@ -2512,14 +2520,13 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.26.2"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
|
||||
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2588,9 +2595,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.1"
|
||||
version = "0.32.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
|
||||
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"crc32fast",
|
||||
@ -2618,16 +2625,6 @@ version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "opener"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opener"
|
||||
version = "0.6.1"
|
||||
@ -2641,11 +2638,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.55"
|
||||
version = "0.10.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d"
|
||||
checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
@ -2673,9 +2670,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.90"
|
||||
version = "0.9.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6"
|
||||
checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@ -3006,11 +3003,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.9.3"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998"
|
||||
checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"memchr",
|
||||
"unicase",
|
||||
]
|
||||
@ -3280,9 +3277,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc-build-sysroot"
|
||||
version = "0.4.2"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ed2a90dfa5232ed5ff21d53d4df655f315ab316ea06fc508f1c74bcedb1ce6c"
|
||||
checksum = "39dcf8d82b1f79a179bdb284dc44db440a9666eefa5a6df5ef282d6db930d544"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"rustc_version",
|
||||
@ -3370,7 +3367,7 @@ dependencies = [
|
||||
name = "rustc_abi"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"rand",
|
||||
"rand_xoshiro",
|
||||
"rustc_data_structures",
|
||||
@ -3401,7 +3398,7 @@ dependencies = [
|
||||
name = "rustc_ast"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"memchr",
|
||||
"rustc_data_structures",
|
||||
"rustc_index",
|
||||
@ -3552,7 +3549,7 @@ dependencies = [
|
||||
name = "rustc_codegen_llvm"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"itertools",
|
||||
"libc",
|
||||
"measureme",
|
||||
@ -3587,7 +3584,7 @@ name = "rustc_codegen_ssa"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"ar_archive_writer",
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"cc",
|
||||
"itertools",
|
||||
"jobserver",
|
||||
@ -3654,11 +3651,11 @@ name = "rustc_data_structures"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"either",
|
||||
"elsa",
|
||||
"ena",
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"measureme",
|
||||
@ -3703,7 +3700,6 @@ dependencies = [
|
||||
"rustc_codegen_ssa",
|
||||
"rustc_const_eval",
|
||||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_errors",
|
||||
"rustc_expand",
|
||||
"rustc_feature",
|
||||
@ -3738,6 +3734,7 @@ dependencies = [
|
||||
"rustc_trait_selection",
|
||||
"rustc_ty_utils",
|
||||
"serde_json",
|
||||
"shlex",
|
||||
"time",
|
||||
"tracing",
|
||||
"windows",
|
||||
@ -3770,14 +3767,16 @@ dependencies = [
|
||||
name = "rustc_errors"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"annotate-snippets",
|
||||
"annotate-snippets 0.10.1",
|
||||
"derive_setters",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_error_messages",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_lint_defs",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
@ -3797,7 +3796,6 @@ dependencies = [
|
||||
name = "rustc_expand"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"rustc_ast",
|
||||
"rustc_ast_passes",
|
||||
"rustc_ast_pretty",
|
||||
@ -3831,7 +3829,7 @@ dependencies = [
|
||||
name = "rustc_fluent_macro"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"annotate-snippets",
|
||||
"annotate-snippets 0.10.1",
|
||||
"fluent-bundle",
|
||||
"fluent-syntax",
|
||||
"proc-macro2",
|
||||
@ -3869,6 +3867,7 @@ dependencies = [
|
||||
name = "rustc_hir_analysis"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
@ -3877,6 +3876,7 @@ dependencies = [
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_hir_pretty",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
"rustc_lint_defs",
|
||||
@ -3906,6 +3906,7 @@ dependencies = [
|
||||
name = "rustc_hir_typeck"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
"rustc_data_structures",
|
||||
@ -3992,7 +3993,7 @@ dependencies = [
|
||||
name = "rustc_interface"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"libloading 0.7.4",
|
||||
"libloading",
|
||||
"rustc-rayon",
|
||||
"rustc-rayon-core",
|
||||
"rustc_ast",
|
||||
@ -4121,8 +4122,8 @@ dependencies = [
|
||||
name = "rustc_metadata"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"libloading 0.7.4",
|
||||
"bitflags 2.4.1",
|
||||
"libloading",
|
||||
"odht",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
@ -4151,7 +4152,7 @@ dependencies = [
|
||||
name = "rustc_middle"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"derive_more",
|
||||
"either",
|
||||
"field-offset",
|
||||
@ -4189,6 +4190,7 @@ name = "rustc_mir_build"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"itertools",
|
||||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
@ -4286,7 +4288,7 @@ dependencies = [
|
||||
name = "rustc_parse"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_data_structures",
|
||||
@ -4340,6 +4342,7 @@ dependencies = [
|
||||
name = "rustc_pattern_analysis"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc-hash",
|
||||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
"rustc_data_structures",
|
||||
@ -4354,7 +4357,6 @@ dependencies = [
|
||||
"rustc_target",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
"typed-arena",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4423,7 +4425,7 @@ dependencies = [
|
||||
name = "rustc_resolve"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"pulldown-cmark",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
@ -4462,7 +4464,7 @@ dependencies = [
|
||||
name = "rustc_session"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"getopts",
|
||||
"libc",
|
||||
"rustc_ast",
|
||||
@ -4520,7 +4522,7 @@ dependencies = [
|
||||
name = "rustc_symbol_mangling"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"punycode",
|
||||
"rustc-demangle",
|
||||
"rustc_data_structures",
|
||||
@ -4538,7 +4540,7 @@ dependencies = [
|
||||
name = "rustc_target"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"object",
|
||||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
@ -4562,6 +4564,8 @@ checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f"
|
||||
name = "rustc_trait_selection"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"itertools",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
"rustc_data_structures",
|
||||
@ -4636,12 +4640,13 @@ dependencies = [
|
||||
name = "rustc_type_ir"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"derivative",
|
||||
"rustc_data_structures",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
"rustc_span",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
@ -4734,7 +4739,7 @@ dependencies = [
|
||||
name = "rustfmt-nightly"
|
||||
version = "1.7.0"
|
||||
dependencies = [
|
||||
"annotate-snippets",
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
"bytecount",
|
||||
"cargo_metadata 0.15.4",
|
||||
@ -4766,7 +4771,7 @@ version = "0.38.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
@ -4781,12 +4786,12 @@ checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
|
||||
|
||||
[[package]]
|
||||
name = "ruzstd"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3ffab8f9715a0d455df4bbb9d21e91135aab3cd3ca187af0cd0c3c3f868fdc"
|
||||
checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"thiserror-core",
|
||||
"derive_more",
|
||||
"twox-hash",
|
||||
]
|
||||
|
||||
@ -5204,9 +5209,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.29.2"
|
||||
version = "0.29.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9557d0845b86eea8182f7b10dff120214fb6cd9fd937b6f4917714e546a38695"
|
||||
checksum = "cd727fc423c2060f6c92d9534cef765c65a6ed3f428a03d7def74a8c4348e666"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"core-foundation-sys",
|
||||
@ -5336,9 +5341,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thin-vec"
|
||||
version = "0.2.12"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aac81b6fd6beb5884b0cf3321b8117e6e5d47ecb6fc89f414cfdcca8b2fe2dd8"
|
||||
checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
@ -5349,26 +5354,6 @@ dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-core"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497"
|
||||
dependencies = [
|
||||
"thiserror-core-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-core-impl"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.47"
|
||||
@ -5690,12 +5675,6 @@ dependencies = [
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typed-arena"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.16.0"
|
||||
@ -5724,7 +5703,7 @@ version = "0.21.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aaf4bf7c184b8dfc7a4d3b90df789b1eb992ee42811cd115f32a7a1eb781058d"
|
||||
dependencies = [
|
||||
"annotate-snippets",
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
"bstr",
|
||||
"cargo-platform",
|
||||
@ -5747,9 +5726,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unic-langid"
|
||||
version = "0.9.1"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "398f9ad7239db44fd0f80fe068d12ff22d78354080332a5077dc6f52f14dcf2f"
|
||||
checksum = "238722e6d794ed130f91f4ea33e01fcff4f188d92337a21297892521c72df516"
|
||||
dependencies = [
|
||||
"unic-langid-impl",
|
||||
"unic-langid-macros",
|
||||
@ -5757,18 +5736,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unic-langid-impl"
|
||||
version = "0.9.1"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e35bfd2f2b8796545b55d7d3fd3e89a0613f68a0d1c8bc28cb7ff96b411a35ff"
|
||||
checksum = "4bd55a2063fdea4ef1f8633243a7b0524cbeef1905ae04c31a1c9b9775c55bc6"
|
||||
dependencies = [
|
||||
"tinystr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-langid-macros"
|
||||
version = "0.9.1"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "055e618bf694161ffff0466d95cef3e1a5edc59f6ba1888e97801f2b4ebdc4fe"
|
||||
checksum = "5c854cefb82ff2816410ce606acbad1b3af065140907b29be9229040752b83ec"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"tinystr",
|
||||
@ -5778,13 +5757,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unic-langid-macros-impl"
|
||||
version = "0.9.1"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f5cdec05b907f4e2f6843f4354f4ce6a5bebe1a56df320a49134944477ce4d8"
|
||||
checksum = "fea2a4c80deb4fb3ca51f66b5e2dd91e3642bbce52234bcf22e41668281208e4"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.32",
|
||||
"unic-langid-impl",
|
||||
]
|
||||
|
||||
@ -5855,9 +5834,9 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.10"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-core",
|
||||
@ -6141,6 +6120,15 @@ dependencies = [
|
||||
"windows-targets 0.48.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
@ -6171,6 +6159,21 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.0",
|
||||
"windows_aarch64_msvc 0.52.0",
|
||||
"windows_i686_gnu 0.52.0",
|
||||
"windows_i686_msvc 0.52.0",
|
||||
"windows_x86_64_gnu 0.52.0",
|
||||
"windows_x86_64_gnullvm 0.52.0",
|
||||
"windows_x86_64_msvc 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
@ -6183,6 +6186,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
@ -6195,6 +6204,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
@ -6207,6 +6222,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
@ -6219,6 +6240,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
@ -6231,6 +6258,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
@ -6243,6 +6276,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
@ -6255,6 +6294,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.4.7"
|
||||
|
||||
10
Cargo.toml
10
Cargo.toml
@ -64,7 +64,7 @@ exclude = [
|
||||
]
|
||||
|
||||
[profile.release.package.compiler_builtins]
|
||||
# The compiler-builtins crate cannot reference libcore, and it's own CI will
|
||||
# The compiler-builtins crate cannot reference libcore, and its own CI will
|
||||
# verify that this is the case. This requires, however, that the crate is built
|
||||
# without overflow checks and debug assertions. Forcefully disable debug
|
||||
# assertions and overflow checks here which should ensure that even if these
|
||||
@ -104,6 +104,14 @@ gimli.debug = 0
|
||||
miniz_oxide.debug = 0
|
||||
object.debug = 0
|
||||
|
||||
# These are very thin wrappers around executing lld with the right binary name.
|
||||
# Basically nothing within them can go wrong without having been explicitly logged anyway.
|
||||
# We ship these in every rustc tarball and even after compression they add up
|
||||
# to around 0.6MB of data every user needs to download (and 15MB on disk).
|
||||
[profile.release.package.lld-wrapper]
|
||||
debug = 0
|
||||
strip = true
|
||||
|
||||
[patch.crates-io]
|
||||
# See comments in `library/rustc-std-workspace-core/README.md` for what's going on
|
||||
# here
|
||||
|
||||
251
README.md
251
README.md
@ -16,8 +16,6 @@ If you wish to _contribute_ to the compiler, you should read
|
||||
|
||||
- [Quick Start](#quick-start)
|
||||
- [Installing from Source](#installing-from-source)
|
||||
- [Building Documentation](#building-documentation)
|
||||
- [Notes](#notes)
|
||||
- [Getting Help](#getting-help)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
@ -34,253 +32,8 @@ Read ["Installation"] from [The Book].
|
||||
|
||||
## Installing from Source
|
||||
|
||||
The Rust build system uses a Python script called `x.py` to build the compiler,
|
||||
which manages the bootstrapping process. It lives at the root of the project.
|
||||
It also uses a file named `config.toml` to determine various configuration
|
||||
settings for the build. You can see a full list of options in
|
||||
`config.example.toml`.
|
||||
|
||||
The `x.py` command can be run directly on most Unix systems in the following
|
||||
format:
|
||||
|
||||
```sh
|
||||
./x.py <subcommand> [flags]
|
||||
```
|
||||
|
||||
This is how the documentation and examples assume you are running `x.py`.
|
||||
See the [rustc dev guide][rustcguidebuild] if this does not work on your
|
||||
platform.
|
||||
|
||||
More information about `x.py` can be found by running it with the `--help` flag
|
||||
or reading the [rustc dev guide][rustcguidebuild].
|
||||
|
||||
[gettingstarted]: https://rustc-dev-guide.rust-lang.org/getting-started.html
|
||||
[rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#what-is-xpy
|
||||
|
||||
### Dependencies
|
||||
|
||||
Make sure you have installed the dependencies:
|
||||
|
||||
* `python` 3 or 2.7
|
||||
* `git`
|
||||
* A C compiler (when building for the host, `cc` is enough; cross-compiling may
|
||||
need additional compilers)
|
||||
* `curl` (not needed on Windows)
|
||||
* `pkg-config` if you are compiling on Linux and targeting Linux
|
||||
* `libiconv` (already included with glibc on Debian-based distros)
|
||||
|
||||
To build Cargo, you'll also need OpenSSL (`libssl-dev` or `openssl-devel` on
|
||||
most Unix distros).
|
||||
|
||||
If building LLVM from source, you'll need additional tools:
|
||||
|
||||
* `g++`, `clang++`, or MSVC with versions listed on
|
||||
[LLVM's documentation](https://llvm.org/docs/GettingStarted.html#host-c-toolchain-both-compiler-and-standard-library)
|
||||
* `ninja`, or GNU `make` 3.81 or later (Ninja is recommended, especially on
|
||||
Windows)
|
||||
* `cmake` 3.13.4 or later
|
||||
* `libstdc++-static` may be required on some Linux distributions such as Fedora
|
||||
and Ubuntu
|
||||
|
||||
On tier 1 or tier 2 with host tools platforms, you can also choose to download
|
||||
LLVM by setting `llvm.download-ci-llvm = true`.
|
||||
Otherwise, you'll need LLVM installed and `llvm-config` in your path.
|
||||
See [the rustc-dev-guide for more info][sysllvm].
|
||||
|
||||
[sysllvm]: https://rustc-dev-guide.rust-lang.org/building/new-target.html#using-pre-built-llvm
|
||||
|
||||
|
||||
### Building on a Unix-like system
|
||||
|
||||
#### Build steps
|
||||
|
||||
1. Clone the [source] with `git`:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rust-lang/rust.git
|
||||
cd rust
|
||||
```
|
||||
|
||||
[source]: https://github.com/rust-lang/rust
|
||||
|
||||
2. Configure the build settings:
|
||||
|
||||
```sh
|
||||
./configure
|
||||
```
|
||||
|
||||
If you plan to use `x.py install` to create an installation, it is
|
||||
recommended that you set the `prefix` value in the `[install]` section to a
|
||||
directory: `./configure --set install.prefix=<path>`
|
||||
|
||||
3. Build and install:
|
||||
|
||||
```sh
|
||||
./x.py build && ./x.py install
|
||||
```
|
||||
|
||||
When complete, `./x.py install` will place several programs into
|
||||
`$PREFIX/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
|
||||
API-documentation tool. By default, it will also include [Cargo], Rust's
|
||||
package manager. You can disable this behavior by passing
|
||||
`--set build.extended=false` to `./configure`.
|
||||
|
||||
[Cargo]: https://github.com/rust-lang/cargo
|
||||
|
||||
#### Configure and Make
|
||||
|
||||
This project provides a configure script and makefile (the latter of which just
|
||||
invokes `x.py`). `./configure` is the recommended way to programmatically
|
||||
generate a `config.toml`. `make` is not recommended (we suggest using `x.py`
|
||||
directly), but it is supported and we try not to break it unnecessarily.
|
||||
|
||||
```sh
|
||||
./configure
|
||||
make && sudo make install
|
||||
```
|
||||
|
||||
`configure` generates a `config.toml` which can also be used with normal `x.py`
|
||||
invocations.
|
||||
|
||||
### Building on Windows
|
||||
|
||||
On Windows, we suggest using [winget] to install dependencies by running the
|
||||
following in a terminal:
|
||||
|
||||
```powershell
|
||||
winget install -e Python.Python.3
|
||||
winget install -e Kitware.CMake
|
||||
winget install -e Git.Git
|
||||
```
|
||||
|
||||
Then edit your system's `PATH` variable and add: `C:\Program Files\CMake\bin`.
|
||||
See
|
||||
[this guide on editing the system `PATH`](https://www.java.com/en/download/help/path.html)
|
||||
from the Java documentation.
|
||||
|
||||
[winget]: https://github.com/microsoft/winget-cli
|
||||
|
||||
There are two prominent ABIs in use on Windows: the native (MSVC) ABI used by
|
||||
Visual Studio and the GNU ABI used by the GCC toolchain. Which version of Rust
|
||||
you need depends largely on what C/C++ libraries you want to interoperate with.
|
||||
Use the MSVC build of Rust to interop with software produced by Visual Studio
|
||||
and the GNU build to interop with GNU software built using the MinGW/MSYS2
|
||||
toolchain.
|
||||
|
||||
#### MinGW
|
||||
|
||||
[MSYS2][msys2] can be used to easily build Rust on Windows:
|
||||
|
||||
[msys2]: https://www.msys2.org/
|
||||
|
||||
1. Download the latest [MSYS2 installer][msys2] and go through the installer.
|
||||
|
||||
2. Run `mingw32_shell.bat` or `mingw64_shell.bat` from the MSYS2 installation
|
||||
directory (e.g. `C:\msys64`), depending on whether you want 32-bit or 64-bit
|
||||
Rust. (As of the latest version of MSYS2 you have to run `msys2_shell.cmd
|
||||
-mingw32` or `msys2_shell.cmd -mingw64` from the command line instead.)
|
||||
|
||||
3. From this terminal, install the required tools:
|
||||
|
||||
```sh
|
||||
# Update package mirrors (may be needed if you have a fresh install of MSYS2)
|
||||
pacman -Sy pacman-mirrors
|
||||
|
||||
# Install build tools needed for Rust. If you're building a 32-bit compiler,
|
||||
# then replace "x86_64" below with "i686". If you've already got Git, Python,
|
||||
# or CMake installed and in PATH you can remove them from this list.
|
||||
# Note that it is important that you do **not** use the 'python2', 'cmake',
|
||||
# and 'ninja' packages from the 'msys2' subsystem.
|
||||
# The build has historically been known to fail with these packages.
|
||||
pacman -S git \
|
||||
make \
|
||||
diffutils \
|
||||
tar \
|
||||
mingw-w64-x86_64-python \
|
||||
mingw-w64-x86_64-cmake \
|
||||
mingw-w64-x86_64-gcc \
|
||||
mingw-w64-x86_64-ninja
|
||||
```
|
||||
|
||||
4. Navigate to Rust's source code (or clone it), then build it:
|
||||
|
||||
```sh
|
||||
python x.py setup user && python x.py build && python x.py install
|
||||
```
|
||||
|
||||
#### MSVC
|
||||
|
||||
MSVC builds of Rust additionally require an installation of Visual Studio 2017
|
||||
(or later) so `rustc` can use its linker. The simplest way is to get
|
||||
[Visual Studio], check the "C++ build tools" and "Windows 10 SDK" workload.
|
||||
|
||||
[Visual Studio]: https://visualstudio.microsoft.com/downloads/
|
||||
|
||||
(If you're installing CMake yourself, be careful that "C++ CMake tools for
|
||||
Windows" doesn't get included under "Individual components".)
|
||||
|
||||
With these dependencies installed, you can build the compiler in a `cmd.exe`
|
||||
shell with:
|
||||
|
||||
```sh
|
||||
python x.py setup user
|
||||
python x.py build
|
||||
```
|
||||
|
||||
Right now, building Rust only works with some known versions of Visual Studio.
|
||||
If you have a more recent version installed and the build system doesn't
|
||||
understand, you may need to force rustbuild to use an older version.
|
||||
This can be done by manually calling the appropriate vcvars file before running
|
||||
the bootstrap.
|
||||
|
||||
```batch
|
||||
CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||
python x.py build
|
||||
```
|
||||
|
||||
#### Specifying an ABI
|
||||
|
||||
Each specific ABI can also be used from either environment (for example, using
|
||||
the GNU ABI in PowerShell) by using an explicit build triple. The available
|
||||
Windows build triples are:
|
||||
- GNU ABI (using GCC)
|
||||
- `i686-pc-windows-gnu`
|
||||
- `x86_64-pc-windows-gnu`
|
||||
- The MSVC ABI
|
||||
- `i686-pc-windows-msvc`
|
||||
- `x86_64-pc-windows-msvc`
|
||||
|
||||
The build triple can be specified by either specifying `--build=<triple>` when
|
||||
invoking `x.py` commands, or by creating a `config.toml` file (as described in
|
||||
[Building on a Unix-like system](#building-on-a-unix-like-system)), and passing
|
||||
`--set build.build=<triple>` to `./configure`.
|
||||
|
||||
## Building Documentation
|
||||
|
||||
If you'd like to build the documentation, it's almost the same:
|
||||
|
||||
```sh
|
||||
./x.py doc
|
||||
```
|
||||
|
||||
The generated documentation will appear under `doc` in the `build` directory for
|
||||
the ABI used. That is, if the ABI was `x86_64-pc-windows-msvc`, the directory
|
||||
will be `build\x86_64-pc-windows-msvc\doc`.
|
||||
|
||||
## Notes
|
||||
|
||||
Since the Rust compiler is written in Rust, it must be built by a precompiled
|
||||
"snapshot" version of itself (made in an earlier stage of development).
|
||||
As such, source builds require an Internet connection to fetch snapshots, and an
|
||||
OS that can execute the available snapshot binaries.
|
||||
|
||||
See https://doc.rust-lang.org/nightly/rustc/platform-support.html for a list of
|
||||
supported platforms.
|
||||
Only "host tools" platforms have a pre-compiled snapshot binary available; to
|
||||
compile for a platform without host tools you must cross-compile.
|
||||
|
||||
You may find that other platforms work, but these are our officially supported
|
||||
build environments that are most likely to work.
|
||||
If you really want to install from source (though this is not recommended), see
|
||||
[INSTALL.md](INSTALL.md).
|
||||
|
||||
## Getting Help
|
||||
|
||||
|
||||
136
RELEASES.md
136
RELEASES.md
@ -1,3 +1,137 @@
|
||||
Version 1.77.2 (2024-04-09)
|
||||
===========================
|
||||
|
||||
<a id="1.77.2"></a>
|
||||
|
||||
- [CVE-2024-24576: fix escaping of Windows batch file arguments in `std::process::Command`](https://blog.rust-lang.org/2024/04/09/cve-2024-24576.html)
|
||||
|
||||
Version 1.77.1 (2024-03-28)
|
||||
===========================
|
||||
|
||||
<a id="1.77.1"></a>
|
||||
|
||||
- [Revert stripping debuginfo by default for Windows](https://github.com/rust-lang/cargo/pull/13654)
|
||||
This fixes a regression in 1.77 by reverting to the previous default.
|
||||
Platforms other than Windows are not affected.
|
||||
- Internal: [Fix heading anchor rendering in doc pages](https://github.com/rust-lang/rust/pull/122693)
|
||||
|
||||
Version 1.77.0 (2024-03-21)
|
||||
==========================
|
||||
|
||||
<a id="1.77.0-Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
|
||||
- [Reveal opaque types within the defining body for exhaustiveness checking.](https://github.com/rust-lang/rust/pull/116821/)
|
||||
- [Stabilize C-string literals.](https://github.com/rust-lang/rust/pull/117472/)
|
||||
- [Stabilize THIR unsafeck.](https://github.com/rust-lang/rust/pull/117673/)
|
||||
- [Add lint `static_mut_refs` to warn on references to mutable statics.](https://github.com/rust-lang/rust/pull/117556/)
|
||||
- [Support async recursive calls (as long as they have indirection).](https://github.com/rust-lang/rust/pull/117703/)
|
||||
- [Undeprecate lint `unstable_features` and make use of it in the compiler.](https://github.com/rust-lang/rust/pull/118639/)
|
||||
- [Make inductive cycles in coherence ambiguous always.](https://github.com/rust-lang/rust/pull/118649/)
|
||||
- [Get rid of type-driven traversal in const-eval interning](https://github.com/rust-lang/rust/pull/119044/),
|
||||
only as a [future compatiblity lint](https://github.com/rust-lang/rust/pull/122204) for now.
|
||||
- [Deny braced macro invocations in let-else.](https://github.com/rust-lang/rust/pull/119062/)
|
||||
|
||||
<a id="1.77.0-Compiler"></a>
|
||||
|
||||
Compiler
|
||||
--------
|
||||
|
||||
- [Include lint `soft_unstable` in future breakage reports.](https://github.com/rust-lang/rust/pull/116274/)
|
||||
- [Make `i128` and `u128` 16-byte aligned on x86-based targets.](https://github.com/rust-lang/rust/pull/116672/)
|
||||
- [Use `--verbose` in diagnostic output.](https://github.com/rust-lang/rust/pull/119129/)
|
||||
- [Improve spacing between printed tokens.](https://github.com/rust-lang/rust/pull/120227/)
|
||||
- [Merge the `unused_tuple_struct_fields` lint into `dead_code`.](https://github.com/rust-lang/rust/pull/118297/)
|
||||
- [Error on incorrect implied bounds in well-formedness check](https://github.com/rust-lang/rust/pull/118553/),
|
||||
with a temporary exception for Bevy.
|
||||
- [Fix coverage instrumentation/reports for non-ASCII source code.](https://github.com/rust-lang/rust/pull/119033/)
|
||||
- [Fix `fn`/`const` items implied bounds and well-formedness check.](https://github.com/rust-lang/rust/pull/120019/)
|
||||
- [Promote `riscv32{im|imafc}-unknown-none-elf` targets to tier 2.](https://github.com/rust-lang/rust/pull/118704/)
|
||||
- Add several new tier 3 targets:
|
||||
- [`aarch64-unknown-illumos`](https://github.com/rust-lang/rust/pull/112936/)
|
||||
- [`hexagon-unknown-none-elf`](https://github.com/rust-lang/rust/pull/117601/)
|
||||
- [`riscv32imafc-esp-espidf`](https://github.com/rust-lang/rust/pull/119738/)
|
||||
- [`riscv32im-risc0-zkvm-elf`](https://github.com/rust-lang/rust/pull/117958/)
|
||||
|
||||
Refer to Rust's [platform support page][platform-support-doc]
|
||||
for more information on Rust's tiered platform support.
|
||||
|
||||
<a id="1.77.0-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
|
||||
- [Implement `From<&[T; N]>` for `Cow<[T]>`.](https://github.com/rust-lang/rust/pull/113489/)
|
||||
- [Remove special-case handling of `vec.split_off(0)`.](https://github.com/rust-lang/rust/pull/119917/)
|
||||
|
||||
<a id="1.77.0-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`array::each_ref`](https://doc.rust-lang.org/stable/std/primitive.array.html#method.each_ref)
|
||||
- [`array::each_mut`](https://doc.rust-lang.org/stable/std/primitive.array.html#method.each_mut)
|
||||
- [`core::net`](https://doc.rust-lang.org/stable/core/net/index.html)
|
||||
- [`f32::round_ties_even`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.round_ties_even)
|
||||
- [`f64::round_ties_even`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.round_ties_even)
|
||||
- [`mem::offset_of!`](https://doc.rust-lang.org/stable/std/mem/macro.offset_of.html)
|
||||
- [`slice::first_chunk`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.first_chunk)
|
||||
- [`slice::first_chunk_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.first_chunk_mut)
|
||||
- [`slice::split_first_chunk`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_first_chunk)
|
||||
- [`slice::split_first_chunk_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_first_chunk_mut)
|
||||
- [`slice::last_chunk`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.last_chunk)
|
||||
- [`slice::last_chunk_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.last_chunk_mut)
|
||||
- [`slice::split_last_chunk`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_last_chunk)
|
||||
- [`slice::split_last_chunk_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_last_chunk_mut)
|
||||
- [`slice::chunk_by`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.chunk_by)
|
||||
- [`slice::chunk_by_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.chunk_by_mut)
|
||||
- [`Bound::map`](https://doc.rust-lang.org/stable/std/ops/enum.Bound.html#method.map)
|
||||
- [`File::create_new`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.create_new)
|
||||
- [`Mutex::clear_poison`](https://doc.rust-lang.org/stable/std/sync/struct.Mutex.html#method.clear_poison)
|
||||
- [`RwLock::clear_poison`](https://doc.rust-lang.org/stable/std/sync/struct.RwLock.html#method.clear_poison)
|
||||
|
||||
<a id="1.77.0-Cargo"></a>
|
||||
|
||||
Cargo
|
||||
-----
|
||||
|
||||
- [Extend the build directive syntax with `cargo::`.](https://github.com/rust-lang/cargo/pull/12201/)
|
||||
- [Stabilize metadata `id` format as `PackageIDSpec`.](https://github.com/rust-lang/cargo/pull/12914/)
|
||||
- [Pull out as `cargo-util-schemas` as a crate.](https://github.com/rust-lang/cargo/pull/13178/)
|
||||
- [Strip all debuginfo when debuginfo is not requested.](https://github.com/rust-lang/cargo/pull/13257/)
|
||||
- [Inherit jobserver from env for all kinds of runners.](https://github.com/rust-lang/cargo/pull/12776/)
|
||||
- [Deprecate rustc plugin support in cargo.](https://github.com/rust-lang/cargo/pull/13248/)
|
||||
|
||||
<a id="1.77.0-Rustdoc"></a>
|
||||
|
||||
Rustdoc
|
||||
-----
|
||||
|
||||
- [Allows links in markdown headings.](https://github.com/rust-lang/rust/pull/117662/)
|
||||
- [Search for tuples and unit by type with `()`.](https://github.com/rust-lang/rust/pull/118194/)
|
||||
- [Clean up the source sidebar's hide button.](https://github.com/rust-lang/rust/pull/119066/)
|
||||
- [Prevent JS injection from `localStorage`.](https://github.com/rust-lang/rust/pull/120250/)
|
||||
|
||||
<a id="1.77.0-Misc"></a>
|
||||
|
||||
Misc
|
||||
----
|
||||
|
||||
- [Recommend version-sorting for all sorting in style guide.](https://github.com/rust-lang/rust/pull/115046/)
|
||||
|
||||
<a id="1.77.0-Internal-Changes"></a>
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
These changes do not affect any public interfaces of Rust, but they represent
|
||||
significant improvements to the performance or internals of rustc and related
|
||||
tools.
|
||||
|
||||
- [Add more weirdness to `weird-exprs.rs`.](https://github.com/rust-lang/rust/pull/119028/)
|
||||
|
||||
Version 1.76.0 (2024-02-08)
|
||||
==========================
|
||||
|
||||
@ -7,7 +141,7 @@ Language
|
||||
--------
|
||||
- [Document Rust ABI compatibility between various types](https://github.com/rust-lang/rust/pull/115476/)
|
||||
- [Also: guarantee that char and u32 are ABI-compatible](https://github.com/rust-lang/rust/pull/118032/)
|
||||
- [Warn against ambiguous wide pointer comparisons](https://github.com/rust-lang/rust/pull/117758/)
|
||||
- [Add lint `ambiguous_wide_pointer_comparisons` that supersedes `clippy::vtable_address_comparisons`](https://github.com/rust-lang/rust/pull/117758)
|
||||
|
||||
<a id="1.76.0-Compiler"></a>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
bitflags = "1.2.1"
|
||||
bitflags = "2.4.1"
|
||||
rand = { version = "0.8.4", default-features = false, optional = true }
|
||||
rand_xoshiro = { version = "0.6.0", optional = true }
|
||||
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
|
||||
|
||||
@ -11,6 +11,24 @@ use crate::{
|
||||
Variants, WrappingRange,
|
||||
};
|
||||
|
||||
// A variant is absent if it's uninhabited and only has ZST fields.
|
||||
// Present uninhabited variants only require space for their fields,
|
||||
// but *not* an encoding of the discriminant (e.g., a tag value).
|
||||
// See issue #49298 for more details on the need to leave space
|
||||
// for non-ZST uninhabited data (mostly partial initialization).
|
||||
fn absent<'a, FieldIdx, VariantIdx, F>(fields: &IndexSlice<FieldIdx, F>) -> bool
|
||||
where
|
||||
FieldIdx: Idx,
|
||||
VariantIdx: Idx,
|
||||
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
|
||||
{
|
||||
let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited());
|
||||
// We cannot ignore alignment; that might lead us to entirely discard a variant and
|
||||
// produce an enum that is less aligned than it should be!
|
||||
let is_1zst = fields.iter().all(|f| f.is_1zst());
|
||||
uninhabited && is_1zst
|
||||
}
|
||||
|
||||
pub trait LayoutCalculator {
|
||||
type TargetDataLayoutRef: Borrow<TargetDataLayout>;
|
||||
|
||||
@ -162,24 +180,6 @@ pub trait LayoutCalculator {
|
||||
let dl = self.current_data_layout();
|
||||
let dl = dl.borrow();
|
||||
|
||||
let scalar_unit = |value: Primitive| {
|
||||
let size = value.size(dl);
|
||||
assert!(size.bits() <= 128);
|
||||
Scalar::Initialized { value, valid_range: WrappingRange::full(size) }
|
||||
};
|
||||
|
||||
// A variant is absent if it's uninhabited and only has ZST fields.
|
||||
// Present uninhabited variants only require space for their fields,
|
||||
// but *not* an encoding of the discriminant (e.g., a tag value).
|
||||
// See issue #49298 for more details on the need to leave space
|
||||
// for non-ZST uninhabited data (mostly partial initialization).
|
||||
let absent = |fields: &IndexSlice<FieldIdx, F>| {
|
||||
let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited());
|
||||
// We cannot ignore alignment; that might lead us to entirely discard a variant and
|
||||
// produce an enum that is less aligned than it should be!
|
||||
let is_1zst = fields.iter().all(|f| f.is_1zst());
|
||||
uninhabited && is_1zst
|
||||
};
|
||||
let (present_first, present_second) = {
|
||||
let mut present_variants = variants
|
||||
.iter_enumerated()
|
||||
@ -197,12 +197,160 @@ pub trait LayoutCalculator {
|
||||
None => VariantIdx::new(0),
|
||||
};
|
||||
|
||||
let is_struct = !is_enum ||
|
||||
// Only one variant is present.
|
||||
(present_second.is_none() &&
|
||||
// Representation optimizations are allowed.
|
||||
!repr.inhibit_enum_layout_opt());
|
||||
if is_struct {
|
||||
// take the struct path if it is an actual struct
|
||||
if !is_enum ||
|
||||
// or for optimizing univariant enums
|
||||
(present_second.is_none() && !repr.inhibit_enum_layout_opt())
|
||||
{
|
||||
layout_of_struct(
|
||||
self,
|
||||
repr,
|
||||
variants,
|
||||
is_enum,
|
||||
is_unsafe_cell,
|
||||
scalar_valid_range,
|
||||
always_sized,
|
||||
dl,
|
||||
present_first,
|
||||
)
|
||||
} else {
|
||||
// At this point, we have handled all unions and
|
||||
// structs. (We have also handled univariant enums
|
||||
// that allow representation optimization.)
|
||||
assert!(is_enum);
|
||||
layout_of_enum(
|
||||
self,
|
||||
repr,
|
||||
variants,
|
||||
discr_range_of_repr,
|
||||
discriminants,
|
||||
dont_niche_optimize_enum,
|
||||
dl,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_of_union<
|
||||
'a,
|
||||
FieldIdx: Idx,
|
||||
VariantIdx: Idx,
|
||||
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
|
||||
>(
|
||||
&self,
|
||||
repr: &ReprOptions,
|
||||
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
||||
) -> Option<LayoutS<FieldIdx, VariantIdx>> {
|
||||
let dl = self.current_data_layout();
|
||||
let dl = dl.borrow();
|
||||
let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align };
|
||||
let mut max_repr_align = repr.align;
|
||||
|
||||
// If all the non-ZST fields have the same ABI and union ABI optimizations aren't
|
||||
// disabled, we can use that common ABI for the union as a whole.
|
||||
struct AbiMismatch;
|
||||
let mut common_non_zst_abi_and_align = if repr.inhibit_union_abi_opt() {
|
||||
// Can't optimize
|
||||
Err(AbiMismatch)
|
||||
} else {
|
||||
Ok(None)
|
||||
};
|
||||
|
||||
let mut size = Size::ZERO;
|
||||
let only_variant = &variants[VariantIdx::new(0)];
|
||||
for field in only_variant {
|
||||
if field.is_unsized() {
|
||||
self.delayed_bug("unsized field in union".to_string());
|
||||
}
|
||||
|
||||
align = align.max(field.align);
|
||||
max_repr_align = max_repr_align.max(field.max_repr_align);
|
||||
size = cmp::max(size, field.size);
|
||||
|
||||
if field.is_zst() {
|
||||
// Nothing more to do for ZST fields
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Ok(common) = common_non_zst_abi_and_align {
|
||||
// Discard valid range information and allow undef
|
||||
let field_abi = field.abi.to_union();
|
||||
|
||||
if let Some((common_abi, common_align)) = common {
|
||||
if common_abi != field_abi {
|
||||
// Different fields have different ABI: disable opt
|
||||
common_non_zst_abi_and_align = Err(AbiMismatch);
|
||||
} else {
|
||||
// Fields with the same non-Aggregate ABI should also
|
||||
// have the same alignment
|
||||
if !matches!(common_abi, Abi::Aggregate { .. }) {
|
||||
assert_eq!(
|
||||
common_align, field.align.abi,
|
||||
"non-Aggregate field with matching ABI but differing alignment"
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// First non-ZST field: record its ABI and alignment
|
||||
common_non_zst_abi_and_align = Ok(Some((field_abi, field.align.abi)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(pack) = repr.pack {
|
||||
align = align.min(AbiAndPrefAlign::new(pack));
|
||||
}
|
||||
// The unadjusted ABI alignment does not include repr(align), but does include repr(pack).
|
||||
// See documentation on `LayoutS::unadjusted_abi_align`.
|
||||
let unadjusted_abi_align = align.abi;
|
||||
if let Some(repr_align) = repr.align {
|
||||
align = align.max(AbiAndPrefAlign::new(repr_align));
|
||||
}
|
||||
// `align` must not be modified after this, or `unadjusted_abi_align` could be inaccurate.
|
||||
let align = align;
|
||||
|
||||
// If all non-ZST fields have the same ABI, we may forward that ABI
|
||||
// for the union as a whole, unless otherwise inhibited.
|
||||
let abi = match common_non_zst_abi_and_align {
|
||||
Err(AbiMismatch) | Ok(None) => Abi::Aggregate { sized: true },
|
||||
Ok(Some((abi, _))) => {
|
||||
if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) {
|
||||
// Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
|
||||
Abi::Aggregate { sized: true }
|
||||
} else {
|
||||
abi
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Some(LayoutS {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Union(NonZeroUsize::new(only_variant.len())?),
|
||||
abi,
|
||||
largest_niche: None,
|
||||
align,
|
||||
size: size.align_to(align.abi),
|
||||
max_repr_align,
|
||||
unadjusted_abi_align,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// single-variant enums are just structs, if you think about it
|
||||
fn layout_of_struct<'a, LC, FieldIdx: Idx, VariantIdx: Idx, F>(
|
||||
layout_calc: &LC,
|
||||
repr: &ReprOptions,
|
||||
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
||||
is_enum: bool,
|
||||
is_unsafe_cell: bool,
|
||||
scalar_valid_range: (Bound<u128>, Bound<u128>),
|
||||
always_sized: bool,
|
||||
dl: &TargetDataLayout,
|
||||
present_first: VariantIdx,
|
||||
) -> Option<LayoutS<FieldIdx, VariantIdx>>
|
||||
where
|
||||
LC: LayoutCalculator + ?Sized,
|
||||
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
|
||||
{
|
||||
// Struct, or univariant enum equivalent to a struct.
|
||||
// (Typechecking will reject discriminant-sizing attrs.)
|
||||
|
||||
@ -213,7 +361,7 @@ pub trait LayoutCalculator {
|
||||
StructKind::MaybeUnsized
|
||||
};
|
||||
|
||||
let mut st = self.univariant(dl, &variants[v], repr, kind)?;
|
||||
let mut st = layout_calc.univariant(dl, &variants[v], repr, kind)?;
|
||||
st.variants = Variants::Single { index: v };
|
||||
|
||||
if is_unsafe_cell {
|
||||
@ -284,14 +432,22 @@ pub trait LayoutCalculator {
|
||||
),
|
||||
}
|
||||
|
||||
return Some(st);
|
||||
}
|
||||
|
||||
// At this point, we have handled all unions and
|
||||
// structs. (We have also handled univariant enums
|
||||
// that allow representation optimization.)
|
||||
assert!(is_enum);
|
||||
Some(st)
|
||||
}
|
||||
|
||||
fn layout_of_enum<'a, LC, FieldIdx: Idx, VariantIdx: Idx, F>(
|
||||
layout_calc: &LC,
|
||||
repr: &ReprOptions,
|
||||
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
||||
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
|
||||
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
|
||||
dont_niche_optimize_enum: bool,
|
||||
dl: &TargetDataLayout,
|
||||
) -> Option<LayoutS<FieldIdx, VariantIdx>>
|
||||
where
|
||||
LC: LayoutCalculator + ?Sized,
|
||||
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
|
||||
{
|
||||
// Until we've decided whether to use the tagged or
|
||||
// niche filling LayoutS, we don't want to intern the
|
||||
// variant layouts, so we can't store them in the
|
||||
@ -318,7 +474,7 @@ pub trait LayoutCalculator {
|
||||
let mut variant_layouts = variants
|
||||
.iter_enumerated()
|
||||
.map(|(j, v)| {
|
||||
let mut st = self.univariant(dl, v, repr, StructKind::AlwaysSized)?;
|
||||
let mut st = layout_calc.univariant(dl, v, repr, StructKind::AlwaysSized)?;
|
||||
st.variants = Variants::Single { index: j };
|
||||
|
||||
align = align.max(st.align);
|
||||
@ -512,7 +668,7 @@ pub trait LayoutCalculator {
|
||||
let mut layout_variants = variants
|
||||
.iter_enumerated()
|
||||
.map(|(i, field_layouts)| {
|
||||
let mut st = self.univariant(
|
||||
let mut st = layout_calc.univariant(
|
||||
dl,
|
||||
field_layouts,
|
||||
repr,
|
||||
@ -672,12 +828,14 @@ pub trait LayoutCalculator {
|
||||
}
|
||||
if let Some((prim, offset)) = common_prim {
|
||||
let prim_scalar = if common_prim_initialized_in_all_variants {
|
||||
scalar_unit(prim)
|
||||
let size = prim.size(dl);
|
||||
assert!(size.bits() <= 128);
|
||||
Scalar::Initialized { value: prim, valid_range: WrappingRange::full(size) }
|
||||
} else {
|
||||
// Common prim might be uninit.
|
||||
Scalar::Union { value: prim }
|
||||
};
|
||||
let pair = self.scalar_pair::<FieldIdx, VariantIdx>(tag, prim_scalar);
|
||||
let pair = layout_calc.scalar_pair::<FieldIdx, VariantIdx>(tag, prim_scalar);
|
||||
let pair_offsets = match pair.fields {
|
||||
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
|
||||
assert_eq!(memory_index.raw, [0, 1]);
|
||||
@ -723,10 +881,7 @@ pub trait LayoutCalculator {
|
||||
tag_field: 0,
|
||||
variants: IndexVec::new(),
|
||||
},
|
||||
fields: FieldsShape::Arbitrary {
|
||||
offsets: [Size::ZERO].into(),
|
||||
memory_index: [0].into(),
|
||||
},
|
||||
fields: FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() },
|
||||
largest_niche,
|
||||
abi,
|
||||
align,
|
||||
@ -765,111 +920,6 @@ pub trait LayoutCalculator {
|
||||
}
|
||||
};
|
||||
Some(best_layout.layout)
|
||||
}
|
||||
|
||||
fn layout_of_union<
|
||||
'a,
|
||||
FieldIdx: Idx,
|
||||
VariantIdx: Idx,
|
||||
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
|
||||
>(
|
||||
&self,
|
||||
repr: &ReprOptions,
|
||||
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
||||
) -> Option<LayoutS<FieldIdx, VariantIdx>> {
|
||||
let dl = self.current_data_layout();
|
||||
let dl = dl.borrow();
|
||||
let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align };
|
||||
let mut max_repr_align = repr.align;
|
||||
|
||||
// If all the non-ZST fields have the same ABI and union ABI optimizations aren't
|
||||
// disabled, we can use that common ABI for the union as a whole.
|
||||
struct AbiMismatch;
|
||||
let mut common_non_zst_abi_and_align = if repr.inhibit_union_abi_opt() {
|
||||
// Can't optimize
|
||||
Err(AbiMismatch)
|
||||
} else {
|
||||
Ok(None)
|
||||
};
|
||||
|
||||
let mut size = Size::ZERO;
|
||||
let only_variant = &variants[VariantIdx::new(0)];
|
||||
for field in only_variant {
|
||||
if field.is_unsized() {
|
||||
self.delayed_bug("unsized field in union".to_string());
|
||||
}
|
||||
|
||||
align = align.max(field.align);
|
||||
max_repr_align = max_repr_align.max(field.max_repr_align);
|
||||
size = cmp::max(size, field.size);
|
||||
|
||||
if field.is_zst() {
|
||||
// Nothing more to do for ZST fields
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Ok(common) = common_non_zst_abi_and_align {
|
||||
// Discard valid range information and allow undef
|
||||
let field_abi = field.abi.to_union();
|
||||
|
||||
if let Some((common_abi, common_align)) = common {
|
||||
if common_abi != field_abi {
|
||||
// Different fields have different ABI: disable opt
|
||||
common_non_zst_abi_and_align = Err(AbiMismatch);
|
||||
} else {
|
||||
// Fields with the same non-Aggregate ABI should also
|
||||
// have the same alignment
|
||||
if !matches!(common_abi, Abi::Aggregate { .. }) {
|
||||
assert_eq!(
|
||||
common_align, field.align.abi,
|
||||
"non-Aggregate field with matching ABI but differing alignment"
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// First non-ZST field: record its ABI and alignment
|
||||
common_non_zst_abi_and_align = Ok(Some((field_abi, field.align.abi)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(pack) = repr.pack {
|
||||
align = align.min(AbiAndPrefAlign::new(pack));
|
||||
}
|
||||
// The unadjusted ABI alignment does not include repr(align), but does include repr(pack).
|
||||
// See documentation on `LayoutS::unadjusted_abi_align`.
|
||||
let unadjusted_abi_align = align.abi;
|
||||
if let Some(repr_align) = repr.align {
|
||||
align = align.max(AbiAndPrefAlign::new(repr_align));
|
||||
}
|
||||
// `align` must not be modified after this, or `unadjusted_abi_align` could be inaccurate.
|
||||
let align = align;
|
||||
|
||||
// If all non-ZST fields have the same ABI, we may forward that ABI
|
||||
// for the union as a whole, unless otherwise inhibited.
|
||||
let abi = match common_non_zst_abi_and_align {
|
||||
Err(AbiMismatch) | Ok(None) => Abi::Aggregate { sized: true },
|
||||
Ok(Some((abi, _))) => {
|
||||
if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) {
|
||||
// Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
|
||||
Abi::Aggregate { sized: true }
|
||||
} else {
|
||||
abi
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Some(LayoutS {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Union(NonZeroUsize::new(only_variant.len())?),
|
||||
abi,
|
||||
largest_niche: None,
|
||||
align,
|
||||
size: size.align_to(align.abi),
|
||||
max_repr_align,
|
||||
unadjusted_abi_align,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines towards which end of a struct layout optimizations will try to place the best niches.
|
||||
|
||||
@ -16,7 +16,7 @@ use rustc_data_structures::stable_hasher::StableOrd;
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::HashStable_Generic;
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
use rustc_macros::{Decodable_Generic, Encodable_Generic};
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::iter::Step;
|
||||
|
||||
@ -29,10 +29,12 @@ pub use layout::LayoutCalculator;
|
||||
/// instead of implementing everything in `rustc_middle`.
|
||||
pub trait HashStableContext {}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Default)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
|
||||
pub struct ReprFlags(u8);
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
||||
pub struct ReprFlags: u8 {
|
||||
impl ReprFlags: u8 {
|
||||
const IS_C = 1 << 0;
|
||||
const IS_SIMD = 1 << 1;
|
||||
const IS_TRANSPARENT = 1 << 2;
|
||||
@ -42,14 +44,22 @@ bitflags! {
|
||||
// the seed stored in `ReprOptions.layout_seed`
|
||||
const RANDOMIZE_LAYOUT = 1 << 4;
|
||||
// Any of these flags being set prevent field reordering optimisation.
|
||||
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits
|
||||
| ReprFlags::IS_SIMD.bits
|
||||
| ReprFlags::IS_LINEAR.bits;
|
||||
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits()
|
||||
| ReprFlags::IS_SIMD.bits()
|
||||
| ReprFlags::IS_LINEAR.bits();
|
||||
}
|
||||
}
|
||||
|
||||
// This is the same as `rustc_data_structures::external_bitflags_debug` but without the
|
||||
// `rustc_data_structures` to make it build on stable.
|
||||
impl std::fmt::Debug for ReprFlags {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
bitflags::parser::to_writer(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
|
||||
pub enum IntegerType {
|
||||
/// Pointer-sized integer type, i.e. `isize` and `usize`. The field shows signedness, e.g.
|
||||
/// `Pointer(true)` means `isize`.
|
||||
@ -70,7 +80,7 @@ impl IntegerType {
|
||||
|
||||
/// Represents the repr options provided by the user.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
|
||||
pub struct ReprOptions {
|
||||
pub int: Option<IntegerType>,
|
||||
pub align: Option<Align>,
|
||||
@ -409,7 +419,7 @@ impl FromStr for Endian {
|
||||
|
||||
/// Size of a type in bytes.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
|
||||
pub struct Size {
|
||||
raw: u64,
|
||||
}
|
||||
@ -633,7 +643,7 @@ impl Step for Size {
|
||||
|
||||
/// Alignment of a type in bytes (always a power of two).
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
|
||||
pub struct Align {
|
||||
pow2: u8,
|
||||
}
|
||||
@ -774,7 +784,7 @@ impl AbiAndPrefAlign {
|
||||
|
||||
/// Integers, also used for enum discriminants.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
|
||||
pub enum Integer {
|
||||
I8,
|
||||
I16,
|
||||
|
||||
@ -484,6 +484,19 @@ impl DroplessArena {
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by `Lift` to check whether this slice is allocated
|
||||
/// in this arena.
|
||||
#[inline]
|
||||
pub fn contains_slice<T>(&self, slice: &[T]) -> bool {
|
||||
for chunk in self.chunks.borrow_mut().iter_mut() {
|
||||
let ptr = slice.as_ptr().cast::<u8>().cast_mut();
|
||||
if chunk.start() <= ptr && chunk.end() >= ptr {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Allocates a string slice that is copied into the `DroplessArena`, returning a
|
||||
/// reference to it. Will panic if passed an empty string.
|
||||
///
|
||||
|
||||
@ -5,7 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
bitflags = "1.2.1"
|
||||
bitflags = "2.4.1"
|
||||
memchr = "2.5.0"
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
|
||||
@ -20,17 +20,18 @@
|
||||
|
||||
pub use crate::format::*;
|
||||
pub use crate::util::parser::ExprPrecedence;
|
||||
pub use rustc_span::AttrId;
|
||||
pub use GenericArgs::*;
|
||||
pub use UnsafeSource::*;
|
||||
|
||||
use crate::ptr::P;
|
||||
use crate::token::{self, CommentKind, Delimiter};
|
||||
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
use rustc_span::source_map::{respan, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
||||
@ -286,41 +287,16 @@ impl ParenthesizedArgs {
|
||||
|
||||
pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
|
||||
|
||||
/// A modifier on a bound, e.g., `?Trait` or `~const Trait`.
|
||||
///
|
||||
/// Negative bounds should also be handled here.
|
||||
/// Modifiers on a trait bound like `~const`, `?` and `!`.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
|
||||
pub enum TraitBoundModifier {
|
||||
/// No modifiers
|
||||
None,
|
||||
|
||||
/// `!Trait`
|
||||
Negative,
|
||||
|
||||
/// `?Trait`
|
||||
Maybe,
|
||||
|
||||
/// `~const Trait`
|
||||
MaybeConst(Span),
|
||||
|
||||
/// `~const !Trait`
|
||||
//
|
||||
// This parses but will be rejected during AST validation.
|
||||
MaybeConstNegative,
|
||||
|
||||
/// `~const ?Trait`
|
||||
//
|
||||
// This parses but will be rejected during AST validation.
|
||||
MaybeConstMaybe,
|
||||
pub struct TraitBoundModifiers {
|
||||
pub constness: BoundConstness,
|
||||
pub polarity: BoundPolarity,
|
||||
}
|
||||
|
||||
impl TraitBoundModifier {
|
||||
pub fn to_constness(self) -> Const {
|
||||
match self {
|
||||
Self::MaybeConst(span) => Const::Yes(span),
|
||||
_ => Const::No,
|
||||
}
|
||||
}
|
||||
impl TraitBoundModifiers {
|
||||
pub const NONE: Self =
|
||||
Self { constness: BoundConstness::Never, polarity: BoundPolarity::Positive };
|
||||
}
|
||||
|
||||
/// The AST represents all type param bounds as types.
|
||||
@ -329,7 +305,7 @@ impl TraitBoundModifier {
|
||||
/// detects `Copy`, `Send` and `Sync`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum GenericBound {
|
||||
Trait(PolyTraitRef, TraitBoundModifier),
|
||||
Trait(PolyTraitRef, TraitBoundModifiers),
|
||||
Outlives(Lifetime),
|
||||
}
|
||||
|
||||
@ -650,7 +626,8 @@ impl Pat {
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Ident(..)
|
||||
| PatKind::Path(..)
|
||||
| PatKind::MacCall(_) => {}
|
||||
| PatKind::MacCall(_)
|
||||
| PatKind::Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -779,8 +756,7 @@ pub enum PatKind {
|
||||
Ident(BindingAnnotation, Ident, Option<P<Pat>>),
|
||||
|
||||
/// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`).
|
||||
/// The `bool` is `true` in the presence of a `..`.
|
||||
Struct(Option<P<QSelf>>, Path, ThinVec<PatField>, /* recovered */ bool),
|
||||
Struct(Option<P<QSelf>>, Path, ThinVec<PatField>, PatFieldsRest),
|
||||
|
||||
/// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
|
||||
TupleStruct(Option<P<QSelf>>, Path, ThinVec<P<Pat>>),
|
||||
@ -835,6 +811,18 @@ pub enum PatKind {
|
||||
|
||||
/// A macro pattern; pre-expansion.
|
||||
MacCall(P<MacCall>),
|
||||
|
||||
/// Placeholder for a pattern that wasn't syntactically well formed in some way.
|
||||
Err(ErrorGuaranteed),
|
||||
}
|
||||
|
||||
/// Whether the `..` is present in a struct fields pattern.
|
||||
#[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq)]
|
||||
pub enum PatFieldsRest {
|
||||
/// `module::StructName { field, ..}`
|
||||
Rest,
|
||||
/// `module::StructName { field }`
|
||||
None,
|
||||
}
|
||||
|
||||
/// The kind of borrow in an `AddrOf` expression,
|
||||
@ -1193,7 +1181,7 @@ impl Expr {
|
||||
match &self.kind {
|
||||
ExprKind::Path(None, path) => Some(GenericBound::Trait(
|
||||
PolyTraitRef::new(ThinVec::new(), path.clone(), self.span),
|
||||
TraitBoundModifier::None,
|
||||
TraitBoundModifiers::NONE,
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
@ -1274,7 +1262,7 @@ impl Expr {
|
||||
ExprKind::Let(..) => ExprPrecedence::Let,
|
||||
ExprKind::If(..) => ExprPrecedence::If,
|
||||
ExprKind::While(..) => ExprPrecedence::While,
|
||||
ExprKind::ForLoop(..) => ExprPrecedence::ForLoop,
|
||||
ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop,
|
||||
ExprKind::Loop(..) => ExprPrecedence::Loop,
|
||||
ExprKind::Match(..) => ExprPrecedence::Match,
|
||||
ExprKind::Closure(..) => ExprPrecedence::Closure,
|
||||
@ -1436,10 +1424,10 @@ pub enum ExprKind {
|
||||
While(P<Expr>, P<Block>, Option<Label>),
|
||||
/// A `for` loop, with an optional label.
|
||||
///
|
||||
/// `'label: for pat in expr { block }`
|
||||
/// `'label: for await? pat in iter { block }`
|
||||
///
|
||||
/// This is desugared to a combination of `loop` and `match` expressions.
|
||||
ForLoop(P<Pat>, P<Expr>, P<Block>, Option<Label>),
|
||||
ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind },
|
||||
/// Conditionless loop (can be exited with `break`, `continue`, or `return`).
|
||||
///
|
||||
/// `'label: loop { block }`
|
||||
@ -1542,6 +1530,13 @@ pub enum ExprKind {
|
||||
Err,
|
||||
}
|
||||
|
||||
/// Used to differentiate between `for` loops and `for await` loops.
|
||||
#[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq, Eq)]
|
||||
pub enum ForLoopKind {
|
||||
For,
|
||||
ForAwait,
|
||||
}
|
||||
|
||||
/// Used to differentiate between `async {}` blocks and `gen {}` blocks.
|
||||
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
|
||||
pub enum GenBlockKind {
|
||||
@ -1839,7 +1834,7 @@ pub enum LitKind {
|
||||
/// A character literal (`'a'`).
|
||||
Char(char),
|
||||
/// An integer literal (`1`).
|
||||
Int(u128, LitIntType),
|
||||
Int(Pu128, LitIntType),
|
||||
/// A float literal (`1.0`, `1f64` or `1E10f64`). The pre-suffix part is
|
||||
/// stored as a symbol rather than `f64` so that `LitKind` can impl `Eq`
|
||||
/// and `Hash`.
|
||||
@ -2181,9 +2176,10 @@ pub enum InlineAsmRegOrRegClass {
|
||||
RegClass(Symbol),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
||||
pub struct InlineAsmOptions(u16);
|
||||
bitflags::bitflags! {
|
||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||
pub struct InlineAsmOptions: u16 {
|
||||
impl InlineAsmOptions: u16 {
|
||||
const PURE = 1 << 0;
|
||||
const NOMEM = 1 << 1;
|
||||
const READONLY = 1 << 2;
|
||||
@ -2196,6 +2192,12 @@ bitflags::bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for InlineAsmOptions {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
bitflags::parser::to_writer(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
|
||||
pub enum InlineAsmTemplatePiece {
|
||||
String(String),
|
||||
@ -2516,7 +2518,9 @@ impl fmt::Debug for ImplPolarity {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
/// The polarity of a trait bound.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum BoundPolarity {
|
||||
/// `Type: Trait`
|
||||
Positive,
|
||||
@ -2526,6 +2530,38 @@ pub enum BoundPolarity {
|
||||
Maybe(Span),
|
||||
}
|
||||
|
||||
impl BoundPolarity {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Positive => "",
|
||||
Self::Negative(_) => "!",
|
||||
Self::Maybe(_) => "?",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The constness of a trait bound.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum BoundConstness {
|
||||
/// `Type: Trait`
|
||||
Never,
|
||||
/// `Type: const Trait`
|
||||
Always(Span),
|
||||
/// `Type: ~const Trait`
|
||||
Maybe(Span),
|
||||
}
|
||||
|
||||
impl BoundConstness {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Never => "",
|
||||
Self::Always(_) => "const",
|
||||
Self::Maybe(_) => "~const",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum FnRetTy {
|
||||
/// Returns type is not specified.
|
||||
@ -2651,22 +2687,6 @@ pub enum AttrStyle {
|
||||
Inner,
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
#[orderable]
|
||||
#[debug_format = "AttrId({})"]
|
||||
pub struct AttrId {}
|
||||
}
|
||||
|
||||
impl<S: Encoder> Encodable<S> for AttrId {
|
||||
fn encode(&self, _s: &mut S) {}
|
||||
}
|
||||
|
||||
impl<D: Decoder> Decodable<D> for AttrId {
|
||||
default fn decode(_: &mut D) -> AttrId {
|
||||
panic!("cannot decode `AttrId` with `{}`", std::any::type_name::<D>());
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of attributes.
|
||||
pub type AttrVec = ThinVec<Attribute>;
|
||||
|
||||
@ -2858,6 +2878,7 @@ impl Item {
|
||||
| ItemKind::ForeignMod(_)
|
||||
| ItemKind::GlobalAsm(_)
|
||||
| ItemKind::MacCall(_)
|
||||
| ItemKind::Delegation(_)
|
||||
| ItemKind::MacroDef(_) => None,
|
||||
ItemKind::Static(_) => None,
|
||||
ItemKind::Const(i) => Some(&i.generics),
|
||||
@ -3004,6 +3025,15 @@ pub struct Fn {
|
||||
pub body: Option<P<Block>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct Delegation {
|
||||
/// Path resolution id.
|
||||
pub id: NodeId,
|
||||
pub qself: Option<P<QSelf>>,
|
||||
pub path: Path,
|
||||
pub body: Option<P<Block>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct StaticItem {
|
||||
pub ty: P<Ty>,
|
||||
@ -3089,6 +3119,11 @@ pub enum ItemKind {
|
||||
|
||||
/// A macro definition.
|
||||
MacroDef(MacroDef),
|
||||
|
||||
/// A delegation item (`reuse`).
|
||||
///
|
||||
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
|
||||
Delegation(Box<Delegation>),
|
||||
}
|
||||
|
||||
impl ItemKind {
|
||||
@ -3096,7 +3131,8 @@ impl ItemKind {
|
||||
use ItemKind::*;
|
||||
match self {
|
||||
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
|
||||
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..) => "a",
|
||||
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
|
||||
| Delegation(..) => "a",
|
||||
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
|
||||
}
|
||||
}
|
||||
@ -3120,6 +3156,7 @@ impl ItemKind {
|
||||
ItemKind::MacCall(..) => "item macro invocation",
|
||||
ItemKind::MacroDef(..) => "macro definition",
|
||||
ItemKind::Impl { .. } => "implementation",
|
||||
ItemKind::Delegation(..) => "delegated function",
|
||||
}
|
||||
}
|
||||
|
||||
@ -3161,6 +3198,8 @@ pub enum AssocItemKind {
|
||||
Type(Box<TyAlias>),
|
||||
/// A macro expanding to associated items.
|
||||
MacCall(P<MacCall>),
|
||||
/// An associated delegation item.
|
||||
Delegation(Box<Delegation>),
|
||||
}
|
||||
|
||||
impl AssocItemKind {
|
||||
@ -3169,7 +3208,7 @@ impl AssocItemKind {
|
||||
Self::Const(box ConstItem { defaultness, .. })
|
||||
| Self::Fn(box Fn { defaultness, .. })
|
||||
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
|
||||
Self::MacCall(..) => Defaultness::Final,
|
||||
Self::MacCall(..) | Self::Delegation(..) => Defaultness::Final,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3181,6 +3220,7 @@ impl From<AssocItemKind> for ItemKind {
|
||||
AssocItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind),
|
||||
AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
|
||||
AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
|
||||
AssocItemKind::Delegation(delegation) => ItemKind::Delegation(delegation),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3194,6 +3234,7 @@ impl TryFrom<ItemKind> for AssocItemKind {
|
||||
ItemKind::Fn(fn_kind) => AssocItemKind::Fn(fn_kind),
|
||||
ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
|
||||
ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
|
||||
ItemKind::Delegation(d) => AssocItemKind::Delegation(d),
|
||||
_ => return Err(item_kind),
|
||||
})
|
||||
}
|
||||
@ -3259,7 +3300,7 @@ mod size_asserts {
|
||||
static_assert_size!(ForeignItem, 96);
|
||||
static_assert_size!(ForeignItemKind, 24);
|
||||
static_assert_size!(GenericArg, 24);
|
||||
static_assert_size!(GenericBound, 64);
|
||||
static_assert_size!(GenericBound, 72);
|
||||
static_assert_size!(Generics, 40);
|
||||
static_assert_size!(Impl, 136);
|
||||
static_assert_size!(Item, 136);
|
||||
|
||||
@ -13,13 +13,11 @@
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![recursion_limit = "256"]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
|
||||
@ -1117,6 +1117,14 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
|
||||
}
|
||||
ItemKind::MacCall(m) => vis.visit_mac_call(m),
|
||||
ItemKind::MacroDef(def) => vis.visit_macro_def(def),
|
||||
ItemKind::Delegation(box Delegation { id, qself, path, body }) => {
|
||||
vis.visit_id(id);
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
if let Some(body) = body {
|
||||
vis.visit_block(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1155,6 +1163,14 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
|
||||
visit_opt(ty, |ty| visitor.visit_ty(ty));
|
||||
}
|
||||
AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
|
||||
AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => {
|
||||
visitor.visit_id(id);
|
||||
visitor.visit_qself(qself);
|
||||
visitor.visit_path(path);
|
||||
if let Some(body) = body {
|
||||
visitor.visit_block(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
visitor.visit_span(span);
|
||||
visit_lazy_tts(tokens, visitor);
|
||||
@ -1251,7 +1267,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
|
||||
let Pat { id, kind, span, tokens } = pat.deref_mut();
|
||||
vis.visit_id(id);
|
||||
match kind {
|
||||
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||
PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {}
|
||||
PatKind::Ident(_binding_mode, ident, sub) => {
|
||||
vis.visit_ident(ident);
|
||||
visit_opt(sub, |sub| vis.visit_pat(sub));
|
||||
@ -1389,7 +1405,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||
vis.visit_block(body);
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
}
|
||||
ExprKind::ForLoop(pat, iter, body, label) => {
|
||||
ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
|
||||
vis.visit_pat(pat);
|
||||
vis.visit_expr(iter);
|
||||
vis.visit_block(body);
|
||||
|
||||
@ -528,15 +528,6 @@ impl Token {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the token can appear at the start of a generic bound.
|
||||
pub fn can_begin_bound(&self) -> bool {
|
||||
self.is_path_start()
|
||||
|| self.is_lifetime()
|
||||
|| self.is_keyword(kw::For)
|
||||
|| self == &Question
|
||||
|| self == &OpenDelim(Delimiter::Parenthesis)
|
||||
}
|
||||
|
||||
/// Returns `true` if the token can appear at the start of an item.
|
||||
pub fn can_begin_item(&self) -> bool {
|
||||
match self.kind {
|
||||
|
||||
@ -21,12 +21,12 @@ use crate::AttrVec;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::{self, Lrc};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::{cmp, fmt, iter, mem};
|
||||
use std::{cmp, fmt, iter};
|
||||
|
||||
/// When the main Rust parser encounters a syntax-extension invocation, it
|
||||
/// parses the arguments to the invocation as a token tree. This is a very
|
||||
@ -81,14 +81,6 @@ impl TokenTree {
|
||||
}
|
||||
}
|
||||
|
||||
/// Modify the `TokenTree`'s span in-place.
|
||||
pub fn set_span(&mut self, span: Span) {
|
||||
match self {
|
||||
TokenTree::Token(token, _) => token.span = span,
|
||||
TokenTree::Delimited(dspan, ..) => *dspan = DelimSpan::from_single(span),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a `TokenTree::Token` with alone spacing.
|
||||
pub fn token_alone(kind: TokenKind, span: Span) -> TokenTree {
|
||||
TokenTree::Token(Token::new(kind, span), Spacing::Alone)
|
||||
@ -158,14 +150,14 @@ impl fmt::Debug for LazyAttrTokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Encoder> Encodable<S> for LazyAttrTokenStream {
|
||||
impl<S: SpanEncoder> Encodable<S> for LazyAttrTokenStream {
|
||||
fn encode(&self, s: &mut S) {
|
||||
// Used by AST json printing.
|
||||
Encodable::encode(&self.to_attr_token_stream(), s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Decoder> Decodable<D> for LazyAttrTokenStream {
|
||||
impl<D: SpanDecoder> Decodable<D> for LazyAttrTokenStream {
|
||||
fn decode(_d: &mut D) -> Self {
|
||||
panic!("Attempted to decode LazyAttrTokenStream");
|
||||
}
|
||||
@ -461,19 +453,6 @@ impl TokenStream {
|
||||
t1.next().is_none() && t2.next().is_none()
|
||||
}
|
||||
|
||||
/// Applies the supplied function to each `TokenTree` and its index in `self`, returning a new `TokenStream`
|
||||
///
|
||||
/// It is equivalent to `TokenStream::new(self.trees().cloned().enumerate().map(|(i, tt)| f(i, tt)).collect())`.
|
||||
pub fn map_enumerated_owned(
|
||||
mut self,
|
||||
mut f: impl FnMut(usize, TokenTree) -> TokenTree,
|
||||
) -> TokenStream {
|
||||
let owned = Lrc::make_mut(&mut self.0); // clone if necessary
|
||||
// rely on vec's in-place optimizations to avoid another allocation
|
||||
*owned = mem::take(owned).into_iter().enumerate().map(|(i, tree)| f(i, tree)).collect();
|
||||
self
|
||||
}
|
||||
|
||||
/// Create a token stream containing a single token with alone spacing. The
|
||||
/// spacing used for the final token in a constructed stream doesn't matter
|
||||
/// because it's never used. In practice we arbitrarily use
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
// Predicates on exprs and stmts that the pretty-printer and parser use
|
||||
|
||||
use crate::ast;
|
||||
use crate::{ast, token::Delimiter};
|
||||
|
||||
/// Does this expression require a semicolon to be treated
|
||||
/// as a statement? The negation of this: 'can this expression
|
||||
@ -19,7 +19,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
|
||||
| ast::ExprKind::Block(..)
|
||||
| ast::ExprKind::While(..)
|
||||
| ast::ExprKind::Loop(..)
|
||||
| ast::ExprKind::ForLoop(..)
|
||||
| ast::ExprKind::ForLoop { .. }
|
||||
| ast::ExprKind::TryBlock(..)
|
||||
| ast::ExprKind::ConstBlock(..)
|
||||
)
|
||||
@ -48,11 +48,23 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
||||
Closure(closure) => {
|
||||
expr = &closure.body;
|
||||
}
|
||||
Gen(..) | Block(..) | ForLoop(..) | If(..) | Loop(..) | Match(..) | Struct(..)
|
||||
| TryBlock(..) | While(..) | ConstBlock(_) => break Some(expr),
|
||||
Gen(..)
|
||||
| Block(..)
|
||||
| ForLoop { .. }
|
||||
| If(..)
|
||||
| Loop(..)
|
||||
| Match(..)
|
||||
| Struct(..)
|
||||
| TryBlock(..)
|
||||
| While(..)
|
||||
| ConstBlock(_) => break Some(expr),
|
||||
|
||||
// FIXME: These can end in `}`, but changing these would break stable code.
|
||||
InlineAsm(_) | OffsetOf(_, _) | MacCall(_) | IncludedBytes(_) | FormatArgs(_) => {
|
||||
MacCall(mac) => {
|
||||
break (mac.args.delim == Delimiter::Brace).then_some(expr);
|
||||
}
|
||||
|
||||
InlineAsm(_) | OffsetOf(_, _) | IncludedBytes(_) | FormatArgs(_) => {
|
||||
// These should have been denied pre-expansion.
|
||||
break None;
|
||||
}
|
||||
|
||||
|
||||
@ -3,12 +3,10 @@
|
||||
use crate::ast::{self, LitKind, MetaItemLit, StrStyle};
|
||||
use crate::token::{self, Token};
|
||||
use rustc_lexer::unescape::{
|
||||
byte_from_char, unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit,
|
||||
Mode,
|
||||
byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, MixedUnit, Mode,
|
||||
};
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
use std::ops::Range;
|
||||
use std::{ascii, fmt, str};
|
||||
|
||||
// Escapes a string, represented as a symbol. Reuses the original symbol,
|
||||
@ -39,7 +37,6 @@ pub enum LitError {
|
||||
InvalidFloatSuffix,
|
||||
NonDecimalFloat(u32),
|
||||
IntTooLarge(u32),
|
||||
NulInCStr(Range<usize>),
|
||||
}
|
||||
|
||||
impl LitKind {
|
||||
@ -50,6 +47,9 @@ impl LitKind {
|
||||
return Err(LitError::InvalidSuffix);
|
||||
}
|
||||
|
||||
// For byte/char/string literals, chars and escapes have already been
|
||||
// checked in the lexer (in `cook_lexer_literal`). So we can assume all
|
||||
// chars and escapes are valid here.
|
||||
Ok(match kind {
|
||||
token::Bool => {
|
||||
assert!(symbol.is_bool_lit());
|
||||
@ -58,12 +58,12 @@ impl LitKind {
|
||||
token::Byte => {
|
||||
return unescape_byte(symbol.as_str())
|
||||
.map(LitKind::Byte)
|
||||
.map_err(|_| LitError::LexerError);
|
||||
.map_err(|_| panic!("failed to unescape byte literal"));
|
||||
}
|
||||
token::Char => {
|
||||
return unescape_char(symbol.as_str())
|
||||
.map(LitKind::Char)
|
||||
.map_err(|_| LitError::LexerError);
|
||||
.map_err(|_| panic!("failed to unescape char literal"));
|
||||
}
|
||||
|
||||
// There are some valid suffixes for integer and float literals,
|
||||
@ -79,26 +79,22 @@ impl LitKind {
|
||||
let s = symbol.as_str();
|
||||
// Vanilla strings are so common we optimize for the common case where no chars
|
||||
// requiring special behaviour are present.
|
||||
let symbol = if s.contains(['\\', '\r']) {
|
||||
let symbol = if s.contains('\\') {
|
||||
let mut buf = String::with_capacity(s.len());
|
||||
let mut error = Ok(());
|
||||
// Force-inlining here is aggressive but the closure is
|
||||
// called on every char in the string, so it can be
|
||||
// hot in programs with many long strings.
|
||||
unescape_literal(
|
||||
// called on every char in the string, so it can be hot in
|
||||
// programs with many long strings containing escapes.
|
||||
unescape_unicode(
|
||||
s,
|
||||
Mode::Str,
|
||||
&mut #[inline(always)]
|
||||
|_, unescaped_char| match unescaped_char {
|
||||
|_, c| match c {
|
||||
Ok(c) => buf.push(c),
|
||||
Err(err) => {
|
||||
if err.is_fatal() {
|
||||
error = Err(LitError::LexerError);
|
||||
}
|
||||
assert!(!err.is_fatal(), "failed to unescape string literal")
|
||||
}
|
||||
},
|
||||
);
|
||||
error?;
|
||||
Symbol::intern(&buf)
|
||||
} else {
|
||||
symbol
|
||||
@ -106,92 +102,46 @@ impl LitKind {
|
||||
LitKind::Str(symbol, ast::StrStyle::Cooked)
|
||||
}
|
||||
token::StrRaw(n) => {
|
||||
// Raw strings have no escapes, so we only need to check for invalid chars, and we
|
||||
// can reuse the symbol on success.
|
||||
let mut error = Ok(());
|
||||
unescape_literal(symbol.as_str(), Mode::RawStr, &mut |_, unescaped_char| {
|
||||
match unescaped_char {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
if err.is_fatal() {
|
||||
error = Err(LitError::LexerError);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
error?;
|
||||
// Raw strings have no escapes so no work is needed here.
|
||||
LitKind::Str(symbol, ast::StrStyle::Raw(n))
|
||||
}
|
||||
token::ByteStr => {
|
||||
let s = symbol.as_str();
|
||||
let mut buf = Vec::with_capacity(s.len());
|
||||
let mut error = Ok(());
|
||||
unescape_literal(s, Mode::ByteStr, &mut |_, c| match c {
|
||||
unescape_unicode(s, Mode::ByteStr, &mut |_, c| match c {
|
||||
Ok(c) => buf.push(byte_from_char(c)),
|
||||
Err(err) => {
|
||||
if err.is_fatal() {
|
||||
error = Err(LitError::LexerError);
|
||||
}
|
||||
assert!(!err.is_fatal(), "failed to unescape string literal")
|
||||
}
|
||||
});
|
||||
error?;
|
||||
LitKind::ByteStr(buf.into(), StrStyle::Cooked)
|
||||
}
|
||||
token::ByteStrRaw(n) => {
|
||||
// Raw strings have no escapes, so we only need to check for invalid chars, and we
|
||||
// can convert the symbol directly to a `Lrc<u8>` on success.
|
||||
let s = symbol.as_str();
|
||||
let mut error = Ok(());
|
||||
unescape_literal(s, Mode::RawByteStr, &mut |_, c| match c {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
if err.is_fatal() {
|
||||
error = Err(LitError::LexerError);
|
||||
}
|
||||
}
|
||||
});
|
||||
LitKind::ByteStr(s.to_owned().into_bytes().into(), StrStyle::Raw(n))
|
||||
// Raw strings have no escapes so we can convert the symbol
|
||||
// directly to a `Lrc<u8>`.
|
||||
let buf = symbol.as_str().to_owned().into_bytes();
|
||||
LitKind::ByteStr(buf.into(), StrStyle::Raw(n))
|
||||
}
|
||||
token::CStr => {
|
||||
let s = symbol.as_str();
|
||||
let mut buf = Vec::with_capacity(s.len());
|
||||
let mut error = Ok(());
|
||||
unescape_c_string(s, Mode::CStr, &mut |span, c| match c {
|
||||
Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
|
||||
error = Err(LitError::NulInCStr(span));
|
||||
}
|
||||
Ok(CStrUnit::Byte(b)) => buf.push(b),
|
||||
Ok(CStrUnit::Char(c)) => {
|
||||
unescape_mixed(s, Mode::CStr, &mut |_span, c| match c {
|
||||
Ok(MixedUnit::Char(c)) => {
|
||||
buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
|
||||
}
|
||||
Ok(MixedUnit::HighByte(b)) => buf.push(b),
|
||||
Err(err) => {
|
||||
if err.is_fatal() {
|
||||
error = Err(LitError::LexerError);
|
||||
}
|
||||
assert!(!err.is_fatal(), "failed to unescape C string literal")
|
||||
}
|
||||
});
|
||||
error?;
|
||||
buf.push(0);
|
||||
LitKind::CStr(buf.into(), StrStyle::Cooked)
|
||||
}
|
||||
token::CStrRaw(n) => {
|
||||
// Raw strings have no escapes, so we only need to check for invalid chars, and we
|
||||
// can convert the symbol directly to a `Lrc<u8>` on success.
|
||||
let s = symbol.as_str();
|
||||
let mut error = Ok(());
|
||||
unescape_c_string(s, Mode::RawCStr, &mut |span, c| match c {
|
||||
Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
|
||||
error = Err(LitError::NulInCStr(span));
|
||||
}
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
if err.is_fatal() {
|
||||
error = Err(LitError::LexerError);
|
||||
}
|
||||
}
|
||||
});
|
||||
error?;
|
||||
let mut buf = s.to_owned().into_bytes();
|
||||
// Raw strings have no escapes so we can convert the symbol
|
||||
// directly to a `Lrc<u8>` after appending the terminating NUL
|
||||
// char.
|
||||
let mut buf = symbol.as_str().to_owned().into_bytes();
|
||||
buf.push(0);
|
||||
LitKind::CStr(buf.into(), StrStyle::Raw(n))
|
||||
}
|
||||
@ -374,7 +324,7 @@ fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitErr
|
||||
};
|
||||
|
||||
let s = &s[if base != 10 { 2 } else { 0 }..];
|
||||
u128::from_str_radix(s, base).map(|i| LitKind::Int(i, ty)).map_err(|_| {
|
||||
u128::from_str_radix(s, base).map(|i| LitKind::Int(i.into(), ty)).map_err(|_| {
|
||||
// Small bases are lexed as if they were base 10, e.g, the string
|
||||
// might be `0b10201`. This will cause the conversion above to fail,
|
||||
// but these kinds of errors are already reported by the lexer.
|
||||
|
||||
@ -375,6 +375,15 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
|
||||
}
|
||||
ItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
|
||||
ItemKind::MacroDef(ts) => visitor.visit_mac_def(ts, item.id),
|
||||
ItemKind::Delegation(box Delegation { id, qself, path, body }) => {
|
||||
if let Some(qself) = qself {
|
||||
visitor.visit_ty(&qself.ty);
|
||||
}
|
||||
visitor.visit_path(path, *id);
|
||||
if let Some(body) = body {
|
||||
visitor.visit_block(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
walk_list!(visitor, visit_attribute, &item.attrs);
|
||||
}
|
||||
@ -493,7 +502,7 @@ where
|
||||
}
|
||||
GenericArgs::Parenthesized(data) => {
|
||||
walk_list!(visitor, visit_ty, &data.inputs);
|
||||
walk_fn_ret_ty(visitor, &data.output);
|
||||
visitor.visit_fn_ret_ty(&data.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -559,7 +568,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
||||
walk_list!(visitor, visit_expr, lower_bound);
|
||||
walk_list!(visitor, visit_expr, upper_bound);
|
||||
}
|
||||
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||
PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {}
|
||||
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
|
||||
walk_list!(visitor, visit_pat, elems);
|
||||
}
|
||||
@ -704,6 +713,15 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
|
||||
AssocItemKind::MacCall(mac) => {
|
||||
visitor.visit_mac_call(mac);
|
||||
}
|
||||
AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => {
|
||||
if let Some(qself) = qself {
|
||||
visitor.visit_ty(&qself.ty);
|
||||
}
|
||||
visitor.visit_path(path, *id);
|
||||
if let Some(body) = body {
|
||||
visitor.visit_block(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -844,11 +862,11 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
||||
visitor.visit_expr(subexpression);
|
||||
visitor.visit_block(block);
|
||||
}
|
||||
ExprKind::ForLoop(pattern, subexpression, block, opt_label) => {
|
||||
walk_list!(visitor, visit_label, opt_label);
|
||||
visitor.visit_pat(pattern);
|
||||
visitor.visit_expr(subexpression);
|
||||
visitor.visit_block(block);
|
||||
ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
|
||||
walk_list!(visitor, visit_label, label);
|
||||
visitor.visit_pat(pat);
|
||||
visitor.visit_expr(iter);
|
||||
visitor.visit_block(body);
|
||||
}
|
||||
ExprKind::Loop(block, opt_label, _) => {
|
||||
walk_list!(visitor, visit_label, opt_label);
|
||||
|
||||
@ -14,10 +14,6 @@ ast_lowering_assoc_ty_parentheses =
|
||||
ast_lowering_async_coroutines_not_supported =
|
||||
`async` coroutines are not yet supported
|
||||
|
||||
ast_lowering_async_non_move_closure_not_supported =
|
||||
`async` non-`move` closures with parameters are not currently supported
|
||||
.help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure
|
||||
|
||||
ast_lowering_att_syntax_only_x86 =
|
||||
the `att_syntax` option is only supported on x86
|
||||
|
||||
@ -35,7 +31,7 @@ ast_lowering_bad_return_type_notation_output =
|
||||
|
||||
ast_lowering_base_expression_double_dot =
|
||||
base expression required after `..`
|
||||
.label = add a base expression here
|
||||
.suggestion = add a base expression here
|
||||
|
||||
ast_lowering_clobber_abi_not_supported =
|
||||
`clobber_abi` is not supported on this target
|
||||
@ -56,6 +52,9 @@ ast_lowering_functional_record_update_destructuring_assignment =
|
||||
functional record updates are not allowed in destructuring assignments
|
||||
.suggestion = consider removing the trailing pattern
|
||||
|
||||
ast_lowering_generic_param_default_in_binder =
|
||||
defaults for generic parameters are not allowed in `for<...>` binders
|
||||
|
||||
ast_lowering_generic_type_with_parentheses =
|
||||
parenthesized type parameters may only be used with a `Fn` trait
|
||||
.label = only `Fn` traits may use parentheses
|
||||
@ -103,7 +102,8 @@ ast_lowering_misplaced_double_dot =
|
||||
.note = only allowed in tuple, tuple struct, and slice patterns
|
||||
|
||||
ast_lowering_misplaced_impl_trait =
|
||||
`impl Trait` only allowed in function and inherent method argument and return types, not in {$position}
|
||||
`impl Trait` is not allowed in {$position}
|
||||
.note = `impl Trait` is only allowed in arguments and return types of functions and methods
|
||||
|
||||
ast_lowering_misplaced_relax_trait_bound =
|
||||
`?Trait` bounds are only permitted at the point where a type parameter is declared
|
||||
|
||||
@ -32,7 +32,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let asm_arch =
|
||||
if self.tcx.sess.opts.actually_rustdoc { None } else { self.tcx.sess.asm_arch };
|
||||
if asm_arch.is_none() && !self.tcx.sess.opts.actually_rustdoc {
|
||||
self.tcx.sess.emit_err(InlineAsmUnsupportedTarget { span: sp });
|
||||
self.dcx().emit_err(InlineAsmUnsupportedTarget { span: sp });
|
||||
}
|
||||
if let Some(asm_arch) = asm_arch {
|
||||
// Inline assembly is currently only stable for these architectures.
|
||||
@ -48,7 +48,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
);
|
||||
if !is_stable && !self.tcx.features().asm_experimental_arch {
|
||||
feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
&self.tcx.sess,
|
||||
sym::asm_experimental_arch,
|
||||
sp,
|
||||
"inline assembly is not stable yet on this architecture",
|
||||
@ -60,15 +60,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
&& !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
|
||||
&& !self.tcx.sess.opts.actually_rustdoc
|
||||
{
|
||||
self.tcx.sess.emit_err(AttSyntaxOnlyX86 { span: sp });
|
||||
self.dcx().emit_err(AttSyntaxOnlyX86 { span: sp });
|
||||
}
|
||||
if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind {
|
||||
feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
sym::asm_unwind,
|
||||
sp,
|
||||
"the `may_unwind` option is unstable",
|
||||
)
|
||||
feature_err(&self.tcx.sess, sym::asm_unwind, sp, "the `may_unwind` option is unstable")
|
||||
.emit();
|
||||
}
|
||||
|
||||
@ -87,7 +82,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
!= source_map.span_to_snippet(*abi_span))
|
||||
.then_some(());
|
||||
|
||||
self.tcx.sess.emit_err(AbiSpecifiedMultipleTimes {
|
||||
self.dcx().emit_err(AbiSpecifiedMultipleTimes {
|
||||
abi_span: *abi_span,
|
||||
prev_name: *prev_name,
|
||||
prev_span: *prev_sp,
|
||||
@ -100,14 +95,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
}
|
||||
Err(&[]) => {
|
||||
self.tcx.sess.emit_err(ClobberAbiNotSupported { abi_span: *abi_span });
|
||||
self.dcx().emit_err(ClobberAbiNotSupported { abi_span: *abi_span });
|
||||
}
|
||||
Err(supported_abis) => {
|
||||
let mut abis = format!("`{}`", supported_abis[0]);
|
||||
for m in &supported_abis[1..] {
|
||||
let _ = write!(abis, ", `{m}`");
|
||||
}
|
||||
self.tcx.sess.emit_err(InvalidAbiClobberAbi {
|
||||
self.dcx().emit_err(InvalidAbiClobberAbi {
|
||||
abi_span: *abi_span,
|
||||
supported_abis: abis,
|
||||
});
|
||||
@ -128,7 +123,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
InlineAsmRegOrRegClass::Reg(reg) => {
|
||||
asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
|
||||
asm::InlineAsmReg::parse(asm_arch, reg).unwrap_or_else(|error| {
|
||||
sess.emit_err(InvalidRegister { op_span: *op_sp, reg, error });
|
||||
self.dcx().emit_err(InvalidRegister {
|
||||
op_span: *op_sp,
|
||||
reg,
|
||||
error,
|
||||
});
|
||||
asm::InlineAsmReg::Err
|
||||
})
|
||||
} else {
|
||||
@ -139,7 +138,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch {
|
||||
asm::InlineAsmRegClass::parse(asm_arch, reg_class).unwrap_or_else(
|
||||
|error| {
|
||||
sess.emit_err(InvalidRegisterClass {
|
||||
self.dcx().emit_err(InvalidRegisterClass {
|
||||
op_span: *op_sp,
|
||||
reg_class,
|
||||
error,
|
||||
@ -179,7 +178,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
InlineAsmOperand::Const { anon_const } => {
|
||||
if !self.tcx.features().asm_const {
|
||||
feature_err(
|
||||
&sess.parse_sess,
|
||||
sess,
|
||||
sym::asm_const,
|
||||
*op_sp,
|
||||
"const operands for inline assembly are unstable",
|
||||
@ -276,7 +275,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
class_name: class.name(),
|
||||
}
|
||||
};
|
||||
sess.emit_err(InvalidAsmTemplateModifierRegClass {
|
||||
self.dcx().emit_err(InvalidAsmTemplateModifierRegClass {
|
||||
placeholder_span,
|
||||
op_span: op_sp,
|
||||
sub,
|
||||
@ -284,14 +283,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
}
|
||||
hir::InlineAsmOperand::Const { .. } => {
|
||||
sess.emit_err(InvalidAsmTemplateModifierConst {
|
||||
self.dcx().emit_err(InvalidAsmTemplateModifierConst {
|
||||
placeholder_span,
|
||||
op_span: op_sp,
|
||||
});
|
||||
}
|
||||
hir::InlineAsmOperand::SymFn { .. }
|
||||
| hir::InlineAsmOperand::SymStatic { .. } => {
|
||||
sess.emit_err(InvalidAsmTemplateModifierSym {
|
||||
self.dcx().emit_err(InvalidAsmTemplateModifierSym {
|
||||
placeholder_span,
|
||||
op_span: op_sp,
|
||||
});
|
||||
@ -315,7 +314,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// require that the operand name an explicit register, not a
|
||||
// register class.
|
||||
if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() {
|
||||
sess.emit_err(RegisterClassOnlyClobber {
|
||||
self.dcx().emit_err(RegisterClassOnlyClobber {
|
||||
op_span: op_sp,
|
||||
reg_class_name: reg_class.name(),
|
||||
});
|
||||
@ -384,7 +383,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
};
|
||||
|
||||
sess.emit_err(RegisterConflict {
|
||||
self.dcx().emit_err(RegisterConflict {
|
||||
op_span1: op_sp,
|
||||
op_span2: op_sp2,
|
||||
reg1_name: reg_str(idx),
|
||||
|
||||
348
compiler/rustc_ast_lowering/src/delegation.rs
Normal file
348
compiler/rustc_ast_lowering/src/delegation.rs
Normal file
@ -0,0 +1,348 @@
|
||||
//! This module implements expansion of delegation items with early resolved paths.
|
||||
//! It includes a delegation to a free functions:
|
||||
//!
|
||||
//! ```ignore (illustrative)
|
||||
//! reuse module::name { target_expr_template }
|
||||
//! ```
|
||||
//!
|
||||
//! And delegation to a trait methods:
|
||||
//!
|
||||
//! ```ignore (illustrative)
|
||||
//! reuse <Type as Trait>::name { target_expr_template }
|
||||
//! ```
|
||||
//!
|
||||
//! After expansion for both cases we get:
|
||||
//!
|
||||
//! ```ignore (illustrative)
|
||||
//! fn name(
|
||||
//! arg0: InferDelegation(sig_id, Input(0)),
|
||||
//! arg1: InferDelegation(sig_id, Input(1)),
|
||||
//! ...,
|
||||
//! argN: InferDelegation(sig_id, Input(N)),
|
||||
//! ) -> InferDelegation(sig_id, Output) {
|
||||
//! callee_path(target_expr_template(arg0), arg1, ..., argN)
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Where `callee_path` is a path in delegation item e.g. `<Type as Trait>::name`.
|
||||
//! `sig_id` is a id of item from which the signature is inherited. It may be a delegation
|
||||
//! item id (`item_id`) in case of impl trait or path resolution id (`path_id`) otherwise.
|
||||
//!
|
||||
//! Since we do not have a proper way to obtain function type information by path resolution
|
||||
//! in AST, we mark each function parameter type as `InferDelegation` and inherit it in `AstConv`.
|
||||
//!
|
||||
//! Similarly generics, predicates and header are set to the "default" values.
|
||||
//! In case of discrepancy with callee function the `NotSupportedDelegation` error will
|
||||
//! also be emitted in `AstConv`.
|
||||
|
||||
use crate::{ImplTraitPosition, ResolverAstLoweringExt};
|
||||
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode};
|
||||
|
||||
use ast::visit::Visitor;
|
||||
use hir::def::{DefKind, PartialRes, Res};
|
||||
use hir::{BodyId, HirId};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::*;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::ResolverAstLowering;
|
||||
use rustc_span::{symbol::Ident, Span};
|
||||
use rustc_target::spec::abi;
|
||||
use std::iter;
|
||||
|
||||
pub(crate) struct DelegationResults<'hir> {
|
||||
pub body_id: hir::BodyId,
|
||||
pub sig: hir::FnSig<'hir>,
|
||||
pub generics: &'hir hir::Generics<'hir>,
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
pub(crate) fn delegation_has_self(&self, item_id: NodeId, path_id: NodeId, span: Span) -> bool {
|
||||
let sig_id = self.get_delegation_sig_id(item_id, path_id, span);
|
||||
let Ok(sig_id) = sig_id else {
|
||||
return false;
|
||||
};
|
||||
if let Some(local_sig_id) = sig_id.as_local() {
|
||||
self.resolver.has_self.contains(&local_sig_id)
|
||||
} else {
|
||||
match self.tcx.def_kind(sig_id) {
|
||||
DefKind::Fn => false,
|
||||
DefKind::AssocFn => self.tcx.associated_item(sig_id).fn_has_self_parameter,
|
||||
_ => span_bug!(span, "unexpected DefKind for delegation item"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lower_delegation(
|
||||
&mut self,
|
||||
delegation: &Delegation,
|
||||
item_id: NodeId,
|
||||
) -> DelegationResults<'hir> {
|
||||
let span = delegation.path.segments.last().unwrap().ident.span;
|
||||
let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span);
|
||||
match sig_id {
|
||||
Ok(sig_id) => {
|
||||
let decl = self.lower_delegation_decl(sig_id, span);
|
||||
let sig = self.lower_delegation_sig(span, decl);
|
||||
let body_id = self.lower_delegation_body(sig.decl, delegation);
|
||||
|
||||
let generics = self.lower_delegation_generics(span);
|
||||
DelegationResults { body_id, sig, generics }
|
||||
}
|
||||
Err(err) => self.generate_delegation_error(err, span),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_delegation_sig_id(
|
||||
&self,
|
||||
item_id: NodeId,
|
||||
path_id: NodeId,
|
||||
span: Span,
|
||||
) -> Result<DefId, ErrorGuaranteed> {
|
||||
let sig_id = if self.is_in_trait_impl { item_id } else { path_id };
|
||||
let sig_id = self
|
||||
.resolver
|
||||
.get_partial_res(sig_id)
|
||||
.map(|r| r.expect_full_res().opt_def_id())
|
||||
.unwrap_or(None);
|
||||
|
||||
sig_id.ok_or_else(|| {
|
||||
self.tcx
|
||||
.dcx()
|
||||
.span_delayed_bug(span, "LoweringContext: couldn't resolve delegation item")
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
|
||||
self.arena.alloc(hir::Generics {
|
||||
params: &[],
|
||||
predicates: &[],
|
||||
has_where_clause_predicates: false,
|
||||
where_clause_span: span,
|
||||
span: span,
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_delegation_decl(
|
||||
&mut self,
|
||||
sig_id: DefId,
|
||||
param_span: Span,
|
||||
) -> &'hir hir::FnDecl<'hir> {
|
||||
let args_count = if let Some(local_sig_id) = sig_id.as_local() {
|
||||
// Map may be filled incorrectly due to recursive delegation.
|
||||
// Error will be emmited later in astconv.
|
||||
self.resolver.fn_parameter_counts.get(&local_sig_id).cloned().unwrap_or_default()
|
||||
} else {
|
||||
self.tcx.fn_arg_names(sig_id).len()
|
||||
};
|
||||
let inputs = self.arena.alloc_from_iter((0..args_count).into_iter().map(|arg| hir::Ty {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)),
|
||||
span: self.lower_span(param_span),
|
||||
}));
|
||||
|
||||
let output = self.arena.alloc(hir::Ty {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output),
|
||||
span: self.lower_span(param_span),
|
||||
});
|
||||
|
||||
self.arena.alloc(hir::FnDecl {
|
||||
inputs,
|
||||
output: hir::FnRetTy::Return(output),
|
||||
c_variadic: false,
|
||||
lifetime_elision_allowed: true,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_delegation_sig(
|
||||
&mut self,
|
||||
span: Span,
|
||||
decl: &'hir hir::FnDecl<'hir>,
|
||||
) -> hir::FnSig<'hir> {
|
||||
hir::FnSig {
|
||||
decl,
|
||||
header: hir::FnHeader {
|
||||
unsafety: hir::Unsafety::Normal,
|
||||
constness: hir::Constness::NotConst,
|
||||
asyncness: hir::IsAsync::NotAsync,
|
||||
abi: abi::Abi::Rust,
|
||||
},
|
||||
span: self.lower_span(span),
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_param(&mut self, ty: &'hir hir::Ty<'hir>) -> (hir::Param<'hir>, NodeId) {
|
||||
let pat_node_id = self.next_node_id();
|
||||
let pat_id = self.lower_node_id(pat_node_id);
|
||||
let pat = self.arena.alloc(hir::Pat {
|
||||
hir_id: pat_id,
|
||||
kind: hir::PatKind::Binding(hir::BindingAnnotation::NONE, pat_id, Ident::empty(), None),
|
||||
span: ty.span,
|
||||
default_binding_modes: false,
|
||||
});
|
||||
|
||||
(hir::Param { hir_id: self.next_id(), pat, ty_span: ty.span, span: ty.span }, pat_node_id)
|
||||
}
|
||||
|
||||
fn generate_arg(&mut self, ty: &'hir hir::Ty<'hir>, param_id: HirId) -> hir::Expr<'hir> {
|
||||
let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
|
||||
ident: Ident::empty(),
|
||||
hir_id: self.next_id(),
|
||||
res: Res::Local(param_id),
|
||||
args: None,
|
||||
infer_args: false,
|
||||
}));
|
||||
|
||||
let path =
|
||||
self.arena.alloc(hir::Path { span: ty.span, res: Res::Local(param_id), segments });
|
||||
|
||||
hir::Expr {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
|
||||
span: ty.span,
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_delegation_body(
|
||||
&mut self,
|
||||
decl: &'hir hir::FnDecl<'hir>,
|
||||
delegation: &Delegation,
|
||||
) -> BodyId {
|
||||
let path = self.lower_qpath(
|
||||
delegation.id,
|
||||
&delegation.qself,
|
||||
&delegation.path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
let block = delegation.body.as_deref();
|
||||
|
||||
self.lower_body(|this| {
|
||||
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
|
||||
let mut args: Vec<hir::Expr<'hir>> = Vec::new();
|
||||
|
||||
for (idx, param_ty) in decl.inputs.iter().enumerate() {
|
||||
let (param, pat_node_id) = this.generate_param(param_ty);
|
||||
parameters.push(param);
|
||||
|
||||
let arg = if let Some(block) = block
|
||||
&& idx == 0
|
||||
{
|
||||
let mut self_resolver = SelfResolver {
|
||||
resolver: this.resolver,
|
||||
path_id: delegation.id,
|
||||
self_param_id: pat_node_id,
|
||||
};
|
||||
self_resolver.visit_block(block);
|
||||
let block = this.lower_block(block, false);
|
||||
hir::Expr {
|
||||
hir_id: this.next_id(),
|
||||
kind: hir::ExprKind::Block(block, None),
|
||||
span: block.span,
|
||||
}
|
||||
} else {
|
||||
let pat_hir_id = this.lower_node_id(pat_node_id);
|
||||
this.generate_arg(param_ty, pat_hir_id)
|
||||
};
|
||||
args.push(arg);
|
||||
}
|
||||
|
||||
let args = self.arena.alloc_from_iter(args);
|
||||
let final_expr = this.generate_call(path, args);
|
||||
(this.arena.alloc_from_iter(parameters), final_expr)
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_call(
|
||||
&mut self,
|
||||
path: hir::QPath<'hir>,
|
||||
args: &'hir [hir::Expr<'hir>],
|
||||
) -> hir::Expr<'hir> {
|
||||
let callee = self.arena.alloc(hir::Expr {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ExprKind::Path(path),
|
||||
span: path.span(),
|
||||
});
|
||||
|
||||
let expr = self.arena.alloc(hir::Expr {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ExprKind::Call(callee, args),
|
||||
span: path.span(),
|
||||
});
|
||||
|
||||
let block = self.arena.alloc(hir::Block {
|
||||
stmts: &[],
|
||||
expr: Some(expr),
|
||||
hir_id: self.next_id(),
|
||||
rules: hir::BlockCheckMode::DefaultBlock,
|
||||
span: path.span(),
|
||||
targeted_by_break: false,
|
||||
});
|
||||
|
||||
hir::Expr {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ExprKind::Block(block, None),
|
||||
span: path.span(),
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_delegation_error(
|
||||
&mut self,
|
||||
err: ErrorGuaranteed,
|
||||
span: Span,
|
||||
) -> DelegationResults<'hir> {
|
||||
let generics = self.lower_delegation_generics(span);
|
||||
|
||||
let decl = self.arena.alloc(hir::FnDecl {
|
||||
inputs: &[],
|
||||
output: hir::FnRetTy::DefaultReturn(span),
|
||||
c_variadic: false,
|
||||
lifetime_elision_allowed: true,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
});
|
||||
|
||||
let sig = self.lower_delegation_sig(span, decl);
|
||||
let body_id = self.lower_body(|this| {
|
||||
let expr =
|
||||
hir::Expr { hir_id: this.next_id(), kind: hir::ExprKind::Err(err), span: span };
|
||||
(&[], expr)
|
||||
});
|
||||
DelegationResults { generics, body_id, sig }
|
||||
}
|
||||
}
|
||||
|
||||
struct SelfResolver<'a> {
|
||||
resolver: &'a mut ResolverAstLowering,
|
||||
path_id: NodeId,
|
||||
self_param_id: NodeId,
|
||||
}
|
||||
|
||||
impl<'a> SelfResolver<'a> {
|
||||
fn try_replace_id(&mut self, id: NodeId) {
|
||||
if let Some(res) = self.resolver.partial_res_map.get(&id)
|
||||
&& let Some(Res::Local(sig_id)) = res.full_res()
|
||||
&& sig_id == self.path_id
|
||||
{
|
||||
let new_res = PartialRes::new(Res::Local(self.self_param_id));
|
||||
self.resolver.partial_res_map.insert(id, new_res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, 'a> Visitor<'ast> for SelfResolver<'a> {
|
||||
fn visit_path(&mut self, path: &'ast Path, id: NodeId) {
|
||||
self.try_replace_id(id);
|
||||
visit::walk_path(self, path);
|
||||
}
|
||||
|
||||
fn visit_path_segment(&mut self, seg: &'ast PathSegment) {
|
||||
self.try_replace_id(seg.id);
|
||||
visit::walk_path_segment(self, seg);
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
use rustc_errors::DiagnosticArgFromDisplay;
|
||||
use rustc_errors::{codes::*, DiagnosticArgFromDisplay};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering_generic_type_with_parentheses, code = "E0214")]
|
||||
#[diag(ast_lowering_generic_type_with_parentheses, code = E0214)]
|
||||
pub struct GenericTypeWithParentheses {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
@ -22,7 +22,7 @@ pub struct UseAngleBrackets {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_invalid_abi, code = "E0703")]
|
||||
#[diag(ast_lowering_invalid_abi, code = E0703)]
|
||||
#[note]
|
||||
pub struct InvalidAbi {
|
||||
#[primary_span]
|
||||
@ -89,7 +89,8 @@ pub enum AssocTyParenthesesSub {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_misplaced_impl_trait, code = "E0562")]
|
||||
#[diag(ast_lowering_misplaced_impl_trait, code = E0562)]
|
||||
#[note]
|
||||
pub struct MisplacedImplTrait<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -113,15 +114,15 @@ pub struct UnderscoreExprLhsAssign {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering_base_expression_double_dot)]
|
||||
#[diag(ast_lowering_base_expression_double_dot, code = E0797)]
|
||||
pub struct BaseExpressionDoubleDot {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[suggestion(code = "/* expr */", applicability = "has-placeholders", style = "verbose")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = "E0728")]
|
||||
#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = E0728)]
|
||||
pub struct AwaitOnlyInAsyncFnAndBlocks {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
@ -131,27 +132,19 @@ pub struct AwaitOnlyInAsyncFnAndBlocks {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering_coroutine_too_many_parameters, code = "E0628")]
|
||||
#[diag(ast_lowering_coroutine_too_many_parameters, code = E0628)]
|
||||
pub struct CoroutineTooManyParameters {
|
||||
#[primary_span]
|
||||
pub fn_decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering_closure_cannot_be_static, code = "E0697")]
|
||||
#[diag(ast_lowering_closure_cannot_be_static, code = E0697)]
|
||||
pub struct ClosureCannotBeStatic {
|
||||
#[primary_span]
|
||||
pub fn_decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[help]
|
||||
#[diag(ast_lowering_async_non_move_closure_not_supported, code = "E0708")]
|
||||
pub struct AsyncNonMoveClosureNotSupported {
|
||||
#[primary_span]
|
||||
pub fn_decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering_functional_record_update_destructuring_assignment)]
|
||||
pub struct FunctionalRecordUpdateDestructuringAssignment {
|
||||
@ -161,14 +154,14 @@ pub struct FunctionalRecordUpdateDestructuringAssignment {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering_async_coroutines_not_supported, code = "E0727")]
|
||||
#[diag(ast_lowering_async_coroutines_not_supported, code = E0727)]
|
||||
pub struct AsyncCoroutinesNotSupported {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering_inline_asm_unsupported_target, code = "E0472")]
|
||||
#[diag(ast_lowering_inline_asm_unsupported_target, code = E0472)]
|
||||
pub struct InlineAsmUnsupportedTarget {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -395,3 +388,10 @@ pub enum BadReturnTypeNotation {
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_generic_param_default_in_binder)]
|
||||
pub(crate) struct GenericParamDefaultInBinder {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use super::errors::{
|
||||
AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
|
||||
BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters,
|
||||
AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
|
||||
ClosureCannotBeStatic, CoroutineTooManyParameters,
|
||||
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
|
||||
NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure,
|
||||
UnderscoreExprLhsAssign,
|
||||
@ -13,7 +13,6 @@ use rustc_ast::*;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::source_map::{respan, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
@ -56,12 +55,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
return ex;
|
||||
}
|
||||
// Desugar `ExprForLoop`
|
||||
// from: `[opt_ident]: for <pat> in <head> <body>`
|
||||
// from: `[opt_ident]: for await? <pat> in <iter> <body>`
|
||||
//
|
||||
// This also needs special handling because the HirId of the returned `hir::Expr` will not
|
||||
// correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself.
|
||||
ExprKind::ForLoop(pat, head, body, opt_label) => {
|
||||
return self.lower_expr_for(e, pat, head, body, *opt_label);
|
||||
ExprKind::ForLoop { pat, iter, body, label, kind } => {
|
||||
return self.lower_expr_for(e, pat, iter, body, *label, *kind);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
@ -154,7 +153,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
ExprKind::Let(pat, scrutinee, span, is_recovered) => {
|
||||
hir::ExprKind::Let(self.arena.alloc(hir::Let {
|
||||
hir_id: self.next_id(),
|
||||
span: self.lower_span(*span),
|
||||
pat: self.lower_pat(pat),
|
||||
ty: None,
|
||||
@ -183,14 +181,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
|
||||
hir::MatchSource::Normal,
|
||||
),
|
||||
ExprKind::Gen(capture_clause, block, GenBlockKind::Async) => self.make_async_expr(
|
||||
*capture_clause,
|
||||
e.id,
|
||||
None,
|
||||
e.span,
|
||||
hir::CoroutineSource::Block,
|
||||
|this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
|
||||
),
|
||||
ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
|
||||
ExprKind::Closure(box Closure {
|
||||
binder,
|
||||
@ -226,6 +216,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
*fn_arg_span,
|
||||
),
|
||||
},
|
||||
ExprKind::Gen(capture_clause, block, genblock_kind) => {
|
||||
let desugaring_kind = match genblock_kind {
|
||||
GenBlockKind::Async => hir::CoroutineDesugaring::Async,
|
||||
GenBlockKind::Gen => hir::CoroutineDesugaring::Gen,
|
||||
GenBlockKind::AsyncGen => hir::CoroutineDesugaring::AsyncGen,
|
||||
};
|
||||
self.make_desugared_coroutine_expr(
|
||||
*capture_clause,
|
||||
e.id,
|
||||
None,
|
||||
e.span,
|
||||
desugaring_kind,
|
||||
hir::CoroutineSource::Block,
|
||||
|this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
|
||||
)
|
||||
}
|
||||
ExprKind::Block(blk, opt_label) => {
|
||||
let opt_label = self.lower_label(*opt_label);
|
||||
hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
|
||||
@ -249,7 +255,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims)
|
||||
}
|
||||
ExprKind::Underscore => {
|
||||
let guar = self.tcx.sess.emit_err(UnderscoreExprLhsAssign { span: e.span });
|
||||
let guar = self.dcx().emit_err(UnderscoreExprLhsAssign { span: e.span });
|
||||
hir::ExprKind::Err(guar)
|
||||
}
|
||||
ExprKind::Path(qself, path) => {
|
||||
@ -294,8 +300,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let rest = match &se.rest {
|
||||
StructRest::Base(e) => Some(self.lower_expr(e)),
|
||||
StructRest::Rest(sp) => {
|
||||
let guar =
|
||||
self.tcx.sess.emit_err(BaseExpressionDoubleDot { span: *sp });
|
||||
let guar = self.dcx().emit_err(BaseExpressionDoubleDot { span: *sp });
|
||||
Some(&*self.arena.alloc(self.expr_err(*sp, guar)))
|
||||
}
|
||||
StructRest::None => None,
|
||||
@ -314,30 +319,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
rest,
|
||||
)
|
||||
}
|
||||
ExprKind::Gen(capture_clause, block, GenBlockKind::Gen) => self.make_gen_expr(
|
||||
*capture_clause,
|
||||
e.id,
|
||||
None,
|
||||
e.span,
|
||||
hir::CoroutineSource::Block,
|
||||
|this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
|
||||
),
|
||||
ExprKind::Gen(capture_clause, block, GenBlockKind::AsyncGen) => self
|
||||
.make_async_gen_expr(
|
||||
*capture_clause,
|
||||
e.id,
|
||||
None,
|
||||
e.span,
|
||||
hir::CoroutineSource::Block,
|
||||
|this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
|
||||
),
|
||||
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
||||
ExprKind::Err => hir::ExprKind::Err(
|
||||
self.tcx.sess.span_delayed_bug(e.span, "lowered ExprKind::Err"),
|
||||
),
|
||||
ExprKind::Err => {
|
||||
hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err"))
|
||||
}
|
||||
ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
|
||||
|
||||
ExprKind::Paren(_) | ExprKind::ForLoop(..) => {
|
||||
ExprKind::Paren(_) | ExprKind::ForLoop { .. } => {
|
||||
unreachable!("already handled")
|
||||
}
|
||||
|
||||
@ -556,20 +544,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
|
||||
let pat = self.lower_pat(&arm.pat);
|
||||
let mut guard = arm.guard.as_ref().map(|cond| {
|
||||
if let ExprKind::Let(pat, scrutinee, span, is_recovered) = &cond.kind {
|
||||
hir::Guard::IfLet(self.arena.alloc(hir::Let {
|
||||
hir_id: self.next_id(),
|
||||
span: self.lower_span(*span),
|
||||
pat: self.lower_pat(pat),
|
||||
ty: None,
|
||||
init: self.lower_expr(scrutinee),
|
||||
is_recovered: *is_recovered,
|
||||
}))
|
||||
} else {
|
||||
hir::Guard::If(self.lower_expr(cond))
|
||||
}
|
||||
});
|
||||
let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond));
|
||||
let hir_id = self.next_id();
|
||||
let span = self.lower_span(arm.span);
|
||||
self.lower_attrs(hir_id, &arm.attrs);
|
||||
@ -584,14 +559,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
if self.tcx.features().never_patterns {
|
||||
// If the feature is off we already emitted the error after parsing.
|
||||
let suggestion = span.shrink_to_hi();
|
||||
self.tcx.sess.emit_err(MatchArmWithNoBody { span, suggestion });
|
||||
self.dcx().emit_err(MatchArmWithNoBody { span, suggestion });
|
||||
}
|
||||
} else if let Some(body) = &arm.body {
|
||||
self.tcx.sess.emit_err(NeverPatternWithBody { span: body.span });
|
||||
guard = None;
|
||||
self.dcx().emit_err(NeverPatternWithBody { span: body.span });
|
||||
} else if let Some(g) = &arm.guard {
|
||||
self.tcx.sess.emit_err(NeverPatternWithGuard { span: g.span });
|
||||
guard = None;
|
||||
self.dcx().emit_err(NeverPatternWithGuard { span: g.span });
|
||||
}
|
||||
|
||||
// We add a fake `loop {}` arm body so that it typecks to `!`.
|
||||
@ -613,179 +586,46 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir::Arm { hir_id, pat, guard, body, span }
|
||||
}
|
||||
|
||||
/// Lower an `async` construct to a coroutine that implements `Future`.
|
||||
/// Lower/desugar a coroutine construct.
|
||||
///
|
||||
/// In particular, this creates the correct async resume argument and `_task_context`.
|
||||
///
|
||||
/// This results in:
|
||||
///
|
||||
/// ```text
|
||||
/// static move? |_task_context| -> <ret_ty> {
|
||||
/// static move? |<_task_context?>| -> <return_ty> {
|
||||
/// <body>
|
||||
/// }
|
||||
/// ```
|
||||
pub(super) fn make_async_expr(
|
||||
pub(super) fn make_desugared_coroutine_expr(
|
||||
&mut self,
|
||||
capture_clause: CaptureBy,
|
||||
closure_node_id: NodeId,
|
||||
ret_ty: Option<hir::FnRetTy<'hir>>,
|
||||
span: Span,
|
||||
async_coroutine_source: hir::CoroutineSource,
|
||||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
|
||||
|
||||
// Resume argument type: `ResumeTy`
|
||||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Async,
|
||||
self.lower_span(span),
|
||||
Some(self.allow_gen_future.clone()),
|
||||
);
|
||||
let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span);
|
||||
let input_ty = hir::Ty {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::TyKind::Path(resume_ty),
|
||||
span: unstable_span,
|
||||
};
|
||||
|
||||
// The closure/coroutine `FnDecl` takes a single (resume) argument of type `input_ty`.
|
||||
let fn_decl = self.arena.alloc(hir::FnDecl {
|
||||
inputs: arena_vec![self; input_ty],
|
||||
output,
|
||||
c_variadic: false,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
lifetime_elision_allowed: false,
|
||||
});
|
||||
|
||||
// Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
|
||||
let (pat, task_context_hid) = self.pat_ident_binding_mode(
|
||||
span,
|
||||
Ident::with_dummy_span(sym::_task_context),
|
||||
hir::BindingAnnotation::MUT,
|
||||
);
|
||||
let param = hir::Param {
|
||||
hir_id: self.next_id(),
|
||||
pat,
|
||||
ty_span: self.lower_span(span),
|
||||
span: self.lower_span(span),
|
||||
};
|
||||
let params = arena_vec![self; param];
|
||||
|
||||
let body = self.lower_body(move |this| {
|
||||
this.coroutine_kind = Some(hir::CoroutineKind::Async(async_coroutine_source));
|
||||
|
||||
let old_ctx = this.task_context;
|
||||
this.task_context = Some(task_context_hid);
|
||||
let res = body(this);
|
||||
this.task_context = old_ctx;
|
||||
(params, res)
|
||||
});
|
||||
|
||||
// `static |_task_context| -> <ret_ty> { body }`:
|
||||
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_node_id),
|
||||
binder: hir::ClosureBinder::Default,
|
||||
capture_clause,
|
||||
bound_generic_params: &[],
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span: self.lower_span(span),
|
||||
fn_arg_span: None,
|
||||
movability: Some(hir::Movability::Static),
|
||||
constness: hir::Constness::NotConst,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Lower a `gen` construct to a generator that implements `Iterator`.
|
||||
///
|
||||
/// This results in:
|
||||
///
|
||||
/// ```text
|
||||
/// static move? |()| -> () {
|
||||
/// <body>
|
||||
/// }
|
||||
/// ```
|
||||
pub(super) fn make_gen_expr(
|
||||
&mut self,
|
||||
capture_clause: CaptureBy,
|
||||
closure_node_id: NodeId,
|
||||
_yield_ty: Option<hir::FnRetTy<'hir>>,
|
||||
return_ty: Option<hir::FnRetTy<'hir>>,
|
||||
span: Span,
|
||||
desugaring_kind: hir::CoroutineDesugaring,
|
||||
coroutine_source: hir::CoroutineSource,
|
||||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let output = hir::FnRetTy::DefaultReturn(self.lower_span(span));
|
||||
|
||||
// The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
|
||||
let fn_decl = self.arena.alloc(hir::FnDecl {
|
||||
inputs: &[],
|
||||
output,
|
||||
c_variadic: false,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
lifetime_elision_allowed: false,
|
||||
});
|
||||
|
||||
let body = self.lower_body(move |this| {
|
||||
this.coroutine_kind = Some(hir::CoroutineKind::Gen(coroutine_source));
|
||||
|
||||
let res = body(this);
|
||||
(&[], res)
|
||||
});
|
||||
|
||||
// `static |()| -> () { body }`:
|
||||
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_node_id),
|
||||
binder: hir::ClosureBinder::Default,
|
||||
capture_clause,
|
||||
bound_generic_params: &[],
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span: self.lower_span(span),
|
||||
fn_arg_span: None,
|
||||
movability: Some(Movability::Movable),
|
||||
constness: hir::Constness::NotConst,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Lower a `async gen` construct to a generator that implements `AsyncIterator`.
|
||||
///
|
||||
/// This results in:
|
||||
///
|
||||
/// ```text
|
||||
/// static move? |_task_context| -> () {
|
||||
/// <body>
|
||||
/// }
|
||||
/// ```
|
||||
pub(super) fn make_async_gen_expr(
|
||||
&mut self,
|
||||
capture_clause: CaptureBy,
|
||||
closure_node_id: NodeId,
|
||||
_yield_ty: Option<hir::FnRetTy<'hir>>,
|
||||
span: Span,
|
||||
async_coroutine_source: hir::CoroutineSource,
|
||||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let output = hir::FnRetTy::DefaultReturn(self.lower_span(span));
|
||||
let coroutine_kind = hir::CoroutineKind::Desugared(desugaring_kind, coroutine_source);
|
||||
|
||||
// The `async` desugaring takes a resume argument and maintains a `task_context`,
|
||||
// whereas a generator does not.
|
||||
let (inputs, params, task_context): (&[_], &[_], _) = match desugaring_kind {
|
||||
hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen => {
|
||||
// Resume argument type: `ResumeTy`
|
||||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Async,
|
||||
self.lower_span(span),
|
||||
Some(self.allow_gen_future.clone()),
|
||||
);
|
||||
let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span);
|
||||
let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span);
|
||||
let input_ty = hir::Ty {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::TyKind::Path(resume_ty),
|
||||
span: unstable_span,
|
||||
};
|
||||
|
||||
// The closure/coroutine `FnDecl` takes a single (resume) argument of type `input_ty`.
|
||||
let fn_decl = self.arena.alloc(hir::FnDecl {
|
||||
inputs: arena_vec![self; input_ty],
|
||||
output,
|
||||
c_variadic: false,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
lifetime_elision_allowed: false,
|
||||
});
|
||||
let inputs = arena_vec![self; input_ty];
|
||||
|
||||
// Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
|
||||
let (pat, task_context_hid) = self.pat_ident_binding_mode(
|
||||
@ -801,17 +641,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
};
|
||||
let params = arena_vec![self; param];
|
||||
|
||||
(inputs, params, Some(task_context_hid))
|
||||
}
|
||||
hir::CoroutineDesugaring::Gen => (&[], &[], None),
|
||||
};
|
||||
|
||||
let output =
|
||||
return_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
|
||||
|
||||
let fn_decl = self.arena.alloc(hir::FnDecl {
|
||||
inputs,
|
||||
output,
|
||||
c_variadic: false,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
lifetime_elision_allowed: false,
|
||||
});
|
||||
|
||||
let body = self.lower_body(move |this| {
|
||||
this.coroutine_kind = Some(hir::CoroutineKind::AsyncGen(async_coroutine_source));
|
||||
this.coroutine_kind = Some(coroutine_kind);
|
||||
|
||||
let old_ctx = this.task_context;
|
||||
this.task_context = Some(task_context_hid);
|
||||
if task_context.is_some() {
|
||||
this.task_context = task_context;
|
||||
}
|
||||
let res = body(this);
|
||||
this.task_context = old_ctx;
|
||||
|
||||
(params, res)
|
||||
});
|
||||
|
||||
// `static |_task_context| -> <ret_ty> { body }`:
|
||||
// `static |<_task_context?>| -> <return_ty> { <body> }`:
|
||||
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_node_id),
|
||||
binder: hir::ClosureBinder::Default,
|
||||
@ -821,7 +680,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
body,
|
||||
fn_decl_span: self.lower_span(span),
|
||||
fn_arg_span: None,
|
||||
movability: Some(hir::Movability::Static),
|
||||
kind: hir::ClosureKind::Coroutine(coroutine_kind),
|
||||
constness: hir::Constness::NotConst,
|
||||
}))
|
||||
}
|
||||
@ -874,26 +733,42 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
/// }
|
||||
/// ```
|
||||
fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
|
||||
let expr = self.arena.alloc(self.lower_expr_mut(expr));
|
||||
self.make_lowered_await(await_kw_span, expr, FutureKind::Future)
|
||||
}
|
||||
|
||||
/// Takes an expr that has already been lowered and generates a desugared await loop around it
|
||||
fn make_lowered_await(
|
||||
&mut self,
|
||||
await_kw_span: Span,
|
||||
expr: &'hir hir::Expr<'hir>,
|
||||
await_kind: FutureKind,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let full_span = expr.span.to(await_kw_span);
|
||||
|
||||
let is_async_gen = match self.coroutine_kind {
|
||||
Some(hir::CoroutineKind::Async(_)) => false,
|
||||
Some(hir::CoroutineKind::AsyncGen(_)) => true,
|
||||
Some(hir::CoroutineKind::Coroutine) | Some(hir::CoroutineKind::Gen(_)) | None => {
|
||||
return hir::ExprKind::Err(self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks {
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => false,
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
|
||||
Some(hir::CoroutineKind::Coroutine(_))
|
||||
| Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _))
|
||||
| None => {
|
||||
return hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {
|
||||
await_kw_span,
|
||||
item_span: self.current_item,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, None);
|
||||
let features = match await_kind {
|
||||
FutureKind::Future => None,
|
||||
FutureKind::AsyncIterator => Some(self.allow_for_await.clone()),
|
||||
};
|
||||
let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features);
|
||||
let gen_future_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Await,
|
||||
full_span,
|
||||
Some(self.allow_gen_future.clone()),
|
||||
);
|
||||
let expr = self.lower_expr_mut(expr);
|
||||
let expr_hir_id = expr.hir_id;
|
||||
|
||||
// Note that the name of this binding must not be changed to something else because
|
||||
@ -934,11 +809,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir::LangItem::GetContext,
|
||||
arena_vec![self; task_context],
|
||||
);
|
||||
let call = self.expr_call_lang_item_fn(
|
||||
let call = match await_kind {
|
||||
FutureKind::Future => self.expr_call_lang_item_fn(
|
||||
span,
|
||||
hir::LangItem::FuturePoll,
|
||||
arena_vec![self; new_unchecked, get_context],
|
||||
);
|
||||
),
|
||||
FutureKind::AsyncIterator => self.expr_call_lang_item_fn(
|
||||
span,
|
||||
hir::LangItem::AsyncIteratorPollNext,
|
||||
arena_vec![self; new_unchecked, get_context],
|
||||
),
|
||||
};
|
||||
self.arena.alloc(self.expr_unsafe(call))
|
||||
};
|
||||
|
||||
@ -1020,11 +902,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let awaitee_arm = self.arm(awaitee_pat, loop_expr);
|
||||
|
||||
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
|
||||
let into_future_expr = self.expr_call_lang_item_fn(
|
||||
let into_future_expr = match await_kind {
|
||||
FutureKind::Future => self.expr_call_lang_item_fn(
|
||||
span,
|
||||
hir::LangItem::IntoFutureIntoFuture,
|
||||
arena_vec![self; expr],
|
||||
);
|
||||
arena_vec![self; *expr],
|
||||
),
|
||||
// Not needed for `for await` because we expect to have already called
|
||||
// `IntoAsyncIterator::into_async_iter` on it.
|
||||
FutureKind::AsyncIterator => expr,
|
||||
};
|
||||
|
||||
// match <into_future_expr> {
|
||||
// mut __awaitee => loop { .. }
|
||||
@ -1050,7 +937,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
let (body_id, coroutine_option) = self.with_new_scopes(fn_decl_span, move |this| {
|
||||
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
|
||||
let mut coroutine_kind = None;
|
||||
let body_id = this.lower_fn_body(decl, |this| {
|
||||
let e = this.lower_expr_mut(body);
|
||||
@ -1058,7 +945,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
e
|
||||
});
|
||||
let coroutine_option =
|
||||
this.coroutine_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
|
||||
this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
|
||||
(body_id, coroutine_option)
|
||||
});
|
||||
|
||||
@ -1075,39 +962,39 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
body: body_id,
|
||||
fn_decl_span: self.lower_span(fn_decl_span),
|
||||
fn_arg_span: Some(self.lower_span(fn_arg_span)),
|
||||
movability: coroutine_option,
|
||||
kind: closure_kind,
|
||||
constness: self.lower_constness(constness),
|
||||
});
|
||||
|
||||
hir::ExprKind::Closure(c)
|
||||
}
|
||||
|
||||
fn coroutine_movability_for_fn(
|
||||
fn closure_movability_for_fn(
|
||||
&mut self,
|
||||
decl: &FnDecl,
|
||||
fn_decl_span: Span,
|
||||
coroutine_kind: Option<hir::CoroutineKind>,
|
||||
movability: Movability,
|
||||
) -> Option<hir::Movability> {
|
||||
) -> hir::ClosureKind {
|
||||
match coroutine_kind {
|
||||
Some(hir::CoroutineKind::Coroutine) => {
|
||||
Some(hir::CoroutineKind::Coroutine(_)) => {
|
||||
if decl.inputs.len() > 1 {
|
||||
self.tcx.sess.emit_err(CoroutineTooManyParameters { fn_decl_span });
|
||||
self.dcx().emit_err(CoroutineTooManyParameters { fn_decl_span });
|
||||
}
|
||||
Some(movability)
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(movability))
|
||||
}
|
||||
Some(
|
||||
hir::CoroutineKind::Gen(_)
|
||||
| hir::CoroutineKind::Async(_)
|
||||
| hir::CoroutineKind::AsyncGen(_),
|
||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
|
||||
| hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)
|
||||
| hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _),
|
||||
) => {
|
||||
panic!("non-`async`/`gen` closure body turned `async`/`gen` during lowering");
|
||||
}
|
||||
None => {
|
||||
if movability == Movability::Static {
|
||||
self.tcx.sess.emit_err(ClosureCannotBeStatic { fn_decl_span });
|
||||
self.dcx().emit_err(ClosureCannotBeStatic { fn_decl_span });
|
||||
}
|
||||
None
|
||||
hir::ClosureKind::Closure
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1139,28 +1026,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
fn_decl_span: Span,
|
||||
fn_arg_span: Span,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let CoroutineKind::Async { closure_id: inner_closure_id, .. } = coroutine_kind else {
|
||||
span_bug!(fn_decl_span, "`async gen` and `gen` closures are not supported, yet");
|
||||
};
|
||||
|
||||
if let &ClosureBinder::For { span, .. } = binder {
|
||||
self.tcx.sess.emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
|
||||
self.dcx().emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
|
||||
}
|
||||
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
let outer_decl =
|
||||
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
|
||||
|
||||
let body = self.with_new_scopes(fn_decl_span, |this| {
|
||||
// FIXME(cramertj): allow `async` non-`move` closures with arguments.
|
||||
if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
|
||||
this.tcx.sess.emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span });
|
||||
}
|
||||
|
||||
// Transform `async |x: u8| -> X { ... }` into
|
||||
// `|x: u8| || -> X { ... }`.
|
||||
let body_id = this.lower_fn_body(&outer_decl, |this| {
|
||||
let body_id = this.lower_body(|this| {
|
||||
let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output {
|
||||
let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock);
|
||||
Some(hir::FnRetTy::Return(this.lower_ty(ty, &itctx)))
|
||||
@ -1168,21 +1043,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
None
|
||||
};
|
||||
|
||||
let async_body = this.make_async_expr(
|
||||
capture_clause,
|
||||
inner_closure_id,
|
||||
async_ret_ty,
|
||||
body.span,
|
||||
hir::CoroutineSource::Closure,
|
||||
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
|
||||
decl,
|
||||
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
|
||||
body.span,
|
||||
coroutine_kind,
|
||||
hir::CoroutineSource::Closure,
|
||||
async_ret_ty,
|
||||
);
|
||||
let hir_id = this.lower_node_id(inner_closure_id);
|
||||
|
||||
let hir_id = this.lower_node_id(coroutine_kind.closure_id());
|
||||
this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
|
||||
hir::Expr { hir_id, kind: async_body, span: this.lower_span(body.span) }
|
||||
|
||||
(parameters, expr)
|
||||
});
|
||||
body_id
|
||||
});
|
||||
|
||||
let outer_decl =
|
||||
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
|
||||
|
||||
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
|
||||
// We need to lower the declaration outside the new scope, because we
|
||||
// have to conserve the state of being inside a loop condition for the
|
||||
@ -1199,7 +1079,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
body,
|
||||
fn_decl_span: self.lower_span(fn_decl_span),
|
||||
fn_arg_span: Some(self.lower_span(fn_arg_span)),
|
||||
movability: None,
|
||||
kind: hir::ClosureKind::Closure,
|
||||
constness: hir::Constness::NotConst,
|
||||
});
|
||||
hir::ExprKind::Closure(c)
|
||||
@ -1411,7 +1291,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
);
|
||||
let fields_omitted = match &se.rest {
|
||||
StructRest::Base(e) => {
|
||||
self.tcx.sess.emit_err(FunctionalRecordUpdateDestructuringAssignment {
|
||||
self.dcx().emit_err(FunctionalRecordUpdateDestructuringAssignment {
|
||||
span: e.span,
|
||||
});
|
||||
true
|
||||
@ -1507,7 +1387,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
(None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
|
||||
(Some(..), Some(..), Closed) => unreachable!(),
|
||||
(start, None, Closed) => {
|
||||
self.tcx.sess.emit_err(InclusiveRangeWithNoEnd { span });
|
||||
self.dcx().emit_err(InclusiveRangeWithNoEnd { span });
|
||||
match start {
|
||||
Some(..) => hir::LangItem::RangeFrom,
|
||||
None => hir::LangItem::RangeFull,
|
||||
@ -1612,24 +1492,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
|
||||
let is_async_gen = match self.coroutine_kind {
|
||||
Some(hir::CoroutineKind::Gen(_)) => false,
|
||||
Some(hir::CoroutineKind::AsyncGen(_)) => true,
|
||||
Some(hir::CoroutineKind::Async(_)) => {
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => false,
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
|
||||
return hir::ExprKind::Err(
|
||||
self.tcx.sess.emit_err(AsyncCoroutinesNotSupported { span }),
|
||||
self.dcx().emit_err(AsyncCoroutinesNotSupported { span }),
|
||||
);
|
||||
}
|
||||
Some(hir::CoroutineKind::Coroutine) | None => {
|
||||
Some(hir::CoroutineKind::Coroutine(_)) => {
|
||||
if !self.tcx.features().coroutines {
|
||||
rustc_session::parse::feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
&self.tcx.sess,
|
||||
sym::coroutines,
|
||||
span,
|
||||
"yield syntax is experimental",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
self.coroutine_kind = Some(hir::CoroutineKind::Coroutine);
|
||||
false
|
||||
}
|
||||
None => {
|
||||
if !self.tcx.features().coroutines {
|
||||
rustc_session::parse::feature_err(
|
||||
&self.tcx.sess,
|
||||
sym::coroutines,
|
||||
span,
|
||||
"yield syntax is experimental",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable));
|
||||
false
|
||||
}
|
||||
};
|
||||
@ -1685,6 +1577,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
head: &Expr,
|
||||
body: &Block,
|
||||
opt_label: Option<Label>,
|
||||
loop_kind: ForLoopKind,
|
||||
) -> hir::Expr<'hir> {
|
||||
let head = self.lower_expr_mut(head);
|
||||
let pat = self.lower_pat(pat);
|
||||
@ -1713,17 +1606,41 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (iter_pat, iter_pat_nid) =
|
||||
self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::MUT);
|
||||
|
||||
// `match Iterator::next(&mut iter) { ... }`
|
||||
let match_expr = {
|
||||
let iter = self.expr_ident(head_span, iter, iter_pat_nid);
|
||||
let next_expr = match loop_kind {
|
||||
ForLoopKind::For => {
|
||||
// `Iterator::next(&mut iter)`
|
||||
let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
|
||||
let next_expr = self.expr_call_lang_item_fn(
|
||||
self.expr_call_lang_item_fn(
|
||||
head_span,
|
||||
hir::LangItem::IteratorNext,
|
||||
arena_vec![self; ref_mut_iter],
|
||||
);
|
||||
)
|
||||
}
|
||||
ForLoopKind::ForAwait => {
|
||||
// we'll generate `unsafe { Pin::new_unchecked(&mut iter) })` and then pass this
|
||||
// to make_lowered_await with `FutureKind::AsyncIterator` which will generator
|
||||
// calls to `poll_next`. In user code, this would probably be a call to
|
||||
// `Pin::as_mut` but here it's easy enough to do `new_unchecked`.
|
||||
|
||||
// `&mut iter`
|
||||
let iter = self.expr_mut_addr_of(head_span, iter);
|
||||
// `Pin::new_unchecked(...)`
|
||||
let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(
|
||||
head_span,
|
||||
hir::LangItem::PinNewUnchecked,
|
||||
arena_vec![self; iter],
|
||||
));
|
||||
// `unsafe { ... }`
|
||||
let iter = self.arena.alloc(self.expr_unsafe(iter));
|
||||
let kind = self.make_lowered_await(head_span, iter, FutureKind::AsyncIterator);
|
||||
self.arena.alloc(hir::Expr { hir_id: self.next_id(), kind, span: head_span })
|
||||
}
|
||||
};
|
||||
let arms = arena_vec![self; none_arm, some_arm];
|
||||
|
||||
// `match $next_expr { ... }`
|
||||
self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
|
||||
};
|
||||
let match_stmt = self.stmt_expr(for_span, match_expr);
|
||||
@ -1743,13 +1660,34 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// `mut iter => { ... }`
|
||||
let iter_arm = self.arm(iter_pat, loop_expr);
|
||||
|
||||
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
|
||||
let into_iter_expr = {
|
||||
let into_iter_expr = match loop_kind {
|
||||
ForLoopKind::For => {
|
||||
// `::std::iter::IntoIterator::into_iter(<head>)`
|
||||
self.expr_call_lang_item_fn(
|
||||
head_span,
|
||||
hir::LangItem::IntoIterIntoIter,
|
||||
arena_vec![self; head],
|
||||
)
|
||||
}
|
||||
// ` unsafe { Pin::new_unchecked(&mut into_async_iter(<head>)) }`
|
||||
ForLoopKind::ForAwait => {
|
||||
// `::core::async_iter::IntoAsyncIterator::into_async_iter(<head>)`
|
||||
let iter = self.expr_call_lang_item_fn(
|
||||
head_span,
|
||||
hir::LangItem::IntoAsyncIterIntoIter,
|
||||
arena_vec![self; head],
|
||||
);
|
||||
let iter = self.expr_mut_addr_of(head_span, iter);
|
||||
// `Pin::new_unchecked(...)`
|
||||
let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(
|
||||
head_span,
|
||||
hir::LangItem::PinNewUnchecked,
|
||||
arena_vec![self; iter],
|
||||
));
|
||||
// `unsafe { ... }`
|
||||
let iter = self.arena.alloc(self.expr_unsafe(iter));
|
||||
iter
|
||||
}
|
||||
};
|
||||
|
||||
let match_expr = self.arena.alloc(self.expr_match(
|
||||
@ -1960,7 +1898,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> {
|
||||
let lit = self.arena.alloc(hir::Lit {
|
||||
span: sp,
|
||||
node: ast::LitKind::Int(value as u128, ast::LitIntType::Unsigned(ast::UintTy::Usize)),
|
||||
node: ast::LitKind::Int(
|
||||
(value as u128).into(),
|
||||
ast::LitIntType::Unsigned(ast::UintTy::Usize),
|
||||
),
|
||||
});
|
||||
self.expr(sp, hir::ExprKind::Lit(lit))
|
||||
}
|
||||
@ -1968,7 +1909,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> {
|
||||
let lit = self.arena.alloc(hir::Lit {
|
||||
span: sp,
|
||||
node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ast::UintTy::U32)),
|
||||
node: ast::LitKind::Int(
|
||||
u128::from(value).into(),
|
||||
ast::LitIntType::Unsigned(ast::UintTy::U32),
|
||||
),
|
||||
});
|
||||
self.expr(sp, hir::ExprKind::Lit(lit))
|
||||
}
|
||||
@ -2033,11 +1977,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
lang_item: hir::LangItem,
|
||||
name: Symbol,
|
||||
) -> hir::Expr<'hir> {
|
||||
let qpath = self.make_lang_item_qpath(lang_item, self.lower_span(span));
|
||||
let path = hir::ExprKind::Path(hir::QPath::TypeRelative(
|
||||
self.arena.alloc(self.ty(
|
||||
span,
|
||||
hir::TyKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span))),
|
||||
)),
|
||||
self.arena.alloc(self.ty(span, hir::TyKind::Path(qpath))),
|
||||
self.arena.alloc(hir::PathSegment::new(
|
||||
Ident::new(name, span),
|
||||
self.next_id(),
|
||||
@ -2152,3 +2094,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by [`LoweringContext::make_lowered_await`] to customize the desugaring based on what kind
|
||||
/// of future we are awaiting.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
enum FutureKind {
|
||||
/// We are awaiting a normal future
|
||||
Future,
|
||||
/// We are awaiting something that's known to be an AsyncIterator (i.e. we are in the header of
|
||||
/// a `for await` loop)
|
||||
AsyncIterator,
|
||||
}
|
||||
|
||||
@ -267,7 +267,7 @@ fn make_count<'hir>(
|
||||
ctx.expr(
|
||||
sp,
|
||||
hir::ExprKind::Err(
|
||||
ctx.tcx.sess.span_delayed_bug(sp, "lowered bad format_args count"),
|
||||
ctx.dcx().span_delayed_bug(sp, "lowered bad format_args count"),
|
||||
),
|
||||
)
|
||||
}
|
||||
@ -306,7 +306,7 @@ fn make_format_spec<'hir>(
|
||||
}
|
||||
Err(_) => ctx.expr(
|
||||
sp,
|
||||
hir::ExprKind::Err(ctx.tcx.sess.span_delayed_bug(sp, "lowered bad format_args count")),
|
||||
hir::ExprKind::Err(ctx.dcx().span_delayed_bug(sp, "lowered bad format_args count")),
|
||||
),
|
||||
};
|
||||
let &FormatOptions {
|
||||
|
||||
@ -12,6 +12,7 @@ use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_hir::PredicateOrigin;
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
@ -182,7 +183,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs)
|
||||
}
|
||||
ItemKind::Static(box ast::StaticItem { ty: t, mutability: m, expr: e }) => {
|
||||
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
|
||||
let (ty, body_id) =
|
||||
self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy);
|
||||
hir::ItemKind::Static(ty, *m, body_id)
|
||||
}
|
||||
ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
|
||||
@ -191,7 +193,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
Const::No,
|
||||
id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_const_item(ty, span, expr.as_deref()),
|
||||
|this| {
|
||||
this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy)
|
||||
},
|
||||
);
|
||||
hir::ItemKind::Const(ty, generics, body_id)
|
||||
}
|
||||
@ -265,7 +269,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| match ty {
|
||||
None => {
|
||||
let guar = this.tcx.sess.span_delayed_bug(
|
||||
let guar = this.dcx().span_delayed_bug(
|
||||
span,
|
||||
"expected to lower type alias type, but it was missing",
|
||||
);
|
||||
@ -339,9 +343,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, (trait_ref, lowered_ty)) =
|
||||
self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
|
||||
let constness = match *constness {
|
||||
Const::Yes(span) => BoundConstness::Maybe(span),
|
||||
Const::No => BoundConstness::Never,
|
||||
};
|
||||
|
||||
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
|
||||
this.lower_trait_ref(
|
||||
*constness,
|
||||
constness,
|
||||
trait_ref,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
|
||||
)
|
||||
@ -432,6 +441,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules });
|
||||
hir::ItemKind::Macro(macro_def, macro_kind)
|
||||
}
|
||||
ItemKind::Delegation(box delegation) => {
|
||||
let delegation_results = self.lower_delegation(delegation, id);
|
||||
hir::ItemKind::Fn(
|
||||
delegation_results.sig,
|
||||
delegation_results.generics,
|
||||
delegation_results.body_id,
|
||||
)
|
||||
}
|
||||
ItemKind::MacCall(..) => {
|
||||
panic!("`TyMac` should have been expanded by now")
|
||||
}
|
||||
@ -443,8 +460,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
ty: &Ty,
|
||||
span: Span,
|
||||
body: Option<&Expr>,
|
||||
impl_trait_position: ImplTraitPosition,
|
||||
) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
|
||||
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(impl_trait_position));
|
||||
(ty, self.lower_const_body(span, body))
|
||||
}
|
||||
|
||||
@ -567,24 +585,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// This is used to track which lifetimes have already been defined,
|
||||
// and which need to be replicated when lowering an async fn.
|
||||
|
||||
match parent_hir.node().expect_item().kind {
|
||||
let generics = match parent_hir.node().expect_item().kind {
|
||||
hir::ItemKind::Impl(impl_) => {
|
||||
self.is_in_trait_impl = impl_.of_trait.is_some();
|
||||
&impl_.generics
|
||||
}
|
||||
hir::ItemKind::Trait(_, _, generics, _, _) if self.tcx.features().effects => {
|
||||
hir::ItemKind::Trait(_, _, generics, _, _) => generics,
|
||||
kind => {
|
||||
span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr())
|
||||
}
|
||||
};
|
||||
|
||||
if self.tcx.features().effects {
|
||||
self.host_param_id = generics
|
||||
.params
|
||||
.iter()
|
||||
.find(|param| {
|
||||
matches!(
|
||||
param.kind,
|
||||
hir::GenericParamKind::Const { is_host_effect: true, .. }
|
||||
)
|
||||
matches!(param.kind, hir::GenericParamKind::Const { is_host_effect: true, .. })
|
||||
})
|
||||
.map(|param| param.def_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match ctxt {
|
||||
AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item)),
|
||||
@ -793,6 +813,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
);
|
||||
(generics, kind, ty.is_some())
|
||||
}
|
||||
AssocItemKind::Delegation(box delegation) => {
|
||||
let delegation_results = self.lower_delegation(delegation, i.id);
|
||||
let item_kind = hir::TraitItemKind::Fn(
|
||||
delegation_results.sig,
|
||||
hir::TraitFn::Provided(delegation_results.body_id),
|
||||
);
|
||||
(delegation_results.generics, item_kind, true)
|
||||
}
|
||||
AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
|
||||
};
|
||||
|
||||
@ -814,6 +842,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
AssocItemKind::Fn(box Fn { sig, .. }) => {
|
||||
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
|
||||
}
|
||||
AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
|
||||
has_self: self.delegation_has_self(i.id, delegation.id, i.span),
|
||||
},
|
||||
AssocItemKind::MacCall(..) => unimplemented!(),
|
||||
};
|
||||
let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
|
||||
@ -879,7 +910,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| match ty {
|
||||
None => {
|
||||
let guar = this.tcx.sess.span_delayed_bug(
|
||||
let guar = this.dcx().span_delayed_bug(
|
||||
i.span,
|
||||
"expected to lower associated type, but it was missing",
|
||||
);
|
||||
@ -896,6 +927,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
},
|
||||
)
|
||||
}
|
||||
AssocItemKind::Delegation(box delegation) => {
|
||||
let delegation_results = self.lower_delegation(delegation, i.id);
|
||||
(
|
||||
delegation_results.generics,
|
||||
hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id),
|
||||
)
|
||||
}
|
||||
AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
|
||||
};
|
||||
|
||||
@ -912,6 +950,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
|
||||
fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
|
||||
let trait_item_def_id = self
|
||||
.resolver
|
||||
.get_partial_res(i.id)
|
||||
.map(|r| r.expect_full_res().opt_def_id())
|
||||
.unwrap_or(None);
|
||||
self.is_in_trait_impl = trait_item_def_id.is_some();
|
||||
|
||||
hir::ImplItemRef {
|
||||
id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
|
||||
ident: self.lower_ident(i.ident),
|
||||
@ -922,12 +967,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
AssocItemKind::Fn(box Fn { sig, .. }) => {
|
||||
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
|
||||
}
|
||||
AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
|
||||
has_self: self.delegation_has_self(i.id, delegation.id, i.span),
|
||||
},
|
||||
AssocItemKind::MacCall(..) => unimplemented!(),
|
||||
},
|
||||
trait_item_def_id: self
|
||||
.resolver
|
||||
.get_partial_res(i.id)
|
||||
.map(|r| r.expect_full_res().def_id()),
|
||||
trait_item_def_id,
|
||||
}
|
||||
}
|
||||
|
||||
@ -952,11 +997,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
params: &'hir [hir::Param<'hir>],
|
||||
value: hir::Expr<'hir>,
|
||||
) -> hir::BodyId {
|
||||
let body = hir::Body {
|
||||
coroutine_kind: self.coroutine_kind,
|
||||
params,
|
||||
value: self.arena.alloc(value),
|
||||
};
|
||||
let body = hir::Body { params, value: self.arena.alloc(value) };
|
||||
let id = body.id();
|
||||
debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
|
||||
self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
|
||||
@ -1012,7 +1053,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr<'hir> {
|
||||
match block {
|
||||
Some(block) => self.lower_block_expr(block),
|
||||
None => self.expr_err(span, self.tcx.sess.span_delayed_bug(span, "no block")),
|
||||
None => self.expr_err(span, self.dcx().span_delayed_bug(span, "no block")),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1022,7 +1063,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&[],
|
||||
match expr {
|
||||
Some(expr) => this.lower_expr_mut(expr),
|
||||
None => this.expr_err(span, this.tcx.sess.span_delayed_bug(span, "no block")),
|
||||
None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")),
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -1041,9 +1082,37 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (Some(coroutine_kind), Some(body)) = (coroutine_kind, body) else {
|
||||
return self.lower_fn_body_block(span, decl, body);
|
||||
};
|
||||
let closure_id = coroutine_kind.closure_id();
|
||||
|
||||
self.lower_body(|this| {
|
||||
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
|
||||
decl,
|
||||
|this| this.lower_block_expr(body),
|
||||
body.span,
|
||||
coroutine_kind,
|
||||
hir::CoroutineSource::Fn,
|
||||
None,
|
||||
);
|
||||
|
||||
// FIXME(async_fn_track_caller): Can this be moved above?
|
||||
let hir_id = this.lower_node_id(coroutine_kind.closure_id());
|
||||
this.maybe_forward_track_caller(body.span, fn_id, hir_id);
|
||||
|
||||
(parameters, expr)
|
||||
})
|
||||
}
|
||||
|
||||
/// Lowers a desugared coroutine body after moving all of the arguments
|
||||
/// into the body. This is to make sure that the future actually owns the
|
||||
/// arguments that are passed to the function, and to ensure things like
|
||||
/// drop order are stable.
|
||||
pub fn lower_coroutine_body_with_moved_arguments(
|
||||
&mut self,
|
||||
decl: &FnDecl,
|
||||
lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>,
|
||||
body_span: Span,
|
||||
coroutine_kind: CoroutineKind,
|
||||
coroutine_source: hir::CoroutineSource,
|
||||
return_type_hint: Option<hir::FnRetTy<'hir>>,
|
||||
) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) {
|
||||
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
|
||||
let mut statements: Vec<hir::Stmt<'_>> = Vec::new();
|
||||
|
||||
@ -1080,7 +1149,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// (and its tail expression!) before we drop the
|
||||
// parameters (c.f. rust-lang/rust#64512).
|
||||
for (index, parameter) in decl.inputs.iter().enumerate() {
|
||||
let parameter = this.lower_param(parameter);
|
||||
let parameter = self.lower_param(parameter);
|
||||
let span = parameter.pat.span;
|
||||
|
||||
// Check if this is a binding pattern, if so, we can optimize and avoid adding a
|
||||
@ -1105,28 +1174,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
};
|
||||
|
||||
let desugared_span = this.mark_span_with_reason(DesugaringKind::Async, span, None);
|
||||
let desugared_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
|
||||
|
||||
// Construct a parameter representing `__argN: <ty>` to replace the parameter of the
|
||||
// async function.
|
||||
//
|
||||
// If this is the simple case, this parameter will end up being the same as the
|
||||
// original parameter, but with a different pattern id.
|
||||
let stmt_attrs = this.attrs.get(¶meter.hir_id.local_id).copied();
|
||||
let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident);
|
||||
let stmt_attrs = self.attrs.get(¶meter.hir_id.local_id).copied();
|
||||
let (new_parameter_pat, new_parameter_id) = self.pat_ident(desugared_span, ident);
|
||||
let new_parameter = hir::Param {
|
||||
hir_id: parameter.hir_id,
|
||||
pat: new_parameter_pat,
|
||||
ty_span: this.lower_span(parameter.ty_span),
|
||||
span: this.lower_span(parameter.span),
|
||||
ty_span: self.lower_span(parameter.ty_span),
|
||||
span: self.lower_span(parameter.span),
|
||||
};
|
||||
|
||||
if is_simple_parameter {
|
||||
// If this is the simple case, then we only insert one statement that is
|
||||
// `let <pat> = <pat>;`. We re-use the original argument's pattern so that
|
||||
// `HirId`s are densely assigned.
|
||||
let expr = this.expr_ident(desugared_span, ident, new_parameter_id);
|
||||
let stmt = this.stmt_let_pat(
|
||||
let expr = self.expr_ident(desugared_span, ident, new_parameter_id);
|
||||
let stmt = self.stmt_let_pat(
|
||||
stmt_attrs,
|
||||
desugared_span,
|
||||
Some(expr),
|
||||
@ -1150,13 +1219,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// Construct the `let mut __argN = __argN;` statement. It must be a mut binding
|
||||
// because the user may have specified a `ref mut` binding in the next
|
||||
// statement.
|
||||
let (move_pat, move_id) = this.pat_ident_binding_mode(
|
||||
desugared_span,
|
||||
ident,
|
||||
hir::BindingAnnotation::MUT,
|
||||
);
|
||||
let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id);
|
||||
let move_stmt = this.stmt_let_pat(
|
||||
let (move_pat, move_id) =
|
||||
self.pat_ident_binding_mode(desugared_span, ident, hir::BindingAnnotation::MUT);
|
||||
let move_expr = self.expr_ident(desugared_span, ident, new_parameter_id);
|
||||
let move_stmt = self.stmt_let_pat(
|
||||
None,
|
||||
desugared_span,
|
||||
Some(move_expr),
|
||||
@ -1166,8 +1232,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
// Construct the `let <pat> = __argN;` statement. We re-use the original
|
||||
// parameter's pattern so that `HirId`s are densely assigned.
|
||||
let pattern_expr = this.expr_ident(desugared_span, ident, move_id);
|
||||
let pattern_stmt = this.stmt_let_pat(
|
||||
let pattern_expr = self.expr_ident(desugared_span, ident, move_id);
|
||||
let pattern_stmt = self.stmt_let_pat(
|
||||
stmt_attrs,
|
||||
desugared_span,
|
||||
Some(pattern_expr),
|
||||
@ -1184,7 +1250,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
|
||||
// Create a block from the user's function body:
|
||||
let user_body = this.lower_block_expr(body);
|
||||
let user_body = lower_body(this);
|
||||
|
||||
// Transform into `drop-temps { <user-body> }`, an expression:
|
||||
let desugared_span =
|
||||
@ -1208,40 +1274,32 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
this.expr_block(body)
|
||||
};
|
||||
// FIXME(gen_blocks): Consider unifying the `make_*_expr` functions.
|
||||
let coroutine_expr = match coroutine_kind {
|
||||
CoroutineKind::Async { .. } => this.make_async_expr(
|
||||
let desugaring_kind = match coroutine_kind {
|
||||
CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,
|
||||
CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,
|
||||
CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen,
|
||||
};
|
||||
let closure_id = coroutine_kind.closure_id();
|
||||
let coroutine_expr = self.make_desugared_coroutine_expr(
|
||||
// FIXME(async_closures): This should only move locals,
|
||||
// and not upvars. Capturing closure upvars by ref doesn't
|
||||
// work right now anyways, so whatever.
|
||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||
closure_id,
|
||||
None,
|
||||
body.span,
|
||||
hir::CoroutineSource::Fn,
|
||||
return_type_hint,
|
||||
body_span,
|
||||
desugaring_kind,
|
||||
coroutine_source,
|
||||
mkbody,
|
||||
),
|
||||
CoroutineKind::Gen { .. } => this.make_gen_expr(
|
||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||
closure_id,
|
||||
None,
|
||||
body.span,
|
||||
hir::CoroutineSource::Fn,
|
||||
mkbody,
|
||||
),
|
||||
CoroutineKind::AsyncGen { .. } => this.make_async_gen_expr(
|
||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||
closure_id,
|
||||
None,
|
||||
body.span,
|
||||
hir::CoroutineSource::Fn,
|
||||
mkbody,
|
||||
),
|
||||
);
|
||||
|
||||
let expr = hir::Expr {
|
||||
hir_id: self.lower_node_id(closure_id),
|
||||
kind: coroutine_expr,
|
||||
span: self.lower_span(body_span),
|
||||
};
|
||||
|
||||
let hir_id = this.lower_node_id(closure_id);
|
||||
this.maybe_forward_track_caller(body.span, fn_id, hir_id);
|
||||
let expr = hir::Expr { hir_id, kind: coroutine_expr, span: this.lower_span(body.span) };
|
||||
|
||||
(this.arena.alloc_from_iter(parameters), expr)
|
||||
})
|
||||
(self.arena.alloc_from_iter(parameters), expr)
|
||||
}
|
||||
|
||||
fn lower_method_sig(
|
||||
@ -1253,9 +1311,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
coroutine_kind: Option<CoroutineKind>,
|
||||
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
|
||||
let header = self.lower_fn_header(sig.header);
|
||||
// Don't pass along the user-provided constness of trait associated functions; we don't want to
|
||||
// synthesize a host effect param for them. We reject `const` on them during AST validation.
|
||||
let constness = if kind == FnDeclKind::Inherent { sig.header.constness } else { Const::No };
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) =
|
||||
self.lower_generics(generics, sig.header.constness, id, &itctx, |this| {
|
||||
let (generics, decl) = self.lower_generics(generics, constness, id, &itctx, |this| {
|
||||
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
|
||||
});
|
||||
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
|
||||
@ -1296,7 +1356,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
.map(|s| Symbol::intern(s))
|
||||
.collect::<Vec<_>>();
|
||||
let suggested_name = find_best_match_for_name(&abi_names, abi.symbol_unescaped, None);
|
||||
self.tcx.sess.emit_err(InvalidAbi {
|
||||
self.dcx().emit_err(InvalidAbi {
|
||||
abi: abi.symbol_unescaped,
|
||||
span: abi.span,
|
||||
explain: match err {
|
||||
@ -1372,12 +1432,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// need to compute this at all unless there is a Maybe bound.
|
||||
let mut is_param: Option<bool> = None;
|
||||
for bound in &bound_pred.bounds {
|
||||
if !matches!(*bound, GenericBound::Trait(_, TraitBoundModifier::Maybe)) {
|
||||
if !matches!(
|
||||
*bound,
|
||||
GenericBound::Trait(
|
||||
_,
|
||||
TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. }
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
let is_param = *is_param.get_or_insert_with(compute_is_param);
|
||||
if !is_param {
|
||||
self.tcx.sess.emit_err(MisplacedRelaxTraitBound { span: bound.span() });
|
||||
self.dcx().emit_err(MisplacedRelaxTraitBound { span: bound.span() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +35,6 @@
|
||||
#![doc(rust_logo)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(let_chains)]
|
||||
#![recursion_limit = "256"]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
@ -53,7 +52,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{DiagnosticArgFromDisplay, StashKey};
|
||||
use rustc_errors::{DiagCtxt, DiagnosticArgFromDisplay, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
|
||||
@ -76,6 +75,7 @@ macro_rules! arena_vec {
|
||||
|
||||
mod asm;
|
||||
mod block;
|
||||
mod delegation;
|
||||
mod errors;
|
||||
mod expr;
|
||||
mod format;
|
||||
@ -130,6 +130,7 @@ struct LoweringContext<'a, 'hir> {
|
||||
allow_try_trait: Lrc<[Symbol]>,
|
||||
allow_gen_future: Lrc<[Symbol]>,
|
||||
allow_async_iterator: Lrc<[Symbol]>,
|
||||
allow_for_await: Lrc<[Symbol]>,
|
||||
|
||||
/// Mapping from generics `def_id`s to TAIT generics `def_id`s.
|
||||
/// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
|
||||
@ -174,6 +175,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
} else {
|
||||
[sym::gen_future].into()
|
||||
},
|
||||
allow_for_await: [sym::async_iterator].into(),
|
||||
// FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller`
|
||||
// interact with `gen`/`async gen` blocks
|
||||
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
|
||||
@ -181,6 +183,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
host_param_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn dcx(&self) -> &'hir DiagCtxt {
|
||||
self.tcx.dcx()
|
||||
}
|
||||
}
|
||||
|
||||
trait ResolverAstLoweringExt {
|
||||
@ -297,8 +303,6 @@ enum ImplTraitPosition {
|
||||
ClosureParam,
|
||||
PointerParam,
|
||||
FnTraitParam,
|
||||
TraitParam,
|
||||
ImplParam,
|
||||
ExternFnReturn,
|
||||
ClosureReturn,
|
||||
PointerReturn,
|
||||
@ -317,29 +321,27 @@ impl std::fmt::Display for ImplTraitPosition {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let name = match self {
|
||||
ImplTraitPosition::Path => "paths",
|
||||
ImplTraitPosition::Variable => "variable bindings",
|
||||
ImplTraitPosition::Variable => "the type of variable bindings",
|
||||
ImplTraitPosition::Trait => "traits",
|
||||
ImplTraitPosition::AsyncBlock => "async blocks",
|
||||
ImplTraitPosition::Bound => "bounds",
|
||||
ImplTraitPosition::Generic => "generics",
|
||||
ImplTraitPosition::ExternFnParam => "`extern fn` params",
|
||||
ImplTraitPosition::ClosureParam => "closure params",
|
||||
ImplTraitPosition::PointerParam => "`fn` pointer params",
|
||||
ImplTraitPosition::FnTraitParam => "`Fn` trait params",
|
||||
ImplTraitPosition::TraitParam => "trait method params",
|
||||
ImplTraitPosition::ImplParam => "`impl` method params",
|
||||
ImplTraitPosition::ExternFnParam => "`extern fn` parameters",
|
||||
ImplTraitPosition::ClosureParam => "closure parameters",
|
||||
ImplTraitPosition::PointerParam => "`fn` pointer parameters",
|
||||
ImplTraitPosition::FnTraitParam => "the parameters of `Fn` trait bounds",
|
||||
ImplTraitPosition::ExternFnReturn => "`extern fn` return types",
|
||||
ImplTraitPosition::ClosureReturn => "closure return types",
|
||||
ImplTraitPosition::PointerReturn => "`fn` pointer return types",
|
||||
ImplTraitPosition::FnTraitReturn => "`Fn` trait return types",
|
||||
ImplTraitPosition::FnTraitReturn => "the return type of `Fn` trait bounds",
|
||||
ImplTraitPosition::GenericDefault => "generic parameter defaults",
|
||||
ImplTraitPosition::ConstTy => "const types",
|
||||
ImplTraitPosition::StaticTy => "static types",
|
||||
ImplTraitPosition::AssocTy => "associated types",
|
||||
ImplTraitPosition::FieldTy => "field types",
|
||||
ImplTraitPosition::Cast => "cast types",
|
||||
ImplTraitPosition::Cast => "cast expression types",
|
||||
ImplTraitPosition::ImplSelf => "impl headers",
|
||||
ImplTraitPosition::OffsetOf => "`offset_of!` params",
|
||||
ImplTraitPosition::OffsetOf => "`offset_of!` parameters",
|
||||
};
|
||||
|
||||
write!(f, "{name}")
|
||||
@ -357,19 +359,6 @@ enum FnDeclKind {
|
||||
Impl,
|
||||
}
|
||||
|
||||
impl FnDeclKind {
|
||||
fn param_impl_trait_allowed(&self) -> bool {
|
||||
matches!(self, FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait)
|
||||
}
|
||||
|
||||
fn return_impl_trait_allowed(&self) -> bool {
|
||||
match self {
|
||||
FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum AstOwner<'a> {
|
||||
NonOwner,
|
||||
@ -671,9 +660,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let (opt_hash_including_bodies, attrs_hash) = if self.tcx.needs_crate_hash() {
|
||||
self.tcx.with_stable_hashing_context(|mut hcx| {
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
hcx.with_hir_bodies(node.def_id(), &bodies, |hcx| {
|
||||
node.hash_stable(hcx, &mut stable_hasher)
|
||||
});
|
||||
node.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
// Bodies are stored out of line, so we need to pull them explicitly in the hash.
|
||||
bodies.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
let h1 = stable_hasher.finish();
|
||||
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
@ -764,6 +753,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
self.resolver.get_import_res(id).present_items()
|
||||
}
|
||||
|
||||
fn make_lang_item_qpath(&mut self, lang_item: hir::LangItem, span: Span) -> hir::QPath<'hir> {
|
||||
hir::QPath::Resolved(None, self.make_lang_item_path(lang_item, span, None))
|
||||
}
|
||||
|
||||
fn make_lang_item_path(
|
||||
&mut self,
|
||||
lang_item: hir::LangItem,
|
||||
@ -781,7 +774,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
hir_id: self.next_id(),
|
||||
res,
|
||||
args,
|
||||
infer_args: false,
|
||||
infer_args: args.is_none(),
|
||||
}]),
|
||||
})
|
||||
}
|
||||
@ -1033,11 +1026,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
&& first_char.is_ascii_lowercase()
|
||||
{
|
||||
let mut err = if !data.inputs.is_empty() {
|
||||
self.tcx.sess.create_err(errors::BadReturnTypeNotation::Inputs {
|
||||
self.dcx().create_err(errors::BadReturnTypeNotation::Inputs {
|
||||
span: data.inputs_span,
|
||||
})
|
||||
} else if let FnRetTy::Ty(ty) = &data.output {
|
||||
self.tcx.sess.create_err(errors::BadReturnTypeNotation::Output {
|
||||
self.dcx().create_err(errors::BadReturnTypeNotation::Output {
|
||||
span: data.inputs_span.shrink_to_hi().to(ty.span),
|
||||
})
|
||||
} else {
|
||||
@ -1048,7 +1041,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
{
|
||||
add_feature_diagnostics(
|
||||
&mut err,
|
||||
&self.tcx.sess.parse_sess,
|
||||
&self.tcx.sess,
|
||||
sym::return_type_notation,
|
||||
);
|
||||
}
|
||||
@ -1161,7 +1154,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
hir::TypeBindingKind::Constraint { bounds }
|
||||
}
|
||||
DesugarKind::Error(position) => {
|
||||
let guar = self.tcx.sess.emit_err(errors::MisplacedAssocTyBinding {
|
||||
let guar = self.dcx().emit_err(errors::MisplacedAssocTyBinding {
|
||||
span: constraint.span,
|
||||
position: DiagnosticArgFromDisplay(position),
|
||||
});
|
||||
@ -1203,7 +1196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
data.inputs.last().unwrap().span.shrink_to_hi().to(data.inputs_span.shrink_to_hi());
|
||||
AssocTyParenthesesSub::NotEmpty { open_param, close_param }
|
||||
};
|
||||
self.tcx.sess.emit_err(AssocTyParentheses { span: data.span, sub });
|
||||
self.dcx().emit_err(AssocTyParentheses { span: data.span, sub });
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
@ -1318,7 +1311,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
span: t.span,
|
||||
},
|
||||
itctx,
|
||||
ast::Const::No,
|
||||
ast::BoundConstness::Never,
|
||||
);
|
||||
let bounds = this.arena.alloc_from_iter([bound]);
|
||||
let lifetime_bound = this.elided_dyn_bound(t.span);
|
||||
@ -1345,20 +1338,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let kind = match &t.kind {
|
||||
TyKind::Infer => hir::TyKind::Infer,
|
||||
TyKind::Err => {
|
||||
hir::TyKind::Err(self.tcx.sess.span_delayed_bug(t.span, "TyKind::Err lowered"))
|
||||
hir::TyKind::Err(self.dcx().span_delayed_bug(t.span, "TyKind::Err lowered"))
|
||||
}
|
||||
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
TyKind::AnonStruct(ref _fields) => hir::TyKind::Err(
|
||||
self.tcx.sess.span_err(t.span, "anonymous structs are unimplemented"),
|
||||
),
|
||||
TyKind::AnonStruct(ref _fields) => {
|
||||
hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous structs are unimplemented"))
|
||||
}
|
||||
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
TyKind::AnonUnion(ref _fields) => hir::TyKind::Err(
|
||||
self.tcx.sess.span_err(t.span, "anonymous unions are unimplemented"),
|
||||
),
|
||||
TyKind::AnonUnion(ref _fields) => {
|
||||
hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous unions are unimplemented"))
|
||||
}
|
||||
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
|
||||
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
|
||||
TyKind::Ref(region, mt) => {
|
||||
@ -1423,22 +1416,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
|
||||
let bounds =
|
||||
this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound {
|
||||
GenericBound::Trait(
|
||||
// We can safely ignore constness here since AST validation
|
||||
// takes care of rejecting invalid modifier combinations and
|
||||
// const trait bounds in trait object types.
|
||||
GenericBound::Trait(ty, modifiers) => match modifiers.polarity {
|
||||
BoundPolarity::Positive | BoundPolarity::Negative(_) => {
|
||||
Some(this.lower_poly_trait_ref(
|
||||
ty,
|
||||
modifier @ (TraitBoundModifier::None
|
||||
| TraitBoundModifier::MaybeConst(_)
|
||||
| TraitBoundModifier::Negative),
|
||||
) => {
|
||||
Some(this.lower_poly_trait_ref(ty, itctx, modifier.to_constness()))
|
||||
itctx,
|
||||
// Still, don't pass along the constness here; we don't want to
|
||||
// synthesize any host effect args, it'd only cause problems.
|
||||
ast::BoundConstness::Never,
|
||||
))
|
||||
}
|
||||
// `~const ?Bound` will cause an error during AST validation
|
||||
// anyways, so treat it like `?Bound` as compilation proceeds.
|
||||
GenericBound::Trait(
|
||||
_,
|
||||
TraitBoundModifier::Maybe
|
||||
| TraitBoundModifier::MaybeConstMaybe
|
||||
| TraitBoundModifier::MaybeConstNegative,
|
||||
) => None,
|
||||
BoundPolarity::Maybe(_) => None,
|
||||
},
|
||||
GenericBound::Outlives(lifetime) => {
|
||||
if lifetime_bound.is_none() {
|
||||
lifetime_bound = Some(this.lower_lifetime(lifetime));
|
||||
@ -1519,7 +1511,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
hir::TyKind::Err(guar)
|
||||
}
|
||||
ImplTraitContext::Disallowed(position) => {
|
||||
let guar = self.tcx.sess.emit_err(MisplacedImplTrait {
|
||||
let guar = self.dcx().emit_err(MisplacedImplTrait {
|
||||
span: t.span,
|
||||
position: DiagnosticArgFromDisplay(position),
|
||||
});
|
||||
@ -1529,7 +1521,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"),
|
||||
TyKind::CVarArgs => {
|
||||
let guar = self.tcx.sess.span_delayed_bug(
|
||||
let guar = self.dcx().span_delayed_bug(
|
||||
t.span,
|
||||
"`TyKind::CVarArgs` should have been handled elsewhere",
|
||||
);
|
||||
@ -1673,8 +1665,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
if let Some(old_def_id) = self.orig_opt_local_def_id(param) {
|
||||
old_def_id
|
||||
} else {
|
||||
self.tcx
|
||||
.sess
|
||||
self.dcx()
|
||||
.span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime");
|
||||
continue;
|
||||
}
|
||||
@ -1833,19 +1824,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
inputs = &inputs[..inputs.len() - 1];
|
||||
}
|
||||
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
|
||||
let itctx = if kind.param_impl_trait_allowed() {
|
||||
let itctx = match kind {
|
||||
FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => {
|
||||
ImplTraitContext::Universal
|
||||
} else {
|
||||
ImplTraitContext::Disallowed(match kind {
|
||||
FnDeclKind::Fn | FnDeclKind::Inherent => {
|
||||
unreachable!("fn should allow APIT")
|
||||
}
|
||||
FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam,
|
||||
FnDeclKind::Closure => ImplTraitPosition::ClosureParam,
|
||||
FnDeclKind::Pointer => ImplTraitPosition::PointerParam,
|
||||
FnDeclKind::Trait => ImplTraitPosition::TraitParam,
|
||||
FnDeclKind::Impl => ImplTraitPosition::ImplParam,
|
||||
})
|
||||
FnDeclKind::ExternFn => {
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnParam)
|
||||
}
|
||||
FnDeclKind::Closure => {
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ClosureParam)
|
||||
}
|
||||
FnDeclKind::Pointer => {
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam)
|
||||
}
|
||||
};
|
||||
self.lower_ty_direct(¶m.ty, &itctx)
|
||||
}));
|
||||
@ -1857,26 +1848,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
None => match &decl.output {
|
||||
FnRetTy::Ty(ty) => {
|
||||
let context = if kind.return_impl_trait_allowed() {
|
||||
let fn_def_id = self.local_def_id(fn_node_id);
|
||||
ImplTraitContext::ReturnPositionOpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
|
||||
fn_kind: kind,
|
||||
}
|
||||
} else {
|
||||
ImplTraitContext::Disallowed(match kind {
|
||||
let itctx = match kind {
|
||||
FnDeclKind::Fn
|
||||
| FnDeclKind::Inherent
|
||||
| FnDeclKind::Trait
|
||||
| FnDeclKind::Impl => {
|
||||
unreachable!("fn should allow return-position impl trait in traits")
|
||||
| FnDeclKind::Impl => ImplTraitContext::ReturnPositionOpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::FnReturn(self.local_def_id(fn_node_id)),
|
||||
fn_kind: kind,
|
||||
},
|
||||
FnDeclKind::ExternFn => {
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnReturn)
|
||||
}
|
||||
FnDeclKind::Closure => {
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ClosureReturn)
|
||||
}
|
||||
FnDeclKind::Pointer => {
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::PointerReturn)
|
||||
}
|
||||
FnDeclKind::ExternFn => ImplTraitPosition::ExternFnReturn,
|
||||
FnDeclKind::Closure => ImplTraitPosition::ClosureReturn,
|
||||
FnDeclKind::Pointer => ImplTraitPosition::PointerReturn,
|
||||
})
|
||||
};
|
||||
hir::FnRetTy::Return(self.lower_ty(ty, &context))
|
||||
hir::FnRetTy::Return(self.lower_ty(ty, &itctx))
|
||||
}
|
||||
FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)),
|
||||
},
|
||||
@ -2028,9 +2018,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
itctx: &ImplTraitContext,
|
||||
) -> hir::GenericBound<'hir> {
|
||||
match tpb {
|
||||
GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
|
||||
self.lower_poly_trait_ref(p, itctx, modifier.to_constness()),
|
||||
self.lower_trait_bound_modifier(*modifier),
|
||||
GenericBound::Trait(p, modifiers) => hir::GenericBound::Trait(
|
||||
self.lower_poly_trait_ref(p, itctx, modifiers.constness.into()),
|
||||
self.lower_trait_bound_modifiers(*modifiers),
|
||||
),
|
||||
GenericBound::Outlives(lifetime) => {
|
||||
hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
|
||||
@ -2109,7 +2099,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
param: &GenericParam,
|
||||
source: hir::GenericParamSource,
|
||||
) -> hir::GenericParam<'hir> {
|
||||
let (name, kind) = self.lower_generic_param_kind(param);
|
||||
let (name, kind) = self.lower_generic_param_kind(param, source);
|
||||
|
||||
let hir_id = self.lower_node_id(param.id);
|
||||
self.lower_attrs(hir_id, ¶m.attrs);
|
||||
@ -2128,6 +2118,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_generic_param_kind(
|
||||
&mut self,
|
||||
param: &GenericParam,
|
||||
source: hir::GenericParamSource,
|
||||
) -> (hir::ParamName, hir::GenericParamKind<'hir>) {
|
||||
match ¶m.kind {
|
||||
GenericParamKind::Lifetime => {
|
||||
@ -2146,22 +2137,51 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
(param_name, kind)
|
||||
}
|
||||
GenericParamKind::Type { default, .. } => {
|
||||
let kind = hir::GenericParamKind::Type {
|
||||
default: default.as_ref().map(|x| {
|
||||
// Not only do we deny type param defaults in binders but we also map them to `None`
|
||||
// since later compiler stages cannot handle them (and shouldn't need to be able to).
|
||||
let default = default
|
||||
.as_ref()
|
||||
.filter(|_| match source {
|
||||
hir::GenericParamSource::Generics => true,
|
||||
hir::GenericParamSource::Binder => {
|
||||
self.dcx().emit_err(errors::GenericParamDefaultInBinder {
|
||||
span: param.span(),
|
||||
});
|
||||
|
||||
false
|
||||
}
|
||||
})
|
||||
.map(|def| {
|
||||
self.lower_ty(
|
||||
x,
|
||||
def,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
|
||||
)
|
||||
}),
|
||||
synthetic: false,
|
||||
};
|
||||
});
|
||||
|
||||
let kind = hir::GenericParamKind::Type { default, synthetic: false };
|
||||
|
||||
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
|
||||
}
|
||||
GenericParamKind::Const { ty, kw_span: _, default } => {
|
||||
let ty = self
|
||||
.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault));
|
||||
let default = default.as_ref().map(|def| self.lower_anon_const(def));
|
||||
|
||||
// Not only do we deny const param defaults in binders but we also map them to `None`
|
||||
// since later compiler stages cannot handle them (and shouldn't need to be able to).
|
||||
let default = default
|
||||
.as_ref()
|
||||
.filter(|_| match source {
|
||||
hir::GenericParamSource::Generics => true,
|
||||
hir::GenericParamSource::Binder => {
|
||||
self.dcx().emit_err(errors::GenericParamDefaultInBinder {
|
||||
span: param.span(),
|
||||
});
|
||||
|
||||
false
|
||||
}
|
||||
})
|
||||
.map(|def| self.lower_anon_const(def));
|
||||
|
||||
(
|
||||
hir::ParamName::Plain(self.lower_ident(param.ident)),
|
||||
hir::GenericParamKind::Const { ty, default, is_host_effect: false },
|
||||
@ -2172,7 +2192,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
fn lower_trait_ref(
|
||||
&mut self,
|
||||
constness: ast::Const,
|
||||
constness: ast::BoundConstness,
|
||||
p: &TraitRef,
|
||||
itctx: &ImplTraitContext,
|
||||
) -> hir::TraitRef<'hir> {
|
||||
@ -2195,7 +2215,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
&mut self,
|
||||
p: &PolyTraitRef,
|
||||
itctx: &ImplTraitContext,
|
||||
constness: ast::Const,
|
||||
constness: ast::BoundConstness,
|
||||
) -> hir::PolyTraitRef<'hir> {
|
||||
let bound_generic_params =
|
||||
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
|
||||
@ -2285,10 +2305,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
match c.value.kind {
|
||||
ExprKind::Underscore => {
|
||||
if self.tcx.features().generic_arg_infer {
|
||||
hir::ArrayLen::Infer(self.lower_node_id(c.id), self.lower_span(c.value.span))
|
||||
hir::ArrayLen::Infer(hir::InferArg {
|
||||
hir_id: self.lower_node_id(c.id),
|
||||
span: self.lower_span(c.value.span),
|
||||
})
|
||||
} else {
|
||||
feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
&self.tcx.sess,
|
||||
sym::generic_arg_infer,
|
||||
c.value.span,
|
||||
"using `_` for array lengths is unstable",
|
||||
@ -2316,25 +2339,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier {
|
||||
match f {
|
||||
TraitBoundModifier::None => hir::TraitBoundModifier::None,
|
||||
TraitBoundModifier::MaybeConst(_) => hir::TraitBoundModifier::MaybeConst,
|
||||
|
||||
TraitBoundModifier::Negative => {
|
||||
fn lower_trait_bound_modifiers(
|
||||
&mut self,
|
||||
modifiers: TraitBoundModifiers,
|
||||
) -> hir::TraitBoundModifier {
|
||||
// Invalid modifier combinations will cause an error during AST validation.
|
||||
// Arbitrarily pick a placeholder for them to make compilation proceed.
|
||||
match (modifiers.constness, modifiers.polarity) {
|
||||
(BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None,
|
||||
(_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
|
||||
(BoundConstness::Never, BoundPolarity::Negative(_)) => {
|
||||
if self.tcx.features().negative_bounds {
|
||||
hir::TraitBoundModifier::Negative
|
||||
} else {
|
||||
hir::TraitBoundModifier::None
|
||||
}
|
||||
}
|
||||
|
||||
// `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a
|
||||
// placeholder for compilation to proceed.
|
||||
TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => {
|
||||
hir::TraitBoundModifier::Maybe
|
||||
}
|
||||
TraitBoundModifier::MaybeConstNegative => hir::TraitBoundModifier::MaybeConst,
|
||||
(BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const,
|
||||
(BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst,
|
||||
}
|
||||
}
|
||||
|
||||
@ -2552,45 +2574,62 @@ struct GenericArgsCtor<'hir> {
|
||||
}
|
||||
|
||||
impl<'hir> GenericArgsCtor<'hir> {
|
||||
fn push_constness(&mut self, lcx: &mut LoweringContext<'_, 'hir>, constness: ast::Const) {
|
||||
fn push_constness(
|
||||
&mut self,
|
||||
lcx: &mut LoweringContext<'_, 'hir>,
|
||||
constness: ast::BoundConstness,
|
||||
) {
|
||||
if !lcx.tcx.features().effects {
|
||||
return;
|
||||
}
|
||||
|
||||
// if bound is non-const, don't add host effect param
|
||||
let ast::Const::Yes(span) = constness else { return };
|
||||
|
||||
let (span, body) = match constness {
|
||||
BoundConstness::Never => return,
|
||||
BoundConstness::Always(span) => {
|
||||
let span = lcx.lower_span(span);
|
||||
|
||||
let id = lcx.next_node_id();
|
||||
let hir_id = lcx.next_id();
|
||||
let body = hir::ExprKind::Lit(
|
||||
lcx.arena.alloc(hir::Lit { node: LitKind::Bool(false), span }),
|
||||
);
|
||||
|
||||
(span, body)
|
||||
}
|
||||
BoundConstness::Maybe(span) => {
|
||||
let span = lcx.lower_span(span);
|
||||
|
||||
let Some(host_param_id) = lcx.host_param_id else {
|
||||
lcx.tcx.sess.span_delayed_bug(
|
||||
lcx.dcx().span_delayed_bug(
|
||||
span,
|
||||
"no host param id for call in const yet no errors reported",
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
let body = lcx.lower_body(|lcx| {
|
||||
(&[], {
|
||||
let hir_id = lcx.next_id();
|
||||
let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
|
||||
let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
let body = hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
lcx.arena.alloc(hir::Path {
|
||||
span,
|
||||
res,
|
||||
segments: arena_vec![lcx; hir::PathSegment::new(Ident {
|
||||
name: sym::host,
|
||||
span,
|
||||
}, hir_id, res)],
|
||||
segments: arena_vec![
|
||||
lcx;
|
||||
hir::PathSegment::new(
|
||||
Ident { name: sym::host, span },
|
||||
hir_id,
|
||||
res
|
||||
)
|
||||
],
|
||||
}),
|
||||
));
|
||||
lcx.expr(span, expr_kind)
|
||||
})
|
||||
});
|
||||
|
||||
(span, body)
|
||||
}
|
||||
};
|
||||
let body = lcx.lower_body(|lcx| (&[], lcx.expr(span, body)));
|
||||
|
||||
let id = lcx.next_node_id();
|
||||
let hir_id = lcx.next_id();
|
||||
|
||||
let def_id = lcx.create_def(
|
||||
lcx.current_hir_id_owner.def_id,
|
||||
|
||||
@ -82,7 +82,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
span: self.lower_span(f.span),
|
||||
}
|
||||
}));
|
||||
break hir::PatKind::Struct(qpath, fs, *etc);
|
||||
break hir::PatKind::Struct(qpath, fs, *etc == ast::PatFieldsRest::Rest);
|
||||
}
|
||||
PatKind::Tuple(pats) => {
|
||||
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
|
||||
@ -109,6 +109,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// return inner to be processed in next loop
|
||||
PatKind::Paren(inner) => pattern = inner,
|
||||
PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span),
|
||||
PatKind::Err(guar) => break hir::PatKind::Err(*guar),
|
||||
}
|
||||
};
|
||||
|
||||
@ -140,7 +141,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// This is not allowed as a sub-tuple pattern
|
||||
PatKind::Ident(_, ident, Some(sub)) if sub.is_rest() => {
|
||||
let sp = pat.span;
|
||||
self.tcx.sess.emit_err(SubTupleBinding {
|
||||
self.dcx().emit_err(SubTupleBinding {
|
||||
span: sp,
|
||||
ident_name: ident.name,
|
||||
ident: *ident,
|
||||
@ -289,12 +290,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
/// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
|
||||
pub(crate) fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
|
||||
self.tcx.sess.emit_err(ExtraDoubleDot { span: sp, prev_span: prev_sp, ctx });
|
||||
self.dcx().emit_err(ExtraDoubleDot { span: sp, prev_span: prev_sp, ctx });
|
||||
}
|
||||
|
||||
/// Used to ban the `..` pattern in places it shouldn't be semantically.
|
||||
fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> {
|
||||
self.tcx.sess.emit_err(MisplacedDoubleDot { span: sp });
|
||||
self.dcx().emit_err(MisplacedDoubleDot { span: sp });
|
||||
|
||||
// We're not in a list context so `..` can be reasonably treated
|
||||
// as `_` because it should always be valid and roughly matches the
|
||||
@ -334,7 +335,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
ExprKind::Path(..) if allow_paths => {}
|
||||
ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
|
||||
_ => {
|
||||
let guar = self.tcx.sess.emit_err(ArbitraryExpressionInPattern { span: expr.span });
|
||||
let guar = self.dcx().emit_err(ArbitraryExpressionInPattern { span: expr.span });
|
||||
return self.arena.alloc(self.expr_err(expr.span, guar));
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
param_mode: ParamMode,
|
||||
itctx: &ImplTraitContext,
|
||||
// constness of the impl/bound if this is a trait path
|
||||
constness: Option<ast::Const>,
|
||||
constness: Option<ast::BoundConstness>,
|
||||
) -> hir::QPath<'hir> {
|
||||
let qself_position = qself.as_ref().map(|q| q.position);
|
||||
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
|
||||
@ -140,7 +140,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
// We should've returned in the for loop above.
|
||||
|
||||
self.tcx.sess.dcx().span_bug(
|
||||
self.dcx().span_bug(
|
||||
p.span,
|
||||
format!(
|
||||
"lower_qpath: no final extension segment in {}..{}",
|
||||
@ -179,7 +179,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
param_mode: ParamMode,
|
||||
parenthesized_generic_args: ParenthesizedGenericArgs,
|
||||
itctx: &ImplTraitContext,
|
||||
constness: Option<ast::Const>,
|
||||
constness: Option<ast::BoundConstness>,
|
||||
) -> hir::PathSegment<'hir> {
|
||||
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment);
|
||||
let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() {
|
||||
@ -214,7 +214,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.tcx.sess.emit_err(GenericTypeWithParentheses { span: data.span, sub });
|
||||
self.dcx().emit_err(GenericTypeWithParentheses { span: data.span, sub });
|
||||
(
|
||||
self.lower_angle_bracketed_parameter_data(
|
||||
&data.as_angle_bracketed_args(),
|
||||
|
||||
@ -46,6 +46,8 @@ ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadi
|
||||
.const = `const` because of this
|
||||
.variadic = C-variadic because of this
|
||||
|
||||
ast_passes_const_bound_trait_object = const trait bounds are not allowed in trait object types
|
||||
|
||||
ast_passes_const_without_body =
|
||||
free constant item without body
|
||||
.suggestion = provide a definition for the constant
|
||||
@ -117,13 +119,13 @@ ast_passes_fn_without_body =
|
||||
free function without a body
|
||||
.suggestion = provide a definition for the function
|
||||
|
||||
ast_passes_forbidden_bound =
|
||||
bounds cannot be used in this context
|
||||
|
||||
ast_passes_forbidden_default =
|
||||
`default` is only allowed on items in trait impls
|
||||
.label = `default` because of this
|
||||
|
||||
ast_passes_forbidden_lifetime_bound =
|
||||
lifetime bounds cannot be used in this context
|
||||
|
||||
ast_passes_forbidden_non_lifetime_param =
|
||||
only lifetime parameters can be used in this context
|
||||
|
||||
@ -152,6 +154,8 @@ ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters
|
||||
ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
|
||||
.help = remove one of these features
|
||||
|
||||
ast_passes_incompatible_trait_bound_modifiers = `{$left}` and `{$right}` are mutually exclusive
|
||||
|
||||
ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
|
||||
.because = {$annotation} because of this
|
||||
.type = inherent impl for this type
|
||||
@ -184,6 +188,9 @@ ast_passes_module_nonascii = trying to load file for module `{$name}` with non-a
|
||||
ast_passes_negative_bound_not_supported =
|
||||
negative bounds are not supported
|
||||
|
||||
ast_passes_negative_bound_with_parenthetical_notation =
|
||||
parenthetical notation may not be used for negative bounds
|
||||
|
||||
ast_passes_nested_impl_trait = nested `impl Trait` is not allowed
|
||||
.outer = outer `impl Trait`
|
||||
.inner = nested `impl Trait` here
|
||||
@ -195,8 +202,6 @@ ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
|
||||
ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
|
||||
.help = use `auto trait Trait {"{}"}` instead
|
||||
|
||||
ast_passes_optional_const_exclusive = `~const` and `{$modifier}` are mutually exclusive
|
||||
|
||||
ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types
|
||||
|
||||
ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits
|
||||
@ -227,12 +232,28 @@ ast_passes_tilde_const_disallowed = `~const` is not allowed here
|
||||
.trait = this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
|
||||
.trait_impl = this impl is not `const`, so it cannot have `~const` trait bounds
|
||||
.impl = inherent impls cannot have `~const` trait bounds
|
||||
.trait_assoc_ty = associated types in non-`#[const_trait]` traits cannot have `~const` trait bounds
|
||||
.trait_impl_assoc_ty = associated types in non-const impls cannot have `~const` trait bounds
|
||||
.inherent_assoc_ty = inherent associated types cannot have `~const` trait bounds
|
||||
.object = trait objects cannot have `~const` trait bounds
|
||||
.item = this item cannot have `~const` trait bounds
|
||||
|
||||
ast_passes_trait_fn_const =
|
||||
functions in traits cannot be declared const
|
||||
.label = functions in traits cannot be const
|
||||
functions in {$in_impl ->
|
||||
[true] trait impls
|
||||
*[false] traits
|
||||
} cannot be declared const
|
||||
.label = functions in {$in_impl ->
|
||||
[true] trait impls
|
||||
*[false] traits
|
||||
} cannot be const
|
||||
.const_context_label = this declares all associated functions implicitly const
|
||||
.remove_const_sugg = remove the `const`{$requires_multiple_changes ->
|
||||
[true] {" ..."}
|
||||
*[false] {""}
|
||||
}
|
||||
.make_impl_const_sugg = ... and declare the impl to be const instead
|
||||
.make_trait_const_sugg = ... and declare the trait to be a `#[const_trait]` instead
|
||||
|
||||
ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted
|
||||
|
||||
|
||||
@ -37,15 +37,35 @@ enum SelfSemantic {
|
||||
}
|
||||
|
||||
/// What is the context that prevents using `~const`?
|
||||
// FIXME(effects): Consider getting rid of this in favor of `errors::TildeConstReason`, they're
|
||||
// almost identical. This gets rid of an abstraction layer which might be considered bad.
|
||||
enum DisallowTildeConstContext<'a> {
|
||||
TraitObject,
|
||||
Fn(FnKind<'a>),
|
||||
Trait(Span),
|
||||
TraitImpl(Span),
|
||||
Impl(Span),
|
||||
TraitAssocTy(Span),
|
||||
TraitImplAssocTy(Span),
|
||||
InherentAssocTy(Span),
|
||||
Item,
|
||||
}
|
||||
|
||||
enum TraitOrTraitImpl<'a> {
|
||||
Trait { span: Span, constness: Option<Span> },
|
||||
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: &'a TraitRef },
|
||||
}
|
||||
|
||||
impl<'a> TraitOrTraitImpl<'a> {
|
||||
fn constness(&self) -> Option<Span> {
|
||||
match self {
|
||||
Self::Trait { constness: Some(span), .. }
|
||||
| Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AstValidator<'a> {
|
||||
session: &'a Session,
|
||||
features: &'a Features,
|
||||
@ -53,11 +73,7 @@ struct AstValidator<'a> {
|
||||
/// The span of the `extern` in an `extern { ... }` block, if any.
|
||||
extern_mod: Option<&'a Item>,
|
||||
|
||||
/// Are we inside a trait impl?
|
||||
in_trait_impl: bool,
|
||||
|
||||
/// Are we inside a const trait defn or impl?
|
||||
in_const_trait_or_impl: bool,
|
||||
outer_trait_or_trait_impl: Option<TraitOrTraitImpl<'a>>,
|
||||
|
||||
has_proc_macro_decls: bool,
|
||||
|
||||
@ -78,24 +94,28 @@ struct AstValidator<'a> {
|
||||
impl<'a> AstValidator<'a> {
|
||||
fn with_in_trait_impl(
|
||||
&mut self,
|
||||
is_in: bool,
|
||||
constness: Option<Const>,
|
||||
trait_: Option<(Const, ImplPolarity, &'a TraitRef)>,
|
||||
f: impl FnOnce(&mut Self),
|
||||
) {
|
||||
let old = mem::replace(&mut self.in_trait_impl, is_in);
|
||||
let old_const = mem::replace(
|
||||
&mut self.in_const_trait_or_impl,
|
||||
matches!(constness, Some(Const::Yes(_))),
|
||||
let old = mem::replace(
|
||||
&mut self.outer_trait_or_trait_impl,
|
||||
trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl {
|
||||
constness,
|
||||
polarity,
|
||||
trait_ref,
|
||||
}),
|
||||
);
|
||||
f(self);
|
||||
self.in_trait_impl = old;
|
||||
self.in_const_trait_or_impl = old_const;
|
||||
self.outer_trait_or_trait_impl = old;
|
||||
}
|
||||
|
||||
fn with_in_trait(&mut self, is_const: bool, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.in_const_trait_or_impl, is_const);
|
||||
fn with_in_trait(&mut self, span: Span, constness: Option<Span>, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(
|
||||
&mut self.outer_trait_or_trait_impl,
|
||||
Some(TraitOrTraitImpl::Trait { span, constness }),
|
||||
);
|
||||
f(self);
|
||||
self.in_const_trait_or_impl = old;
|
||||
self.outer_trait_or_trait_impl = old;
|
||||
}
|
||||
|
||||
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
|
||||
@ -228,13 +248,13 @@ impl<'a> AstValidator<'a> {
|
||||
fn check_lifetime(&self, ident: Ident) {
|
||||
let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
|
||||
if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
|
||||
self.session.emit_err(errors::KeywordLifetime { span: ident.span });
|
||||
self.dcx().emit_err(errors::KeywordLifetime { span: ident.span });
|
||||
}
|
||||
}
|
||||
|
||||
fn check_label(&self, ident: Ident) {
|
||||
if ident.without_first_quote().is_reserved() {
|
||||
self.session.emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
|
||||
self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,7 +263,7 @@ impl<'a> AstValidator<'a> {
|
||||
return;
|
||||
}
|
||||
|
||||
self.session.emit_err(errors::VisibilityNotPermitted { span: vis.span, note });
|
||||
self.dcx().emit_err(errors::VisibilityNotPermitted { span: vis.span, note });
|
||||
}
|
||||
|
||||
fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
|
||||
@ -291,10 +311,49 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_fn_not_const(&self, constness: Const) {
|
||||
if let Const::Yes(span) = constness {
|
||||
self.session.emit_err(errors::TraitFnConst { span });
|
||||
}
|
||||
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl<'a>) {
|
||||
let Const::Yes(span) = constness else {
|
||||
return;
|
||||
};
|
||||
|
||||
let make_impl_const_sugg = if self.features.const_trait_impl
|
||||
&& let TraitOrTraitImpl::TraitImpl {
|
||||
constness: Const::No,
|
||||
polarity: ImplPolarity::Positive,
|
||||
trait_ref,
|
||||
..
|
||||
} = parent
|
||||
{
|
||||
Some(trait_ref.path.span.shrink_to_lo())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let make_trait_const_sugg = if self.features.const_trait_impl
|
||||
&& let TraitOrTraitImpl::Trait { span, constness: None } = parent
|
||||
{
|
||||
Some(span.shrink_to_lo())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let parent_constness = parent.constness();
|
||||
self.dcx().emit_err(errors::TraitFnConst {
|
||||
span,
|
||||
in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
|
||||
const_context_label: parent_constness,
|
||||
remove_const_sugg: (
|
||||
self.session.source_map().span_extend_while(span, |c| c == ' ').unwrap_or(span),
|
||||
match parent_constness {
|
||||
Some(_) => rustc_errors::Applicability::MachineApplicable,
|
||||
None => rustc_errors::Applicability::MaybeIncorrect,
|
||||
},
|
||||
),
|
||||
requires_multiple_changes: make_impl_const_sugg.is_some()
|
||||
|| make_trait_const_sugg.is_some(),
|
||||
make_impl_const_sugg,
|
||||
make_trait_const_sugg,
|
||||
});
|
||||
}
|
||||
|
||||
fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
|
||||
@ -310,7 +369,7 @@ impl<'a> AstValidator<'a> {
|
||||
let max_num_args: usize = u16::MAX.into();
|
||||
if fn_decl.inputs.len() > max_num_args {
|
||||
let Param { span, .. } = fn_decl.inputs[0];
|
||||
self.session.emit_fatal(errors::FnParamTooMany { span, max_num_args });
|
||||
self.dcx().emit_fatal(errors::FnParamTooMany { span, max_num_args });
|
||||
}
|
||||
}
|
||||
|
||||
@ -318,13 +377,13 @@ impl<'a> AstValidator<'a> {
|
||||
match &*fn_decl.inputs {
|
||||
[Param { ty, span, .. }] => {
|
||||
if let TyKind::CVarArgs = ty.kind {
|
||||
self.session.emit_err(errors::FnParamCVarArgsOnly { span: *span });
|
||||
self.dcx().emit_err(errors::FnParamCVarArgsOnly { span: *span });
|
||||
}
|
||||
}
|
||||
[ps @ .., _] => {
|
||||
for Param { ty, span, .. } in ps {
|
||||
if let TyKind::CVarArgs = ty.kind {
|
||||
self.session.emit_err(errors::FnParamCVarArgsNotLast { span: *span });
|
||||
self.dcx().emit_err(errors::FnParamCVarArgsNotLast { span: *span });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -351,9 +410,9 @@ impl<'a> AstValidator<'a> {
|
||||
})
|
||||
.for_each(|attr| {
|
||||
if attr.is_doc_comment() {
|
||||
self.session.emit_err(errors::FnParamDocComment { span: attr.span });
|
||||
self.dcx().emit_err(errors::FnParamDocComment { span: attr.span });
|
||||
} else {
|
||||
self.session.emit_err(errors::FnParamForbiddenAttr { span: attr.span });
|
||||
self.dcx().emit_err(errors::FnParamForbiddenAttr { span: attr.span });
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -361,7 +420,7 @@ impl<'a> AstValidator<'a> {
|
||||
fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
|
||||
if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
|
||||
if param.is_self() {
|
||||
self.session.emit_err(errors::FnParamForbiddenSelf { span: param.span });
|
||||
self.dcx().emit_err(errors::FnParamForbiddenSelf { span: param.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -369,7 +428,7 @@ impl<'a> AstValidator<'a> {
|
||||
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
|
||||
if let Defaultness::Default(def_span) = defaultness {
|
||||
let span = self.session.source_map().guess_head_span(span);
|
||||
self.session.emit_err(errors::ForbiddenDefault { span, def_span });
|
||||
self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
|
||||
}
|
||||
}
|
||||
|
||||
@ -532,24 +591,24 @@ impl<'a> AstValidator<'a> {
|
||||
return;
|
||||
}
|
||||
let span = self.session.source_map().guess_head_span(item_span);
|
||||
self.session.emit_err(errors::NoMangleAscii { span });
|
||||
self.dcx().emit_err(errors::NoMangleAscii { span });
|
||||
}
|
||||
|
||||
fn check_mod_file_item_asciionly(&self, ident: Ident) {
|
||||
if ident.name.as_str().is_ascii() {
|
||||
return;
|
||||
}
|
||||
self.session.emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name });
|
||||
self.dcx().emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name });
|
||||
}
|
||||
|
||||
fn deny_generic_params(&self, generics: &Generics, ident: Span) {
|
||||
if !generics.params.is_empty() {
|
||||
self.session.emit_err(errors::AutoTraitGeneric { span: generics.span, ident });
|
||||
self.dcx().emit_err(errors::AutoTraitGeneric { span: generics.span, ident });
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_e0568(&self, span: Span, ident: Span) {
|
||||
self.session.emit_err(errors::AutoTraitBounds { span, ident });
|
||||
self.dcx().emit_err(errors::AutoTraitBounds { span, ident });
|
||||
}
|
||||
|
||||
fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
|
||||
@ -569,7 +628,7 @@ impl<'a> AstValidator<'a> {
|
||||
if !trait_items.is_empty() {
|
||||
let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
|
||||
let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
|
||||
self.session.emit_err(errors::AutoTraitItems { spans, total, ident });
|
||||
self.dcx().emit_err(errors::AutoTraitItems { spans, total, ident });
|
||||
}
|
||||
}
|
||||
|
||||
@ -633,7 +692,7 @@ impl<'a> AstValidator<'a> {
|
||||
TyKind::BareFn(bfty) => {
|
||||
self.check_fn_decl(&bfty.decl, SelfSemantic::No);
|
||||
Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
|
||||
self.session.emit_err(errors::PatternFnPointer { span });
|
||||
self.dcx().emit_err(errors::PatternFnPointer { span });
|
||||
});
|
||||
if let Extern::Implicit(_) = bfty.ext {
|
||||
let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
|
||||
@ -645,7 +704,7 @@ impl<'a> AstValidator<'a> {
|
||||
for bound in bounds {
|
||||
if let GenericBound::Outlives(lifetime) = bound {
|
||||
if any_lifetime_bounds {
|
||||
self.session
|
||||
self.dcx()
|
||||
.emit_err(errors::TraitObjectBound { span: lifetime.ident.span });
|
||||
break;
|
||||
}
|
||||
@ -655,11 +714,11 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
TyKind::ImplTrait(_, bounds) => {
|
||||
if self.is_impl_trait_banned {
|
||||
self.session.emit_err(errors::ImplTraitPath { span: ty.span });
|
||||
self.dcx().emit_err(errors::ImplTraitPath { span: ty.span });
|
||||
}
|
||||
|
||||
if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
|
||||
self.session.emit_err(errors::NestedImplTrait {
|
||||
self.dcx().emit_err(errors::NestedImplTrait {
|
||||
span: ty.span,
|
||||
outer: outer_impl_trait_sp,
|
||||
inner: ty.span,
|
||||
@ -817,7 +876,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
self_ty,
|
||||
items,
|
||||
}) => {
|
||||
self.with_in_trait_impl(true, Some(*constness), |this| {
|
||||
self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| {
|
||||
this.visibility_not_permitted(
|
||||
&item.vis,
|
||||
errors::VisibilityNotPermittedNote::TraitImpl,
|
||||
@ -827,7 +886,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity)
|
||||
{
|
||||
this.session.emit_err(errors::UnsafeNegativeImpl {
|
||||
this.dcx().emit_err(errors::UnsafeNegativeImpl {
|
||||
span: sp.to(t.path.span),
|
||||
negative: sp,
|
||||
r#unsafe: span,
|
||||
@ -866,12 +925,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
only_trait: only_trait.then_some(()),
|
||||
};
|
||||
|
||||
self.visibility_not_permitted(
|
||||
self.with_in_trait_impl(None, |this| {
|
||||
this.visibility_not_permitted(
|
||||
&item.vis,
|
||||
errors::VisibilityNotPermittedNote::IndividualImplItems,
|
||||
);
|
||||
if let &Unsafe::Yes(span) = unsafety {
|
||||
self.dcx().emit_err(errors::InherentImplCannotUnsafe {
|
||||
this.dcx().emit_err(errors::InherentImplCannotUnsafe {
|
||||
span: self_ty.span,
|
||||
annotation_span: span,
|
||||
annotation: "unsafe",
|
||||
@ -879,22 +939,24 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
});
|
||||
}
|
||||
if let &ImplPolarity::Negative(span) = polarity {
|
||||
self.dcx().emit_err(error(span, "negative", false));
|
||||
this.dcx().emit_err(error(span, "negative", false));
|
||||
}
|
||||
if let &Defaultness::Default(def_span) = defaultness {
|
||||
self.dcx().emit_err(error(def_span, "`default`", true));
|
||||
this.dcx().emit_err(error(def_span, "`default`", true));
|
||||
}
|
||||
if let &Const::Yes(span) = constness {
|
||||
self.dcx().emit_err(error(span, "`const`", true));
|
||||
this.dcx().emit_err(error(span, "`const`", true));
|
||||
}
|
||||
|
||||
self.visit_vis(&item.vis);
|
||||
self.visit_ident(item.ident);
|
||||
self.with_tilde_const(Some(DisallowTildeConstContext::Impl(item.span)), |this| {
|
||||
this.visit_generics(generics)
|
||||
this.visit_vis(&item.vis);
|
||||
this.visit_ident(item.ident);
|
||||
this.with_tilde_const(
|
||||
Some(DisallowTildeConstContext::Impl(item.span)),
|
||||
|this| this.visit_generics(generics),
|
||||
);
|
||||
this.visit_ty(self_ty);
|
||||
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
|
||||
});
|
||||
self.visit_ty(self_ty);
|
||||
walk_list!(self, visit_assoc_item, items, AssocCtxt::Impl);
|
||||
walk_list!(self, visit_attribute, &item.attrs);
|
||||
return; // Avoid visiting again.
|
||||
}
|
||||
@ -902,7 +964,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
|
||||
if body.is_none() {
|
||||
self.session.emit_err(errors::FnWithoutBody {
|
||||
self.dcx().emit_err(errors::FnWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
extern_block_suggestion: match sig.header.ext {
|
||||
@ -963,8 +1025,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
}
|
||||
ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => {
|
||||
let is_const_trait = attr::contains_name(&item.attrs, sym::const_trait);
|
||||
self.with_in_trait(is_const_trait, |this| {
|
||||
let is_const_trait =
|
||||
attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span);
|
||||
self.with_in_trait(item.span, is_const_trait, |this| {
|
||||
if *is_auto == IsAuto::Yes {
|
||||
// Auto traits cannot have generics, super traits nor contain items.
|
||||
this.deny_generic_params(generics, item.ident.span);
|
||||
@ -977,8 +1040,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
// context for the supertraits.
|
||||
this.visit_vis(&item.vis);
|
||||
this.visit_ident(item.ident);
|
||||
let disallowed =
|
||||
(!is_const_trait).then(|| DisallowTildeConstContext::Trait(item.span));
|
||||
let disallowed = is_const_trait
|
||||
.is_none()
|
||||
.then(|| DisallowTildeConstContext::Trait(item.span));
|
||||
this.with_tilde_const(disallowed, |this| {
|
||||
this.visit_generics(generics);
|
||||
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
|
||||
@ -1031,14 +1095,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
ItemKind::Const(box ConstItem { defaultness, expr, .. }) => {
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
if expr.is_none() {
|
||||
self.session.emit_err(errors::ConstWithoutBody {
|
||||
self.dcx().emit_err(errors::ConstWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
}
|
||||
ItemKind::Static(box StaticItem { expr: None, .. }) => {
|
||||
self.session.emit_err(errors::StaticWithoutBody {
|
||||
self.dcx().emit_err(errors::StaticWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
@ -1048,7 +1112,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
) => {
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
if ty.is_none() {
|
||||
self.session.emit_err(errors::TyAliasWithoutBody {
|
||||
self.dcx().emit_err(errors::TyAliasWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
@ -1196,18 +1260,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
|
||||
fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
|
||||
if let GenericBound::Trait(poly, modify) = bound {
|
||||
match (ctxt, modify) {
|
||||
(BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
|
||||
if let GenericBound::Trait(poly, modifiers) = bound {
|
||||
match (ctxt, modifiers.constness, modifiers.polarity) {
|
||||
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
|
||||
self.dcx().emit_err(errors::OptionalTraitSupertrait {
|
||||
span: poly.span,
|
||||
path_str: pprust::path_to_string(&poly.trait_ref.path),
|
||||
});
|
||||
}
|
||||
(BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
|
||||
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
|
||||
self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span });
|
||||
}
|
||||
(_, &TraitBoundModifier::MaybeConst(span))
|
||||
(BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => {
|
||||
self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span });
|
||||
}
|
||||
(_, BoundConstness::Maybe(span), BoundPolarity::Positive)
|
||||
if let Some(reason) = &self.disallow_tilde_const =>
|
||||
{
|
||||
let reason = match reason {
|
||||
@ -1228,6 +1295,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
// suggestion for moving such bounds to the assoc const fns if available.
|
||||
errors::TildeConstReason::Impl { span }
|
||||
}
|
||||
&DisallowTildeConstContext::TraitAssocTy(span) => {
|
||||
errors::TildeConstReason::TraitAssocTy { span }
|
||||
}
|
||||
&DisallowTildeConstContext::TraitImplAssocTy(span) => {
|
||||
errors::TildeConstReason::TraitImplAssocTy { span }
|
||||
}
|
||||
&DisallowTildeConstContext::InherentAssocTy(span) => {
|
||||
errors::TildeConstReason::InherentAssocTy { span }
|
||||
}
|
||||
DisallowTildeConstContext::TraitObject => {
|
||||
errors::TildeConstReason::TraitObject
|
||||
}
|
||||
@ -1235,16 +1311,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
};
|
||||
self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
|
||||
}
|
||||
(_, TraitBoundModifier::MaybeConstMaybe) => {
|
||||
self.dcx().emit_err(errors::OptionalConstExclusive {
|
||||
(
|
||||
_,
|
||||
BoundConstness::Always(_) | BoundConstness::Maybe(_),
|
||||
BoundPolarity::Negative(_) | BoundPolarity::Maybe(_),
|
||||
) => {
|
||||
self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers {
|
||||
span: bound.span(),
|
||||
modifier: "?",
|
||||
});
|
||||
}
|
||||
(_, TraitBoundModifier::MaybeConstNegative) => {
|
||||
self.dcx().emit_err(errors::OptionalConstExclusive {
|
||||
span: bound.span(),
|
||||
modifier: "!",
|
||||
left: modifiers.constness.as_str(),
|
||||
right: modifiers.polarity.as_str(),
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
@ -1252,17 +1327,29 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
|
||||
// Negative trait bounds are not allowed to have associated constraints
|
||||
if let GenericBound::Trait(trait_ref, TraitBoundModifier::Negative) = bound
|
||||
if let GenericBound::Trait(trait_ref, modifiers) = bound
|
||||
&& let BoundPolarity::Negative(_) = modifiers.polarity
|
||||
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
|
||||
&& let Some(ast::GenericArgs::AngleBracketed(args)) = segment.args.as_deref()
|
||||
{
|
||||
match segment.args.as_deref() {
|
||||
Some(ast::GenericArgs::AngleBracketed(args)) => {
|
||||
for arg in &args.args {
|
||||
if let ast::AngleBracketedArg::Constraint(constraint) = arg {
|
||||
self.dcx()
|
||||
.emit_err(errors::ConstraintOnNegativeBound { span: constraint.span });
|
||||
self.dcx().emit_err(errors::ConstraintOnNegativeBound {
|
||||
span: constraint.span,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// The lowered form of parenthesized generic args contains a type binding.
|
||||
Some(ast::GenericArgs::Parenthesized(args)) => {
|
||||
self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation {
|
||||
span: args.span,
|
||||
});
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
visit::walk_param_bound(self, bound)
|
||||
}
|
||||
@ -1339,7 +1426,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
|
||||
let tilde_const_allowed =
|
||||
matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
|
||||
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)) if self.in_const_trait_or_impl);
|
||||
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)))
|
||||
&& self
|
||||
.outer_trait_or_trait_impl
|
||||
.as_ref()
|
||||
.and_then(TraitOrTraitImpl::constness)
|
||||
.is_some();
|
||||
|
||||
let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
|
||||
self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
|
||||
@ -1350,21 +1442,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
self.check_nomangle_item_asciionly(item.ident, item.span);
|
||||
}
|
||||
|
||||
if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
|
||||
if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() {
|
||||
self.check_defaultness(item.span, item.kind.defaultness());
|
||||
}
|
||||
|
||||
if ctxt == AssocCtxt::Impl {
|
||||
match &item.kind {
|
||||
AssocItemKind::Const(box ConstItem { expr: None, .. }) => {
|
||||
self.session.emit_err(errors::AssocConstWithoutBody {
|
||||
self.dcx().emit_err(errors::AssocConstWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { body, .. }) => {
|
||||
if body.is_none() {
|
||||
self.session.emit_err(errors::AssocFnWithoutBody {
|
||||
self.dcx().emit_err(errors::AssocFnWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
@ -1372,7 +1464,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
AssocItemKind::Type(box TyAlias { bounds, ty, .. }) => {
|
||||
if ty.is_none() {
|
||||
self.session.emit_err(errors::AssocTypeWithoutBody {
|
||||
self.dcx().emit_err(errors::AssocTypeWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
@ -1398,10 +1490,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
);
|
||||
}
|
||||
|
||||
if ctxt == AssocCtxt::Trait || self.in_trait_impl {
|
||||
if let Some(parent) = &self.outer_trait_or_trait_impl {
|
||||
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
|
||||
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
||||
self.check_trait_fn_not_const(sig.header.constness);
|
||||
self.check_trait_fn_not_const(sig.header.constness, parent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1409,9 +1501,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
self.check_item_named(item.ident, "const");
|
||||
}
|
||||
|
||||
let parent_is_const =
|
||||
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some();
|
||||
|
||||
match &item.kind {
|
||||
AssocItemKind::Fn(box Fn { sig, generics, body, .. })
|
||||
if self.in_const_trait_or_impl
|
||||
if parent_is_const
|
||||
|| ctxt == AssocCtxt::Trait
|
||||
|| matches!(sig.header.constness, Const::Yes(_)) =>
|
||||
{
|
||||
@ -1427,8 +1522,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
);
|
||||
self.visit_fn(kind, item.span, item.id);
|
||||
}
|
||||
_ => self
|
||||
.with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
|
||||
AssocItemKind::Type(_) => {
|
||||
let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {
|
||||
Some(TraitOrTraitImpl::Trait { .. }) => {
|
||||
DisallowTildeConstContext::TraitAssocTy(item.span)
|
||||
}
|
||||
Some(TraitOrTraitImpl::TraitImpl { .. }) => {
|
||||
DisallowTildeConstContext::TraitImplAssocTy(item.span)
|
||||
}
|
||||
None => DisallowTildeConstContext::InherentAssocTy(item.span),
|
||||
});
|
||||
self.with_tilde_const(disallowed, |this| {
|
||||
this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt))
|
||||
})
|
||||
}
|
||||
_ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1494,7 +1602,8 @@ fn deny_equality_constraints(
|
||||
for param in &generics.params {
|
||||
if param.ident == potential_param.ident {
|
||||
for bound in ¶m.bounds {
|
||||
if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
|
||||
if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) =
|
||||
bound
|
||||
{
|
||||
if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
|
||||
let assoc = pprust::path_to_string(&ast::Path::from_ident(
|
||||
@ -1543,8 +1652,7 @@ pub fn check_crate(
|
||||
session,
|
||||
features,
|
||||
extern_mod: None,
|
||||
in_trait_impl: false,
|
||||
in_const_trait_or_impl: false,
|
||||
outer_trait_or_trait_impl: None,
|
||||
has_proc_macro_decls: false,
|
||||
outer_impl_trait: None,
|
||||
disallow_tilde_const: Some(DisallowTildeConstContext::Item),
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
//! Errors emitted by ast_passes.
|
||||
|
||||
use rustc_ast::ParamKindOrd;
|
||||
use rustc_errors::AddToDiagnostic;
|
||||
use rustc_errors::{codes::*, AddToDiagnostic, Applicability};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||
|
||||
@ -23,7 +23,7 @@ pub struct InvalidLabel {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_visibility_not_permitted, code = "E0449")]
|
||||
#[diag(ast_passes_visibility_not_permitted, code = E0449)]
|
||||
pub struct VisibilityNotPermitted {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -44,16 +44,34 @@ pub enum VisibilityNotPermittedNote {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_trait_fn_const, code = "E0379")]
|
||||
#[diag(ast_passes_trait_fn_const, code = E0379)]
|
||||
pub struct TraitFnConst {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub in_impl: bool,
|
||||
#[label(ast_passes_const_context_label)]
|
||||
pub const_context_label: Option<Span>,
|
||||
#[suggestion(ast_passes_remove_const_sugg, code = "")]
|
||||
pub remove_const_sugg: (Span, Applicability),
|
||||
pub requires_multiple_changes: bool,
|
||||
#[suggestion(
|
||||
ast_passes_make_impl_const_sugg,
|
||||
code = "const ",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub make_impl_const_sugg: Option<Span>,
|
||||
#[suggestion(
|
||||
ast_passes_make_trait_const_sugg,
|
||||
code = "#[const_trait]\n",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub make_trait_const_sugg: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_forbidden_lifetime_bound)]
|
||||
pub struct ForbiddenLifetimeBound {
|
||||
#[diag(ast_passes_forbidden_bound)]
|
||||
pub struct ForbiddenBound {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
}
|
||||
@ -284,14 +302,14 @@ pub struct ItemUnderscore<'a> {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_nomangle_ascii, code = "E0754")]
|
||||
#[diag(ast_passes_nomangle_ascii, code = E0754)]
|
||||
pub struct NoMangleAscii {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_module_nonascii, code = "E0754")]
|
||||
#[diag(ast_passes_module_nonascii, code = E0754)]
|
||||
#[help]
|
||||
pub struct ModuleNonAscii {
|
||||
#[primary_span]
|
||||
@ -300,7 +318,7 @@ pub struct ModuleNonAscii {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_auto_generic, code = "E0567")]
|
||||
#[diag(ast_passes_auto_generic, code = E0567)]
|
||||
pub struct AutoTraitGeneric {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
@ -310,7 +328,7 @@ pub struct AutoTraitGeneric {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_auto_super_lifetime, code = "E0568")]
|
||||
#[diag(ast_passes_auto_super_lifetime, code = E0568)]
|
||||
pub struct AutoTraitBounds {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
@ -320,7 +338,7 @@ pub struct AutoTraitBounds {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_auto_items, code = "E0380")]
|
||||
#[diag(ast_passes_auto_items, code = E0380)]
|
||||
pub struct AutoTraitItems {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
@ -366,28 +384,28 @@ impl AddToDiagnostic for EmptyLabelManySpans {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_pattern_in_fn_pointer, code = "E0561")]
|
||||
#[diag(ast_passes_pattern_in_fn_pointer, code = E0561)]
|
||||
pub struct PatternFnPointer {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_trait_object_single_bound, code = "E0226")]
|
||||
#[diag(ast_passes_trait_object_single_bound, code = E0226)]
|
||||
pub struct TraitObjectBound {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_impl_trait_path, code = "E0667")]
|
||||
#[diag(ast_passes_impl_trait_path, code = E0667)]
|
||||
pub struct ImplTraitPath {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_nested_impl_trait, code = "E0666")]
|
||||
#[diag(ast_passes_nested_impl_trait, code = E0666)]
|
||||
pub struct NestedImplTrait {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -425,7 +443,7 @@ pub struct ObsoleteAuto {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_unsafe_negative_impl, code = "E0198")]
|
||||
#[diag(ast_passes_unsafe_negative_impl, code = E0198)]
|
||||
pub struct UnsafeNegativeImpl {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -450,7 +468,7 @@ pub struct InherentImplCannot<'a> {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_inherent_cannot_be, code = "E0197")]
|
||||
#[diag(ast_passes_inherent_cannot_be, code = E0197)]
|
||||
pub struct InherentImplCannotUnsafe<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -518,7 +536,7 @@ pub struct GenericDefaultTrailing {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_nested_lifetimes, code = "E0316")]
|
||||
#[diag(ast_passes_nested_lifetimes, code = E0316)]
|
||||
pub struct NestedLifetimes {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -540,6 +558,15 @@ pub struct OptionalTraitObject {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_const_bound_trait_object)]
|
||||
pub struct ConstBoundTraitObject {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
// FIXME(effects): Consider making the note/reason the message of the diagnostic.
|
||||
// FIXME(effects): Provide structured suggestions (e.g., add `const` / `#[const_trait]` here).
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_tilde_const_disallowed)]
|
||||
pub struct TildeConstDisallowed {
|
||||
@ -573,6 +600,21 @@ pub enum TildeConstReason {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(ast_passes_trait_assoc_ty)]
|
||||
TraitAssocTy {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(ast_passes_trait_impl_assoc_ty)]
|
||||
TraitImplAssocTy {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(ast_passes_inherent_assoc_ty)]
|
||||
InherentAssocTy {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(ast_passes_object)]
|
||||
TraitObject,
|
||||
#[note(ast_passes_item)]
|
||||
@ -580,11 +622,12 @@ pub enum TildeConstReason {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_optional_const_exclusive)]
|
||||
pub struct OptionalConstExclusive {
|
||||
#[diag(ast_passes_incompatible_trait_bound_modifiers)]
|
||||
pub struct IncompatibleTraitBoundModifiers {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub modifier: &'static str,
|
||||
pub left: &'static str,
|
||||
pub right: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
@ -612,7 +655,7 @@ pub struct ConstAndCVariadic {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_pattern_in_foreign, code = "E0130")]
|
||||
#[diag(ast_passes_pattern_in_foreign, code = E0130)]
|
||||
pub struct PatternInForeign {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
@ -620,7 +663,7 @@ pub struct PatternInForeign {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_pattern_in_bodiless, code = "E0642")]
|
||||
#[diag(ast_passes_pattern_in_bodiless, code = E0642)]
|
||||
pub struct PatternInBodiless {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
@ -668,14 +711,14 @@ pub struct AssociatedSuggestion2 {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_stability_outside_std, code = "E0734")]
|
||||
#[diag(ast_passes_stability_outside_std, code = E0734)]
|
||||
pub struct StabilityOutsideStd {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_feature_on_non_nightly, code = "E0554")]
|
||||
#[diag(ast_passes_feature_on_non_nightly, code = E0554)]
|
||||
pub struct FeatureOnNonNightly {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -699,8 +742,8 @@ impl AddToDiagnostic for StableFeature {
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
diag.set_arg("name", self.name);
|
||||
diag.set_arg("since", self.since);
|
||||
diag.arg("name", self.name);
|
||||
diag.arg("since", self.since);
|
||||
diag.help(fluent::ast_passes_stable_since);
|
||||
}
|
||||
}
|
||||
@ -737,6 +780,13 @@ pub struct ConstraintOnNegativeBound {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_negative_bound_with_parenthetical_notation)]
|
||||
pub struct NegativeBoundWithParentheticalNotation {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_invalid_unnamed_field_ty)]
|
||||
pub struct InvalidUnnamedFieldTy {
|
||||
|
||||
@ -17,14 +17,12 @@ use crate::errors;
|
||||
macro_rules! gate {
|
||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
|
||||
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
|
||||
feature_err(&$visitor.sess.parse_sess, sym::$feature, $span, $explain).emit();
|
||||
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
|
||||
}
|
||||
}};
|
||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
|
||||
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
|
||||
feature_err(&$visitor.sess.parse_sess, sym::$feature, $span, $explain)
|
||||
.help($help)
|
||||
.emit();
|
||||
feature_err(&$visitor.sess, sym::$feature, $span, $explain).with_help($help).emit();
|
||||
}
|
||||
}};
|
||||
}
|
||||
@ -33,7 +31,7 @@ macro_rules! gate {
|
||||
macro_rules! gate_alt {
|
||||
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{
|
||||
if !$has_feature && !$span.allows_unstable($name) {
|
||||
feature_err(&$visitor.sess.parse_sess, $name, $span, $explain).emit();
|
||||
feature_err(&$visitor.sess, $name, $span, $explain).emit();
|
||||
}
|
||||
}};
|
||||
}
|
||||
@ -45,7 +43,7 @@ macro_rules! gate_multi {
|
||||
let spans: Vec<_> =
|
||||
$spans.filter(|span| !span.allows_unstable(sym::$feature)).collect();
|
||||
if !spans.is_empty() {
|
||||
feature_err(&$visitor.sess.parse_sess, sym::$feature, spans, $explain).emit();
|
||||
feature_err(&$visitor.sess, sym::$feature, spans, $explain).emit();
|
||||
}
|
||||
}
|
||||
}};
|
||||
@ -55,7 +53,7 @@ macro_rules! gate_multi {
|
||||
macro_rules! gate_legacy {
|
||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
|
||||
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
|
||||
feature_warn(&$visitor.sess.parse_sess, sym::$feature, $span, $explain);
|
||||
feature_warn(&$visitor.sess, sym::$feature, $span, $explain);
|
||||
}
|
||||
}};
|
||||
}
|
||||
@ -91,14 +89,7 @@ impl<'a> PostExpansionVisitor<'a> {
|
||||
match abi::is_enabled(self.features, span, symbol_unescaped.as_str()) {
|
||||
Ok(()) => (),
|
||||
Err(abi::AbiDisabled::Unstable { feature, explain }) => {
|
||||
feature_err_issue(
|
||||
&self.sess.parse_sess,
|
||||
feature,
|
||||
span,
|
||||
GateIssue::Language,
|
||||
explain,
|
||||
)
|
||||
.emit();
|
||||
feature_err_issue(&self.sess, feature, span, GateIssue::Language, explain).emit();
|
||||
}
|
||||
Err(abi::AbiDisabled::Unrecognized) => {
|
||||
if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) {
|
||||
@ -152,8 +143,8 @@ impl<'a> PostExpansionVisitor<'a> {
|
||||
}
|
||||
|
||||
fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) {
|
||||
// Check only lifetime parameters are present and that the lifetime
|
||||
// parameters that are present have no bounds.
|
||||
// Check only lifetime parameters are present and that the
|
||||
// generic parameters that are present have no bounds.
|
||||
let non_lt_param_spans = params.iter().filter_map(|param| match param.kind {
|
||||
ast::GenericParamKind::Lifetime { .. } => None,
|
||||
_ => Some(param.ident.span),
|
||||
@ -164,10 +155,11 @@ impl<'a> PostExpansionVisitor<'a> {
|
||||
non_lt_param_spans,
|
||||
crate::fluent_generated::ast_passes_forbidden_non_lifetime_param
|
||||
);
|
||||
|
||||
for param in params {
|
||||
if !param.bounds.is_empty() {
|
||||
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
|
||||
self.sess.emit_err(errors::ForbiddenLifetimeBound { spans });
|
||||
self.sess.dcx().emit_err(errors::ForbiddenBound { spans });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -225,7 +217,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
|| attr.has_name(sym::rustc_const_stable)
|
||||
|| attr.has_name(sym::rustc_default_body_unstable)
|
||||
{
|
||||
self.sess.emit_err(errors::StabilityOutsideStd { span: attr.span });
|
||||
self.sess.dcx().emit_err(errors::StabilityOutsideStd { span: attr.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -370,6 +362,19 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_generic_args(&mut self, args: &'a ast::GenericArgs) {
|
||||
// This check needs to happen here because the never type can be returned from a function,
|
||||
// but cannot be used in any other context. If this check was in `visit_fn_ret_ty`, it
|
||||
// include both functions and generics like `impl Fn() -> !`.
|
||||
if let ast::GenericArgs::Parenthesized(generic_args) = args
|
||||
&& let ast::FnRetTy::Ty(ref ty) = generic_args.output
|
||||
&& matches!(ty.kind, ast::TyKind::Never)
|
||||
{
|
||||
gate!(&self, never_type, ty.span, "the `!` type is experimental");
|
||||
}
|
||||
visit::walk_generic_args(self, args);
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, e: &'a ast::Expr) {
|
||||
match e.kind {
|
||||
ast::ExprKind::TryBlock(_) => {
|
||||
@ -406,7 +411,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
&self,
|
||||
exclusive_range_pattern,
|
||||
pattern.span,
|
||||
"exclusive range pattern syntax is experimental"
|
||||
"exclusive range pattern syntax is experimental",
|
||||
"use an inclusive range pattern, like N..=M"
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
@ -515,7 +521,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||
}
|
||||
};
|
||||
}
|
||||
gate_all!(c_str_literals, "`c\"..\"` literals are experimental");
|
||||
gate_all!(
|
||||
if_let_guard,
|
||||
"`if let` guards are experimental",
|
||||
@ -527,6 +532,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||
"async closures are unstable",
|
||||
"to use an async block, remove the `||`: `async {`"
|
||||
);
|
||||
gate_all!(async_for_loop, "`for await` loops are experimental");
|
||||
gate_all!(
|
||||
closure_lifetime_binder,
|
||||
"`for<...>` binders for closures are experimental",
|
||||
@ -555,6 +561,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||
gate_all!(explicit_tail_calls, "`become` expression is experimental");
|
||||
gate_all!(generic_const_items, "generic const items are experimental");
|
||||
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
|
||||
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
|
||||
|
||||
if !visitor.features.never_patterns {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
@ -569,16 +576,11 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||
if let Ok(snippet) = sm.span_to_snippet(span)
|
||||
&& snippet == "!"
|
||||
{
|
||||
feature_err(
|
||||
&sess.parse_sess,
|
||||
sym::never_patterns,
|
||||
span,
|
||||
"`!` patterns are experimental",
|
||||
)
|
||||
feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
|
||||
.emit();
|
||||
} else {
|
||||
let suggestion = span.shrink_to_hi();
|
||||
sess.emit_err(errors::MatchArmWithNoBody { span, suggestion });
|
||||
sess.dcx().emit_err(errors::MatchArmWithNoBody { span, suggestion });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -586,7 +588,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||
|
||||
if !visitor.features.negative_bounds {
|
||||
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
|
||||
sess.emit_err(errors::NegativeBoundUnsupported { span });
|
||||
sess.dcx().emit_err(errors::NegativeBoundUnsupported { span });
|
||||
}
|
||||
}
|
||||
|
||||
@ -676,7 +678,11 @@ fn check_incompatible_features(sess: &Session, features: &Features) {
|
||||
if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2)
|
||||
{
|
||||
let spans = vec![f1_span, f2_span];
|
||||
sess.emit_err(errors::IncompatibleFeatures { spans, f1: f1_name, f2: f2_name });
|
||||
sess.dcx().emit_err(errors::IncompatibleFeatures {
|
||||
spans,
|
||||
f1: f1_name,
|
||||
f2: f2_name,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_is_partitioned)]
|
||||
#![feature(let_chains)]
|
||||
#![recursion_limit = "256"]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
|
||||
@ -38,21 +38,21 @@ struct ShowSpanVisitor<'a> {
|
||||
impl<'a> Visitor<'a> for ShowSpanVisitor<'a> {
|
||||
fn visit_expr(&mut self, e: &'a ast::Expr) {
|
||||
if let Mode::Expression = self.mode {
|
||||
self.dcx.emit_warning(errors::ShowSpan { span: e.span, msg: "expression" });
|
||||
self.dcx.emit_warn(errors::ShowSpan { span: e.span, msg: "expression" });
|
||||
}
|
||||
visit::walk_expr(self, e);
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, p: &'a ast::Pat) {
|
||||
if let Mode::Pattern = self.mode {
|
||||
self.dcx.emit_warning(errors::ShowSpan { span: p.span, msg: "pattern" });
|
||||
self.dcx.emit_warn(errors::ShowSpan { span: p.span, msg: "pattern" });
|
||||
}
|
||||
visit::walk_pat(self, p);
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: &'a ast::Ty) {
|
||||
if let Mode::Type = self.mode {
|
||||
self.dcx.emit_warning(errors::ShowSpan { span: t.span, msg: "type" });
|
||||
self.dcx.emit_warn(errors::ShowSpan { span: t.span, msg: "type" });
|
||||
}
|
||||
visit::walk_ty(self, t);
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
#![feature(box_patterns)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
mod helpers;
|
||||
pub mod pp;
|
||||
|
||||
@ -17,7 +17,7 @@ use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
|
||||
use rustc_ast::util::parser;
|
||||
use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind};
|
||||
use rustc_ast::{attr, BindingAnnotation, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term};
|
||||
use rustc_ast::{GenericArg, GenericBound, SelfKind, TraitBoundModifier};
|
||||
use rustc_ast::{GenericArg, GenericBound, SelfKind};
|
||||
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_span::edition::Edition;
|
||||
@ -160,6 +160,10 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
|
||||
use TokenTree::Delimited as Del;
|
||||
use TokenTree::Token as Tok;
|
||||
|
||||
fn is_punct(tt: &TokenTree) -> bool {
|
||||
matches!(tt, TokenTree::Token(tok, _) if tok.is_punct())
|
||||
}
|
||||
|
||||
// Each match arm has one or more examples in comments. The default is to
|
||||
// insert space between adjacent tokens, except for the cases listed in
|
||||
// this match.
|
||||
@ -167,24 +171,35 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
|
||||
// No space after line doc comments.
|
||||
(Tok(Token { kind: DocComment(CommentKind::Line, ..), .. }, _), _) => false,
|
||||
|
||||
// `.` + ANYTHING: `x.y`, `tup.0`
|
||||
// `$` + ANYTHING: `$e`
|
||||
(Tok(Token { kind: Dot | Dollar, .. }, _), _) => false,
|
||||
// `.` + NON-PUNCT: `x.y`, `tup.0`
|
||||
(Tok(Token { kind: Dot, .. }, _), tt2) if !is_punct(tt2) => false,
|
||||
|
||||
// ANYTHING + `,`: `foo,`
|
||||
// ANYTHING + `.`: `x.y`, `tup.0`
|
||||
// ANYTHING + `!`: `foo! { ... }`
|
||||
//
|
||||
// FIXME: Incorrect cases:
|
||||
// - Logical not: `x =! y`, `if! x { f(); }`
|
||||
// - Never type: `Fn() ->!`
|
||||
(_, Tok(Token { kind: Comma | Dot | Not, .. }, _)) => false,
|
||||
// `$` + IDENT: `$e`
|
||||
(Tok(Token { kind: Dollar, .. }, _), Tok(Token { kind: Ident(..), .. }, _)) => false,
|
||||
|
||||
// IDENT + `(`: `f(3)`
|
||||
//
|
||||
// FIXME: Incorrect cases:
|
||||
// - Let: `let(a, b) = (1, 2)`
|
||||
(Tok(Token { kind: Ident(..), .. }, _), Del(_, _, Parenthesis, _)) => false,
|
||||
// NON-PUNCT + `,`: `foo,`
|
||||
// NON-PUNCT + `;`: `x = 3;`, `[T; 3]`
|
||||
// NON-PUNCT + `.`: `x.y`, `tup.0`
|
||||
(tt1, Tok(Token { kind: Comma | Semi | Dot, .. }, _)) if !is_punct(tt1) => false,
|
||||
|
||||
// IDENT + `!`: `println!()`, but `if !x { ... }` needs a space after the `if`
|
||||
(Tok(Token { kind: Ident(sym, is_raw), span }, _), Tok(Token { kind: Not, .. }, _))
|
||||
if !Ident::new(*sym, *span).is_reserved() || *is_raw =>
|
||||
{
|
||||
false
|
||||
}
|
||||
|
||||
// IDENT|`fn`|`Self`|`pub` + `(`: `f(3)`, `fn(x: u8)`, `Self()`, `pub(crate)`,
|
||||
// but `let (a, b) = (1, 2)` needs a space after the `let`
|
||||
(Tok(Token { kind: Ident(sym, is_raw), span }, _), Del(_, _, Parenthesis, _))
|
||||
if !Ident::new(*sym, *span).is_reserved()
|
||||
|| *sym == kw::Fn
|
||||
|| *sym == kw::SelfUpper
|
||||
|| *sym == kw::Pub
|
||||
|| *is_raw =>
|
||||
{
|
||||
false
|
||||
}
|
||||
|
||||
// `#` + `[`: `#[attr]`
|
||||
(Tok(Token { kind: Pound, .. }, _), Del(_, _, Bracket, _)) => false,
|
||||
@ -1096,14 +1111,22 @@ impl<'a> State<'a> {
|
||||
ast::StmtKind::Item(item) => self.print_item(item),
|
||||
ast::StmtKind::Expr(expr) => {
|
||||
self.space_if_not_bol();
|
||||
self.print_expr_outer_attr_style(expr, false, FixupContext::default());
|
||||
self.print_expr_outer_attr_style(
|
||||
expr,
|
||||
false,
|
||||
FixupContext { stmt: true, ..FixupContext::default() },
|
||||
);
|
||||
if classify::expr_requires_semi_to_be_stmt(expr) {
|
||||
self.word(";");
|
||||
}
|
||||
}
|
||||
ast::StmtKind::Semi(expr) => {
|
||||
self.space_if_not_bol();
|
||||
self.print_expr_outer_attr_style(expr, false, FixupContext::default());
|
||||
self.print_expr_outer_attr_style(
|
||||
expr,
|
||||
false,
|
||||
FixupContext { stmt: true, ..FixupContext::default() },
|
||||
);
|
||||
self.word(";");
|
||||
}
|
||||
ast::StmtKind::Empty => {
|
||||
@ -1155,7 +1178,11 @@ impl<'a> State<'a> {
|
||||
ast::StmtKind::Expr(expr) if i == blk.stmts.len() - 1 => {
|
||||
self.maybe_print_comment(st.span.lo());
|
||||
self.space_if_not_bol();
|
||||
self.print_expr_outer_attr_style(expr, false, FixupContext::default());
|
||||
self.print_expr_outer_attr_style(
|
||||
expr,
|
||||
false,
|
||||
FixupContext { stmt: true, ..FixupContext::default() },
|
||||
);
|
||||
self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
|
||||
}
|
||||
_ => self.print_stmt(st),
|
||||
@ -1427,7 +1454,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
self.nbsp();
|
||||
self.word("{");
|
||||
let empty = fields.is_empty() && !etc;
|
||||
let empty = fields.is_empty() && *etc == ast::PatFieldsRest::None;
|
||||
if !empty {
|
||||
self.space();
|
||||
}
|
||||
@ -1445,7 +1472,7 @@ impl<'a> State<'a> {
|
||||
},
|
||||
|f| f.pat.span,
|
||||
);
|
||||
if *etc {
|
||||
if *etc == ast::PatFieldsRest::Rest {
|
||||
if !fields.is_empty() {
|
||||
self.word_space(",");
|
||||
}
|
||||
@ -1507,6 +1534,11 @@ impl<'a> State<'a> {
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::MacCall(m) => self.print_mac(m),
|
||||
PatKind::Err(_) => {
|
||||
self.popen();
|
||||
self.word("/*ERROR*/");
|
||||
self.pclose();
|
||||
}
|
||||
}
|
||||
self.ann.post(self, AnnNode::Pat(pat))
|
||||
}
|
||||
@ -1559,26 +1591,20 @@ impl<'a> State<'a> {
|
||||
|
||||
match bound {
|
||||
GenericBound::Trait(tref, modifier) => {
|
||||
match modifier {
|
||||
TraitBoundModifier::None => {}
|
||||
TraitBoundModifier::Negative => {
|
||||
self.word("!");
|
||||
}
|
||||
TraitBoundModifier::Maybe => {
|
||||
self.word("?");
|
||||
}
|
||||
TraitBoundModifier::MaybeConst(_) => {
|
||||
self.word_space("~const");
|
||||
}
|
||||
TraitBoundModifier::MaybeConstNegative => {
|
||||
self.word_space("~const");
|
||||
self.word("!");
|
||||
}
|
||||
TraitBoundModifier::MaybeConstMaybe => {
|
||||
self.word_space("~const");
|
||||
self.word("?");
|
||||
match modifier.constness {
|
||||
ast::BoundConstness::Never => {}
|
||||
ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_) => {
|
||||
self.word_space(modifier.constness.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
match modifier.polarity {
|
||||
ast::BoundPolarity::Positive => {}
|
||||
ast::BoundPolarity::Negative(_) | ast::BoundPolarity::Maybe(_) => {
|
||||
self.word(modifier.polarity.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
self.print_poly_trait_ref(tref);
|
||||
}
|
||||
GenericBound::Outlives(lt) => self.print_lifetime(*lt),
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
use crate::pp::Breaks::Inconsistent;
|
||||
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
|
||||
use ast::ForLoopKind;
|
||||
use itertools::{Itertools, Position};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::literal::escape_byte_str_symbol;
|
||||
use rustc_ast::util::parser::{self, AssocOp, Fixity};
|
||||
use rustc_ast::{self as ast, BlockCheckMode};
|
||||
@ -14,6 +16,61 @@ use std::fmt::Write;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct FixupContext {
|
||||
/// Print expression such that it can be parsed back as a statement
|
||||
/// consisting of the original expression.
|
||||
///
|
||||
/// The effect of this is for binary operators in statement position to set
|
||||
/// `leftmost_subexpression_in_stmt` when printing their left-hand operand.
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// (match x {}) - 1; // match needs parens when LHS of binary operator
|
||||
///
|
||||
/// match x {}; // not when its own statement
|
||||
/// ```
|
||||
pub stmt: bool,
|
||||
|
||||
/// This is the difference between:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// (match x {}) - 1; // subexpression needs parens
|
||||
///
|
||||
/// let _ = match x {} - 1; // no parens
|
||||
/// ```
|
||||
///
|
||||
/// There are 3 distinguishable contexts in which `print_expr` might be
|
||||
/// called with the expression `$match` as its argument, where `$match`
|
||||
/// represents an expression of kind `ExprKind::Match`:
|
||||
///
|
||||
/// - stmt=false leftmost_subexpression_in_stmt=false
|
||||
///
|
||||
/// Example: `let _ = $match - 1;`
|
||||
///
|
||||
/// No parentheses required.
|
||||
///
|
||||
/// - stmt=false leftmost_subexpression_in_stmt=true
|
||||
///
|
||||
/// Example: `$match - 1;`
|
||||
///
|
||||
/// Must parenthesize `($match)`, otherwise parsing back the output as a
|
||||
/// statement would terminate the statement after the closing brace of
|
||||
/// the match, parsing `-1;` as a separate statement.
|
||||
///
|
||||
/// - stmt=true leftmost_subexpression_in_stmt=false
|
||||
///
|
||||
/// Example: `$match;`
|
||||
///
|
||||
/// No parentheses required.
|
||||
pub leftmost_subexpression_in_stmt: bool,
|
||||
|
||||
/// This is the difference between:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// if let _ = (Struct {}) {} // needs parens
|
||||
///
|
||||
/// match () {
|
||||
/// () if let _ = Struct {} => {} // no parens
|
||||
/// }
|
||||
/// ```
|
||||
pub parenthesize_exterior_struct_lit: bool,
|
||||
}
|
||||
|
||||
@ -21,7 +78,11 @@ pub(crate) struct FixupContext {
|
||||
/// in a targetted fashion where needed.
|
||||
impl Default for FixupContext {
|
||||
fn default() -> Self {
|
||||
FixupContext { parenthesize_exterior_struct_lit: false }
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
parenthesize_exterior_struct_lit: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,7 +136,8 @@ impl<'a> State<'a> {
|
||||
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
|
||||
/// `if cond { ... }`.
|
||||
fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
|
||||
let fixup = FixupContext { parenthesize_exterior_struct_lit: true };
|
||||
let fixup =
|
||||
FixupContext { parenthesize_exterior_struct_lit: true, ..FixupContext::default() };
|
||||
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr), fixup)
|
||||
}
|
||||
|
||||
@ -98,11 +160,10 @@ impl<'a> State<'a> {
|
||||
&mut self,
|
||||
expr: &ast::Expr,
|
||||
needs_par: bool,
|
||||
fixup: FixupContext,
|
||||
mut fixup: FixupContext,
|
||||
) {
|
||||
if needs_par {
|
||||
self.popen();
|
||||
}
|
||||
|
||||
// If we are surrounding the whole cond in parentheses, such as:
|
||||
//
|
||||
@ -115,9 +176,9 @@ impl<'a> State<'a> {
|
||||
//
|
||||
// if x == (Struct {}) {}
|
||||
//
|
||||
let fixup = FixupContext {
|
||||
parenthesize_exterior_struct_lit: fixup.parenthesize_exterior_struct_lit && !needs_par,
|
||||
};
|
||||
fixup = FixupContext::default();
|
||||
}
|
||||
|
||||
self.print_expr(expr, fixup);
|
||||
|
||||
if needs_par {
|
||||
@ -233,7 +294,32 @@ impl<'a> State<'a> {
|
||||
_ => parser::PREC_POSTFIX,
|
||||
};
|
||||
|
||||
self.print_expr_maybe_paren(func, prec, fixup);
|
||||
// Independent of parenthesization related to precedence, we must
|
||||
// parenthesize `func` if this is a statement context in which without
|
||||
// parentheses, a statement boundary would occur inside `func` or
|
||||
// immediately after `func`.
|
||||
//
|
||||
// Suppose `func` represents `match () { _ => f }`. We must produce:
|
||||
//
|
||||
// (match () { _ => f })();
|
||||
//
|
||||
// instead of:
|
||||
//
|
||||
// match () { _ => f } ();
|
||||
//
|
||||
// because the latter is valid syntax but with the incorrect meaning.
|
||||
// It's a match-expression followed by tuple-expression, not a function
|
||||
// call.
|
||||
self.print_expr_maybe_paren(
|
||||
func,
|
||||
prec,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: fixup.stmt || fixup.leftmost_subexpression_in_stmt,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
|
||||
self.print_call_post(args)
|
||||
}
|
||||
|
||||
@ -244,7 +330,17 @@ impl<'a> State<'a> {
|
||||
base_args: &[P<ast::Expr>],
|
||||
fixup: FixupContext,
|
||||
) {
|
||||
// Unlike in `print_expr_call`, no change to fixup here because
|
||||
// statement boundaries never occur in front of a `.` (or `?`) token.
|
||||
//
|
||||
// match () { _ => f }.method();
|
||||
//
|
||||
// Parenthesizing only for precedence and not with regard to statement
|
||||
// boundaries, `$receiver.method()` can be parsed back as a statement
|
||||
// containing an expression if and only if `$receiver` can be parsed as
|
||||
// a statement containing an expression.
|
||||
self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX, fixup);
|
||||
|
||||
self.word(".");
|
||||
self.print_ident(segment.ident);
|
||||
if let Some(args) = &segment.args {
|
||||
@ -288,22 +384,36 @@ impl<'a> State<'a> {
|
||||
(&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
|
||||
parser::PREC_FORCE_PAREN
|
||||
}
|
||||
// For a binary expression like `(match () { _ => a }) OP b`, the parens are required
|
||||
// otherwise the parser would interpret `match () { _ => a }` as a statement,
|
||||
// with the remaining `OP b` not making sense. So we force parens.
|
||||
(&ast::ExprKind::Match(..), _) => parser::PREC_FORCE_PAREN,
|
||||
_ => left_prec,
|
||||
};
|
||||
|
||||
self.print_expr_maybe_paren(lhs, left_prec, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
lhs,
|
||||
left_prec,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: fixup.stmt || fixup.leftmost_subexpression_in_stmt,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
|
||||
self.space();
|
||||
self.word_space(op.node.as_str());
|
||||
self.print_expr_maybe_paren(rhs, right_prec, fixup)
|
||||
|
||||
self.print_expr_maybe_paren(
|
||||
rhs,
|
||||
right_prec,
|
||||
FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
|
||||
);
|
||||
}
|
||||
|
||||
fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) {
|
||||
self.word(op.as_str());
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX, fixup)
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
parser::PREC_PREFIX,
|
||||
FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
|
||||
);
|
||||
}
|
||||
|
||||
fn print_expr_addr_of(
|
||||
@ -321,7 +431,11 @@ impl<'a> State<'a> {
|
||||
self.print_mutability(mutability, true);
|
||||
}
|
||||
}
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX, fixup)
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
parser::PREC_PREFIX,
|
||||
FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn print_expr(&mut self, expr: &ast::Expr, fixup: FixupContext) {
|
||||
@ -332,7 +446,7 @@ impl<'a> State<'a> {
|
||||
&mut self,
|
||||
expr: &ast::Expr,
|
||||
is_inline: bool,
|
||||
fixup: FixupContext,
|
||||
mut fixup: FixupContext,
|
||||
) {
|
||||
self.maybe_print_comment(expr.span.lo());
|
||||
|
||||
@ -344,7 +458,27 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
self.ibox(INDENT_UNIT);
|
||||
|
||||
// The Match subexpression in `match x {} - 1` must be parenthesized if
|
||||
// it is the leftmost subexpression in a statement:
|
||||
//
|
||||
// (match x {}) - 1;
|
||||
//
|
||||
// But not otherwise:
|
||||
//
|
||||
// let _ = match x {} - 1;
|
||||
//
|
||||
// Same applies to a small set of other expression kinds which eagerly
|
||||
// terminate a statement which opens with them.
|
||||
let needs_par =
|
||||
fixup.leftmost_subexpression_in_stmt && !classify::expr_requires_semi_to_be_stmt(expr);
|
||||
if needs_par {
|
||||
self.popen();
|
||||
fixup = FixupContext::default();
|
||||
}
|
||||
|
||||
self.ann.pre(self, AnnNode::Expr(expr));
|
||||
|
||||
match &expr.kind {
|
||||
ast::ExprKind::Array(exprs) => {
|
||||
self.print_expr_vec(exprs);
|
||||
@ -385,7 +519,16 @@ impl<'a> State<'a> {
|
||||
}
|
||||
ast::ExprKind::Cast(expr, ty) => {
|
||||
let prec = AssocOp::As.precedence() as i8;
|
||||
self.print_expr_maybe_paren(expr, prec, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
prec,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: fixup.stmt
|
||||
|| fixup.leftmost_subexpression_in_stmt,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
self.space();
|
||||
self.word_space("as");
|
||||
self.print_type(ty);
|
||||
@ -418,20 +561,23 @@ impl<'a> State<'a> {
|
||||
self.space();
|
||||
self.print_block_with_attrs(blk, attrs);
|
||||
}
|
||||
ast::ExprKind::ForLoop(pat, iter, blk, opt_label) => {
|
||||
if let Some(label) = opt_label {
|
||||
ast::ExprKind::ForLoop { pat, iter, body, label, kind } => {
|
||||
if let Some(label) = label {
|
||||
self.print_ident(label.ident);
|
||||
self.word_space(":");
|
||||
}
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
self.word_nbsp("for");
|
||||
if kind == &ForLoopKind::ForAwait {
|
||||
self.word_nbsp("await");
|
||||
}
|
||||
self.print_pat(pat);
|
||||
self.space();
|
||||
self.word_space("in");
|
||||
self.print_expr_as_cond(iter);
|
||||
self.space();
|
||||
self.print_block_with_attrs(blk, attrs);
|
||||
self.print_block_with_attrs(body, attrs);
|
||||
}
|
||||
ast::ExprKind::Loop(blk, opt_label, _) => {
|
||||
if let Some(label) = opt_label {
|
||||
@ -504,31 +650,71 @@ impl<'a> State<'a> {
|
||||
self.print_block_with_attrs(blk, attrs);
|
||||
}
|
||||
ast::ExprKind::Await(expr, _) => {
|
||||
// Same fixups as ExprKind::MethodCall.
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
|
||||
self.word(".await");
|
||||
}
|
||||
ast::ExprKind::Assign(lhs, rhs, _) => {
|
||||
// Same fixups as ExprKind::Binary.
|
||||
let prec = AssocOp::Assign.precedence() as i8;
|
||||
self.print_expr_maybe_paren(lhs, prec + 1, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
lhs,
|
||||
prec + 1,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: fixup.stmt
|
||||
|| fixup.leftmost_subexpression_in_stmt,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.print_expr_maybe_paren(rhs, prec, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
rhs,
|
||||
prec,
|
||||
FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
|
||||
);
|
||||
}
|
||||
ast::ExprKind::AssignOp(op, lhs, rhs) => {
|
||||
// Same fixups as ExprKind::Binary.
|
||||
let prec = AssocOp::Assign.precedence() as i8;
|
||||
self.print_expr_maybe_paren(lhs, prec + 1, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
lhs,
|
||||
prec + 1,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: fixup.stmt
|
||||
|| fixup.leftmost_subexpression_in_stmt,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
self.space();
|
||||
self.word(op.node.as_str());
|
||||
self.word_space("=");
|
||||
self.print_expr_maybe_paren(rhs, prec, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
rhs,
|
||||
prec,
|
||||
FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
|
||||
);
|
||||
}
|
||||
ast::ExprKind::Field(expr, ident) => {
|
||||
// Same fixups as ExprKind::MethodCall.
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
|
||||
self.word(".");
|
||||
self.print_ident(*ident);
|
||||
}
|
||||
ast::ExprKind::Index(expr, index, _) => {
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
|
||||
// Same fixups as ExprKind::Call.
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
parser::PREC_POSTFIX,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: fixup.stmt
|
||||
|| fixup.leftmost_subexpression_in_stmt,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
self.word("[");
|
||||
self.print_expr(index, FixupContext::default());
|
||||
self.word("]");
|
||||
@ -540,14 +726,31 @@ impl<'a> State<'a> {
|
||||
// a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
|
||||
let fake_prec = AssocOp::LOr.precedence() as i8;
|
||||
if let Some(e) = start {
|
||||
self.print_expr_maybe_paren(e, fake_prec, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
e,
|
||||
fake_prec,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: fixup.stmt
|
||||
|| fixup.leftmost_subexpression_in_stmt,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
}
|
||||
match limits {
|
||||
ast::RangeLimits::HalfOpen => self.word(".."),
|
||||
ast::RangeLimits::Closed => self.word("..="),
|
||||
}
|
||||
if let Some(e) = end {
|
||||
self.print_expr_maybe_paren(e, fake_prec, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
e,
|
||||
fake_prec,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Underscore => self.word("_"),
|
||||
@ -561,7 +764,15 @@ impl<'a> State<'a> {
|
||||
}
|
||||
if let Some(expr) = opt_expr {
|
||||
self.space();
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
parser::PREC_JUMP,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Continue(opt_label) => {
|
||||
@ -575,7 +786,15 @@ impl<'a> State<'a> {
|
||||
self.word("return");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
parser::PREC_JUMP,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Yeet(result) => {
|
||||
@ -584,13 +803,25 @@ impl<'a> State<'a> {
|
||||
self.word("yeet");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
parser::PREC_JUMP,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Become(result) => {
|
||||
self.word("become");
|
||||
self.word(" ");
|
||||
self.print_expr_maybe_paren(result, parser::PREC_JUMP, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
result,
|
||||
parser::PREC_JUMP,
|
||||
FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
|
||||
);
|
||||
}
|
||||
ast::ExprKind::InlineAsm(a) => {
|
||||
// FIXME: This should have its own syntax, distinct from a macro invocation.
|
||||
@ -640,10 +871,19 @@ impl<'a> State<'a> {
|
||||
|
||||
if let Some(expr) = e {
|
||||
self.space();
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
|
||||
self.print_expr_maybe_paren(
|
||||
expr,
|
||||
parser::PREC_JUMP,
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
..fixup
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Try(e) => {
|
||||
// Same fixups as ExprKind::MethodCall.
|
||||
self.print_expr_maybe_paren(e, parser::PREC_POSTFIX, fixup);
|
||||
self.word("?")
|
||||
}
|
||||
@ -659,7 +899,13 @@ impl<'a> State<'a> {
|
||||
self.pclose()
|
||||
}
|
||||
}
|
||||
|
||||
self.ann.post(self, AnnNode::Expr(expr));
|
||||
|
||||
if needs_par {
|
||||
self.pclose();
|
||||
}
|
||||
|
||||
self.end();
|
||||
}
|
||||
|
||||
@ -700,7 +946,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
_ => {
|
||||
self.end(); // Close the ibox for the pattern.
|
||||
self.print_expr(body, FixupContext::default());
|
||||
self.print_expr(body, FixupContext { stmt: true, ..FixupContext::default() });
|
||||
self.word(",");
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
|
||||
use ast::StaticItem;
|
||||
use itertools::{Itertools, Position};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::GenericBound;
|
||||
use rustc_ast::ModKind;
|
||||
use rustc_span::symbol::Ident;
|
||||
|
||||
@ -338,19 +337,9 @@ impl<'a> State<'a> {
|
||||
self.word_nbsp("trait");
|
||||
self.print_ident(item.ident);
|
||||
self.print_generic_params(&generics.params);
|
||||
let mut real_bounds = Vec::with_capacity(bounds.len());
|
||||
for b in bounds.iter() {
|
||||
if let GenericBound::Trait(ptr, ast::TraitBoundModifier::Maybe) = b {
|
||||
self.space();
|
||||
self.word_space("for ?");
|
||||
self.print_trait_ref(&ptr.trait_ref);
|
||||
} else {
|
||||
real_bounds.push(b.clone());
|
||||
}
|
||||
}
|
||||
if !real_bounds.is_empty() {
|
||||
if !bounds.is_empty() {
|
||||
self.word_nbsp(":");
|
||||
self.print_type_bounds(&real_bounds);
|
||||
self.print_type_bounds(bounds);
|
||||
}
|
||||
self.print_where_clause(&generics.where_clause);
|
||||
self.word(" ");
|
||||
@ -387,6 +376,9 @@ impl<'a> State<'a> {
|
||||
state.print_visibility(&item.vis)
|
||||
});
|
||||
}
|
||||
ast::ItemKind::Delegation(box delegation) => {
|
||||
self.print_delegation(delegation, &item.vis, &item.attrs)
|
||||
}
|
||||
}
|
||||
self.ann.post(self, AnnNode::Item(item))
|
||||
}
|
||||
@ -565,10 +557,38 @@ impl<'a> State<'a> {
|
||||
self.word(";");
|
||||
}
|
||||
}
|
||||
ast::AssocItemKind::Delegation(box delegation) => {
|
||||
self.print_delegation(delegation, vis, &item.attrs)
|
||||
}
|
||||
}
|
||||
self.ann.post(self, AnnNode::SubItem(id))
|
||||
}
|
||||
|
||||
pub(crate) fn print_delegation(
|
||||
&mut self,
|
||||
delegation: &ast::Delegation,
|
||||
vis: &ast::Visibility,
|
||||
attrs: &[ast::Attribute],
|
||||
) {
|
||||
if delegation.body.is_some() {
|
||||
self.head("");
|
||||
}
|
||||
self.print_visibility(vis);
|
||||
self.word_space("reuse");
|
||||
|
||||
if let Some(qself) = &delegation.qself {
|
||||
self.print_qpath(&delegation.path, qself, false);
|
||||
} else {
|
||||
self.print_path(&delegation.path, false, 0);
|
||||
}
|
||||
if let Some(body) = &delegation.body {
|
||||
self.nbsp();
|
||||
self.print_block_with_attrs(body, attrs);
|
||||
} else {
|
||||
self.word(";");
|
||||
}
|
||||
}
|
||||
|
||||
fn print_fn_full(
|
||||
&mut self,
|
||||
sig: &ast::FnSig,
|
||||
|
||||
@ -9,7 +9,7 @@ use rustc_macros::HashStable_Generic;
|
||||
use rustc_session::config::ExpectedValues;
|
||||
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||
use rustc_session::parse::{feature_err, ParseSess};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::{RustcVersion, Session};
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::{symbol::sym, symbol::Symbol, Span};
|
||||
@ -207,7 +207,8 @@ pub fn find_stability(
|
||||
sym::rustc_allowed_through_unstable_modules => allowed_through_unstable_modules = true,
|
||||
sym::unstable => {
|
||||
if stab.is_some() {
|
||||
sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
|
||||
sess.dcx()
|
||||
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
|
||||
break;
|
||||
}
|
||||
|
||||
@ -217,7 +218,8 @@ pub fn find_stability(
|
||||
}
|
||||
sym::stable => {
|
||||
if stab.is_some() {
|
||||
sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
|
||||
sess.dcx()
|
||||
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
|
||||
break;
|
||||
}
|
||||
if let Some((feature, level)) = parse_stability(sess, attr) {
|
||||
@ -238,7 +240,8 @@ pub fn find_stability(
|
||||
_,
|
||||
)) => *allowed_through_unstable_modules = true,
|
||||
_ => {
|
||||
sess.emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp });
|
||||
sess.dcx()
|
||||
.emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -261,7 +264,8 @@ pub fn find_const_stability(
|
||||
sym::rustc_promotable => promotable = true,
|
||||
sym::rustc_const_unstable => {
|
||||
if const_stab.is_some() {
|
||||
sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
|
||||
sess.dcx()
|
||||
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
|
||||
break;
|
||||
}
|
||||
|
||||
@ -272,7 +276,8 @@ pub fn find_const_stability(
|
||||
}
|
||||
sym::rustc_const_stable => {
|
||||
if const_stab.is_some() {
|
||||
sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
|
||||
sess.dcx()
|
||||
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
|
||||
break;
|
||||
}
|
||||
if let Some((feature, level)) = parse_stability(sess, attr) {
|
||||
@ -288,7 +293,11 @@ pub fn find_const_stability(
|
||||
if promotable {
|
||||
match &mut const_stab {
|
||||
Some((stab, _)) => stab.promotable = promotable,
|
||||
_ => _ = sess.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp }),
|
||||
_ => {
|
||||
_ = sess
|
||||
.dcx()
|
||||
.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -306,7 +315,8 @@ pub fn find_body_stability(
|
||||
for attr in attrs {
|
||||
if attr.has_name(sym::rustc_default_body_unstable) {
|
||||
if body_stab.is_some() {
|
||||
sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
|
||||
sess.dcx()
|
||||
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
|
||||
break;
|
||||
}
|
||||
|
||||
@ -321,7 +331,7 @@ pub fn find_body_stability(
|
||||
|
||||
fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option<Symbol>) -> Option<()> {
|
||||
if item.is_some() {
|
||||
sess.emit_err(session_diagnostics::MultipleItem {
|
||||
sess.dcx().emit_err(session_diagnostics::MultipleItem {
|
||||
span: meta.span,
|
||||
item: pprust::path_to_string(&meta.path),
|
||||
});
|
||||
@ -330,7 +340,7 @@ fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option<Symbol>) -
|
||||
*item = Some(v);
|
||||
Some(())
|
||||
} else {
|
||||
sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
|
||||
sess.dcx().emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -345,7 +355,7 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
|
||||
let mut since = None;
|
||||
for meta in metas {
|
||||
let Some(mi) = meta.meta_item() else {
|
||||
sess.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
span: meta.span(),
|
||||
reason: UnsupportedLiteralReason::Generic,
|
||||
is_bytestr: false,
|
||||
@ -358,7 +368,7 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
|
||||
sym::feature => insert_or_error(sess, mi, &mut feature)?,
|
||||
sym::since => insert_or_error(sess, mi, &mut since)?,
|
||||
_ => {
|
||||
sess.emit_err(session_diagnostics::UnknownMetaItem {
|
||||
sess.dcx().emit_err(session_diagnostics::UnknownMetaItem {
|
||||
span: meta.span(),
|
||||
item: pprust::path_to_string(&mi.path),
|
||||
expected: &["feature", "since"],
|
||||
@ -371,9 +381,9 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
|
||||
let feature = match feature {
|
||||
Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
|
||||
Some(_bad_feature) => {
|
||||
Err(sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
|
||||
Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
|
||||
}
|
||||
None => Err(sess.emit_err(session_diagnostics::MissingFeature { span: attr.span })),
|
||||
None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span })),
|
||||
};
|
||||
|
||||
let since = if let Some(since) = since {
|
||||
@ -382,11 +392,11 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
|
||||
} else if let Some(version) = parse_version(since) {
|
||||
StableSince::Version(version)
|
||||
} else {
|
||||
sess.emit_err(session_diagnostics::InvalidSince { span: attr.span });
|
||||
sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span });
|
||||
StableSince::Err
|
||||
}
|
||||
} else {
|
||||
sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
|
||||
sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span });
|
||||
StableSince::Err
|
||||
};
|
||||
|
||||
@ -413,7 +423,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
|
||||
let mut implied_by = None;
|
||||
for meta in metas {
|
||||
let Some(mi) = meta.meta_item() else {
|
||||
sess.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
span: meta.span(),
|
||||
reason: UnsupportedLiteralReason::Generic,
|
||||
is_bytestr: false,
|
||||
@ -435,7 +445,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
|
||||
issue => match issue.parse::<NonZeroU32>() {
|
||||
Ok(num) => Some(num),
|
||||
Err(err) => {
|
||||
sess.emit_err(
|
||||
sess.dcx().emit_err(
|
||||
session_diagnostics::InvalidIssueString {
|
||||
span: mi.span,
|
||||
cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind(
|
||||
@ -451,13 +461,13 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
|
||||
}
|
||||
sym::soft => {
|
||||
if !mi.is_word() {
|
||||
sess.emit_err(session_diagnostics::SoftNoArgs { span: mi.span });
|
||||
sess.dcx().emit_err(session_diagnostics::SoftNoArgs { span: mi.span });
|
||||
}
|
||||
is_soft = true;
|
||||
}
|
||||
sym::implied_by => insert_or_error(sess, mi, &mut implied_by)?,
|
||||
_ => {
|
||||
sess.emit_err(session_diagnostics::UnknownMetaItem {
|
||||
sess.dcx().emit_err(session_diagnostics::UnknownMetaItem {
|
||||
span: meta.span(),
|
||||
item: pprust::path_to_string(&mi.path),
|
||||
expected: &["feature", "reason", "issue", "soft", "implied_by"],
|
||||
@ -470,13 +480,13 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
|
||||
let feature = match feature {
|
||||
Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
|
||||
Some(_bad_feature) => {
|
||||
Err(sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
|
||||
Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
|
||||
}
|
||||
None => Err(sess.emit_err(session_diagnostics::MissingFeature { span: attr.span })),
|
||||
None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span })),
|
||||
};
|
||||
|
||||
let issue =
|
||||
issue.ok_or_else(|| sess.emit_err(session_diagnostics::MissingIssue { span: attr.span }));
|
||||
let issue = issue
|
||||
.ok_or_else(|| sess.dcx().emit_err(session_diagnostics::MissingIssue { span: attr.span }));
|
||||
|
||||
match (feature, issue) {
|
||||
(Ok(feature), Ok(_)) => {
|
||||
@ -508,15 +518,15 @@ pub struct Condition {
|
||||
/// Tests if a cfg-pattern matches the cfg set
|
||||
pub fn cfg_matches(
|
||||
cfg: &ast::MetaItem,
|
||||
sess: &ParseSess,
|
||||
sess: &Session,
|
||||
lint_node_id: NodeId,
|
||||
features: Option<&Features>,
|
||||
) -> bool {
|
||||
eval_condition(cfg, sess, features, &mut |cfg| {
|
||||
try_gate_cfg(cfg.name, cfg.span, sess, features);
|
||||
match sess.check_config.expecteds.get(&cfg.name) {
|
||||
match sess.parse_sess.check_config.expecteds.get(&cfg.name) {
|
||||
Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
|
||||
sess.buffer_lint_with_diagnostic(
|
||||
sess.parse_sess.buffer_lint_with_diagnostic(
|
||||
UNEXPECTED_CFGS,
|
||||
cfg.span,
|
||||
lint_node_id,
|
||||
@ -531,8 +541,8 @@ pub fn cfg_matches(
|
||||
),
|
||||
);
|
||||
}
|
||||
None if sess.check_config.exhaustive_names => {
|
||||
sess.buffer_lint_with_diagnostic(
|
||||
None if sess.parse_sess.check_config.exhaustive_names => {
|
||||
sess.parse_sess.buffer_lint_with_diagnostic(
|
||||
UNEXPECTED_CFGS,
|
||||
cfg.span,
|
||||
lint_node_id,
|
||||
@ -545,18 +555,18 @@ pub fn cfg_matches(
|
||||
}
|
||||
_ => { /* not unexpected */ }
|
||||
}
|
||||
sess.config.contains(&(cfg.name, cfg.value))
|
||||
sess.parse_sess.config.contains(&(cfg.name, cfg.value))
|
||||
})
|
||||
}
|
||||
|
||||
fn try_gate_cfg(name: Symbol, span: Span, sess: &ParseSess, features: Option<&Features>) {
|
||||
fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) {
|
||||
let gate = find_gated_cfg(|sym| sym == name);
|
||||
if let (Some(feats), Some(gated_cfg)) = (features, gate) {
|
||||
gate_cfg(gated_cfg, span, sess, feats);
|
||||
}
|
||||
}
|
||||
|
||||
fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &Features) {
|
||||
fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) {
|
||||
let (cfg, feature, has_feature) = gated_cfg;
|
||||
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
|
||||
let explain = format!("`cfg({cfg})` is experimental and subject to change");
|
||||
@ -584,10 +594,11 @@ fn parse_version(s: Symbol) -> Option<RustcVersion> {
|
||||
/// evaluate individual items.
|
||||
pub fn eval_condition(
|
||||
cfg: &ast::MetaItem,
|
||||
sess: &ParseSess,
|
||||
sess: &Session,
|
||||
features: Option<&Features>,
|
||||
eval: &mut impl FnMut(Condition) -> bool,
|
||||
) -> bool {
|
||||
let dcx = &sess.parse_sess.dcx;
|
||||
match &cfg.kind {
|
||||
ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
|
||||
try_gate_cfg(sym::version, cfg.span, sess, features);
|
||||
@ -599,23 +610,23 @@ pub fn eval_condition(
|
||||
NestedMetaItem::Lit(MetaItemLit { span, .. })
|
||||
| NestedMetaItem::MetaItem(MetaItem { span, .. }),
|
||||
] => {
|
||||
sess.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span });
|
||||
dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span });
|
||||
return false;
|
||||
}
|
||||
[..] => {
|
||||
sess.emit_err(session_diagnostics::ExpectedSingleVersionLiteral {
|
||||
dcx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral {
|
||||
span: cfg.span,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let Some(min_version) = parse_version(*min_version) else {
|
||||
sess.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span });
|
||||
dcx.emit_warn(session_diagnostics::UnknownVersionLiteral { span: *span });
|
||||
return false;
|
||||
};
|
||||
|
||||
// See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
|
||||
if sess.assume_incomplete_release {
|
||||
if sess.parse_sess.assume_incomplete_release {
|
||||
RustcVersion::CURRENT > min_version
|
||||
} else {
|
||||
RustcVersion::CURRENT >= min_version
|
||||
@ -624,7 +635,7 @@ pub fn eval_condition(
|
||||
ast::MetaItemKind::List(mis) => {
|
||||
for mi in mis.iter() {
|
||||
if !mi.is_meta_item() {
|
||||
sess.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
span: mi.span(),
|
||||
reason: UnsupportedLiteralReason::Generic,
|
||||
is_bytestr: false,
|
||||
@ -653,9 +664,7 @@ pub fn eval_condition(
|
||||
}),
|
||||
sym::not => {
|
||||
if mis.len() != 1 {
|
||||
sess.emit_err(session_diagnostics::ExpectedOneCfgPattern {
|
||||
span: cfg.span,
|
||||
});
|
||||
dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -684,7 +693,7 @@ pub fn eval_condition(
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
sess.emit_err(session_diagnostics::InvalidPredicate {
|
||||
dcx.emit_err(session_diagnostics::InvalidPredicate {
|
||||
span: cfg.span,
|
||||
predicate: pprust::path_to_string(&cfg.path),
|
||||
});
|
||||
@ -693,11 +702,11 @@ pub fn eval_condition(
|
||||
}
|
||||
}
|
||||
ast::MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => {
|
||||
sess.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span });
|
||||
dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span });
|
||||
true
|
||||
}
|
||||
MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
|
||||
sess.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
span: lit.span,
|
||||
reason: UnsupportedLiteralReason::CfgString,
|
||||
is_bytestr: lit.kind.is_bytestr(),
|
||||
@ -791,7 +800,7 @@ pub fn find_deprecation(
|
||||
MetaItemKind::List(list) => {
|
||||
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
|
||||
if item.is_some() {
|
||||
sess.emit_err(session_diagnostics::MultipleItem {
|
||||
sess.dcx().emit_err(session_diagnostics::MultipleItem {
|
||||
span: meta.span,
|
||||
item: pprust::path_to_string(&meta.path),
|
||||
});
|
||||
@ -802,14 +811,14 @@ pub fn find_deprecation(
|
||||
true
|
||||
} else {
|
||||
if let Some(lit) = meta.name_value_literal() {
|
||||
sess.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
span: lit.span,
|
||||
reason: UnsupportedLiteralReason::DeprecatedString,
|
||||
is_bytestr: lit.kind.is_bytestr(),
|
||||
start_point_span: sess.source_map().start_point(lit.span),
|
||||
});
|
||||
} else {
|
||||
sess.emit_err(session_diagnostics::IncorrectMetaItem {
|
||||
sess.dcx().emit_err(session_diagnostics::IncorrectMetaItem {
|
||||
span: meta.span,
|
||||
});
|
||||
}
|
||||
@ -833,11 +842,13 @@ pub fn find_deprecation(
|
||||
}
|
||||
sym::suggestion => {
|
||||
if !features.deprecated_suggestion {
|
||||
sess.emit_err(session_diagnostics::DeprecatedItemSuggestion {
|
||||
sess.dcx().emit_err(
|
||||
session_diagnostics::DeprecatedItemSuggestion {
|
||||
span: mi.span,
|
||||
is_nightly: sess.is_nightly_build().then_some(()),
|
||||
details: (),
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if !get(mi, &mut suggestion) {
|
||||
@ -845,7 +856,7 @@ pub fn find_deprecation(
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
sess.emit_err(session_diagnostics::UnknownMetaItem {
|
||||
sess.dcx().emit_err(session_diagnostics::UnknownMetaItem {
|
||||
span: meta.span(),
|
||||
item: pprust::path_to_string(&mi.path),
|
||||
expected: if features.deprecated_suggestion {
|
||||
@ -858,7 +869,7 @@ pub fn find_deprecation(
|
||||
}
|
||||
},
|
||||
NestedMetaItem::Lit(lit) => {
|
||||
sess.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
span: lit.span,
|
||||
reason: UnsupportedLiteralReason::DeprecatedKvPair,
|
||||
is_bytestr: false,
|
||||
@ -879,18 +890,18 @@ pub fn find_deprecation(
|
||||
} else if let Some(version) = parse_version(since) {
|
||||
DeprecatedSince::RustcVersion(version)
|
||||
} else {
|
||||
sess.emit_err(session_diagnostics::InvalidSince { span: attr.span });
|
||||
sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span });
|
||||
DeprecatedSince::Err
|
||||
}
|
||||
} else if is_rustc {
|
||||
sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
|
||||
sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span });
|
||||
DeprecatedSince::Err
|
||||
} else {
|
||||
DeprecatedSince::Unspecified
|
||||
};
|
||||
|
||||
if is_rustc && note.is_none() {
|
||||
sess.emit_err(session_diagnostics::MissingNote { span: attr.span });
|
||||
sess.dcx().emit_err(session_diagnostics::MissingNote { span: attr.span });
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -945,7 +956,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {attr:?}");
|
||||
use ReprAttr::*;
|
||||
let mut acc = Vec::new();
|
||||
let diagnostic = sess.dcx();
|
||||
let dcx = sess.dcx();
|
||||
|
||||
if let Some(items) = attr.meta_item_list() {
|
||||
for item in items {
|
||||
@ -958,7 +969,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
sym::simd => Some(ReprSimd),
|
||||
sym::transparent => Some(ReprTransparent),
|
||||
sym::align => {
|
||||
sess.emit_err(session_diagnostics::InvalidReprAlignNeedArg {
|
||||
sess.dcx().emit_err(session_diagnostics::InvalidReprAlignNeedArg {
|
||||
span: item.span(),
|
||||
});
|
||||
recognised = true;
|
||||
@ -989,13 +1000,13 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
|| int_type_of_word(name).is_some()
|
||||
{
|
||||
recognised = true;
|
||||
sess.emit_err(session_diagnostics::InvalidReprHintNoParen {
|
||||
sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
|
||||
span: item.span(),
|
||||
name: name.to_ident_string(),
|
||||
});
|
||||
}
|
||||
if let Some(literal_error) = literal_error {
|
||||
sess.emit_err(session_diagnostics::InvalidReprGeneric {
|
||||
sess.dcx().emit_err(session_diagnostics::InvalidReprGeneric {
|
||||
span: item.span(),
|
||||
repr_arg: name.to_ident_string(),
|
||||
error_part: literal_error,
|
||||
@ -1007,7 +1018,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
|
||||
let name = meta_item.name_or_empty().to_ident_string();
|
||||
recognised = true;
|
||||
sess.emit_err(session_diagnostics::IncorrectReprFormatGeneric {
|
||||
sess.dcx().emit_err(session_diagnostics::IncorrectReprFormatGeneric {
|
||||
span: item.span(),
|
||||
repr_arg: &name,
|
||||
cause: IncorrectReprFormatGenericCause::from_lit_kind(
|
||||
@ -1022,7 +1033,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
) || int_type_of_word(meta_item.name_or_empty()).is_some()
|
||||
{
|
||||
recognised = true;
|
||||
sess.emit_err(session_diagnostics::InvalidReprHintNoValue {
|
||||
sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoValue {
|
||||
span: meta_item.span,
|
||||
name: meta_item.name_or_empty().to_ident_string(),
|
||||
});
|
||||
@ -1031,12 +1042,14 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
MetaItemKind::List(_) => {
|
||||
if meta_item.has_name(sym::align) {
|
||||
recognised = true;
|
||||
sess.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
|
||||
sess.dcx().emit_err(
|
||||
session_diagnostics::IncorrectReprFormatAlignOneArg {
|
||||
span: meta_item.span,
|
||||
});
|
||||
},
|
||||
);
|
||||
} else if meta_item.has_name(sym::packed) {
|
||||
recognised = true;
|
||||
sess.emit_err(
|
||||
sess.dcx().emit_err(
|
||||
session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
|
||||
span: meta_item.span,
|
||||
},
|
||||
@ -1047,7 +1060,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
) || int_type_of_word(meta_item.name_or_empty()).is_some()
|
||||
{
|
||||
recognised = true;
|
||||
sess.emit_err(session_diagnostics::InvalidReprHintNoParen {
|
||||
sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
|
||||
span: meta_item.span,
|
||||
name: meta_item.name_or_empty().to_ident_string(),
|
||||
});
|
||||
@ -1062,7 +1075,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
// (e.g. if we only pretty-print the source), so we have to gate
|
||||
// the `span_delayed_bug` call as follows:
|
||||
if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
|
||||
diagnostic.span_delayed_bug(item.span(), "unrecognized representation hint");
|
||||
dcx.span_delayed_bug(item.span(), "unrecognized representation hint");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1149,7 +1162,7 @@ fn allow_unstable<'a>(
|
||||
let list = attrs
|
||||
.filter_map(move |attr| {
|
||||
attr.meta_item_list().or_else(|| {
|
||||
sess.emit_err(session_diagnostics::ExpectsFeatureList {
|
||||
sess.dcx().emit_err(session_diagnostics::ExpectsFeatureList {
|
||||
span: attr.span,
|
||||
name: symbol.to_ident_string(),
|
||||
});
|
||||
@ -1161,7 +1174,7 @@ fn allow_unstable<'a>(
|
||||
list.into_iter().filter_map(move |it| {
|
||||
let name = it.ident().map(|ident| ident.name);
|
||||
if name.is_none() {
|
||||
sess.emit_err(session_diagnostics::ExpectsFeatures {
|
||||
sess.dcx().emit_err(session_diagnostics::ExpectsFeatures {
|
||||
span: it.span(),
|
||||
name: symbol.to_ident_string(),
|
||||
});
|
||||
@ -1172,9 +1185,9 @@ fn allow_unstable<'a>(
|
||||
|
||||
pub fn parse_alignment(node: &ast::LitKind) -> Result<u32, &'static str> {
|
||||
if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
|
||||
if literal.is_power_of_two() {
|
||||
if literal.get().is_power_of_two() {
|
||||
// rustc_middle::ty::layout::Align restricts align to <= 2^29
|
||||
if *literal <= 1 << 29 { Ok(*literal as u32) } else { Err("larger than 2^29") }
|
||||
if *literal <= 1 << 29 { Ok(literal.get() as u32) } else { Err("larger than 2^29") }
|
||||
} else {
|
||||
Err("not a power of two")
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ use std::num::IntErrorKind;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_errors::{
|
||||
error_code, Applicability, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
|
||||
codes::*, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level,
|
||||
};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
@ -11,14 +11,14 @@ use crate::fluent_generated as fluent;
|
||||
use crate::UnsupportedLiteralReason;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_expected_one_cfg_pattern, code = "E0536")]
|
||||
#[diag(attr_expected_one_cfg_pattern, code = E0536)]
|
||||
pub(crate) struct ExpectedOneCfgPattern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_invalid_predicate, code = "E0537")]
|
||||
#[diag(attr_invalid_predicate, code = E0537)]
|
||||
pub(crate) struct InvalidPredicate {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -27,7 +27,7 @@ pub(crate) struct InvalidPredicate {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_multiple_item, code = "E0538")]
|
||||
#[diag(attr_multiple_item, code = E0538)]
|
||||
pub(crate) struct MultipleItem {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -36,7 +36,7 @@ pub(crate) struct MultipleItem {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_incorrect_meta_item, code = "E0539")]
|
||||
#[diag(attr_incorrect_meta_item, code = E0539)]
|
||||
pub(crate) struct IncorrectMetaItem {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -50,44 +50,41 @@ pub(crate) struct UnknownMetaItem<'a> {
|
||||
}
|
||||
|
||||
// Manual implementation to be able to format `expected` items correctly.
|
||||
impl<'a> IntoDiagnostic<'a> for UnknownMetaItem<'_> {
|
||||
fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnknownMetaItem<'_> {
|
||||
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
|
||||
let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
|
||||
let mut diag = dcx.struct_span_err_with_code(
|
||||
self.span,
|
||||
fluent::attr_unknown_meta_item,
|
||||
error_code!(E0541),
|
||||
);
|
||||
diag.set_arg("item", self.item);
|
||||
diag.set_arg("expected", expected.join(", "));
|
||||
diag.span_label(self.span, fluent::attr_label);
|
||||
diag
|
||||
DiagnosticBuilder::new(dcx, level, fluent::attr_unknown_meta_item)
|
||||
.with_span(self.span)
|
||||
.with_code(E0541)
|
||||
.with_arg("item", self.item)
|
||||
.with_arg("expected", expected.join(", "))
|
||||
.with_span_label(self.span, fluent::attr_label)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_missing_since, code = "E0542")]
|
||||
#[diag(attr_missing_since, code = E0542)]
|
||||
pub(crate) struct MissingSince {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_missing_note, code = "E0543")]
|
||||
#[diag(attr_missing_note, code = E0543)]
|
||||
pub(crate) struct MissingNote {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_multiple_stability_levels, code = "E0544")]
|
||||
#[diag(attr_multiple_stability_levels, code = E0544)]
|
||||
pub(crate) struct MultipleStabilityLevels {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_invalid_issue_string, code = "E0545")]
|
||||
#[diag(attr_invalid_issue_string, code = E0545)]
|
||||
pub(crate) struct InvalidIssueString {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -145,21 +142,21 @@ impl InvalidIssueStringCause {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_missing_feature, code = "E0546")]
|
||||
#[diag(attr_missing_feature, code = E0546)]
|
||||
pub(crate) struct MissingFeature {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_non_ident_feature, code = "E0546")]
|
||||
#[diag(attr_non_ident_feature, code = E0546)]
|
||||
pub(crate) struct NonIdentFeature {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_missing_issue, code = "E0547")]
|
||||
#[diag(attr_missing_issue, code = E0547)]
|
||||
pub(crate) struct MissingIssue {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -168,14 +165,14 @@ pub(crate) struct MissingIssue {
|
||||
// FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`?
|
||||
// It is more similar to `IncorrectReprFormatGeneric`.
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")]
|
||||
#[diag(attr_incorrect_repr_format_packed_one_or_zero_arg, code = E0552)]
|
||||
pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_invalid_repr_hint_no_paren, code = "E0552")]
|
||||
#[diag(attr_invalid_repr_hint_no_paren, code = E0552)]
|
||||
pub(crate) struct InvalidReprHintNoParen {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -184,7 +181,7 @@ pub(crate) struct InvalidReprHintNoParen {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_invalid_repr_hint_no_value, code = "E0552")]
|
||||
#[diag(attr_invalid_repr_hint_no_value, code = E0552)]
|
||||
pub(crate) struct InvalidReprHintNoValue {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -200,10 +197,11 @@ pub(crate) struct UnsupportedLiteral {
|
||||
pub start_point_span: Span,
|
||||
}
|
||||
|
||||
impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral {
|
||||
fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
let mut diag = dcx.struct_span_err_with_code(
|
||||
self.span,
|
||||
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnsupportedLiteral {
|
||||
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
|
||||
let mut diag = DiagnosticBuilder::new(
|
||||
dcx,
|
||||
level,
|
||||
match self.reason {
|
||||
UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
|
||||
UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string,
|
||||
@ -214,8 +212,9 @@ impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral {
|
||||
fluent::attr_unsupported_literal_deprecated_kv_pair
|
||||
}
|
||||
},
|
||||
error_code!(E0565),
|
||||
);
|
||||
diag.span(self.span);
|
||||
diag.code(E0565);
|
||||
if self.is_bytestr {
|
||||
diag.span_suggestion(
|
||||
self.start_point_span,
|
||||
@ -229,7 +228,7 @@ impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_invalid_repr_align_need_arg, code = "E0589")]
|
||||
#[diag(attr_invalid_repr_align_need_arg, code = E0589)]
|
||||
pub(crate) struct InvalidReprAlignNeedArg {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "align(...)", applicability = "has-placeholders")]
|
||||
@ -237,7 +236,7 @@ pub(crate) struct InvalidReprAlignNeedArg {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_invalid_repr_generic, code = "E0589")]
|
||||
#[diag(attr_invalid_repr_generic, code = E0589)]
|
||||
pub(crate) struct InvalidReprGeneric<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -247,14 +246,14 @@ pub(crate) struct InvalidReprGeneric<'a> {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_incorrect_repr_format_align_one_arg, code = "E0693")]
|
||||
#[diag(attr_incorrect_repr_format_align_one_arg, code = E0693)]
|
||||
pub(crate) struct IncorrectReprFormatAlignOneArg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_incorrect_repr_format_generic, code = "E0693")]
|
||||
#[diag(attr_incorrect_repr_format_generic, code = E0693)]
|
||||
pub(crate) struct IncorrectReprFormatGeneric<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
@ -296,7 +295,7 @@ impl<'a> IncorrectReprFormatGenericCause<'a> {
|
||||
pub fn from_lit_kind(span: Span, kind: &ast::LitKind, name: &'a str) -> Option<Self> {
|
||||
match kind {
|
||||
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
|
||||
Some(Self::Int { span, name, int: *int })
|
||||
Some(Self::Int { span, name, int: int.get() })
|
||||
}
|
||||
ast::LitKind::Str(symbol, _) => Some(Self::Symbol { span, name, symbol: *symbol }),
|
||||
_ => None,
|
||||
@ -305,14 +304,14 @@ impl<'a> IncorrectReprFormatGenericCause<'a> {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_rustc_promotable_pairing, code = "E0717")]
|
||||
#[diag(attr_rustc_promotable_pairing, code = E0717)]
|
||||
pub(crate) struct RustcPromotablePairing {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_rustc_allowed_unstable_pairing, code = "E0789")]
|
||||
#[diag(attr_rustc_allowed_unstable_pairing, code = E0789)]
|
||||
pub(crate) struct RustcAllowedUnstablePairing {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
use rustc_errors::{
|
||||
struct_span_err, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
|
||||
};
|
||||
use rustc_errors::{codes::*, struct_span_code_err, DiagCtxt, DiagnosticBuilder};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
||||
impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
pub fn dcx(&self) -> &'tcx DiagCtxt {
|
||||
self.infcx.dcx()
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_move_when_borrowed(
|
||||
&self,
|
||||
span: Span,
|
||||
@ -12,8 +14,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
place: &str,
|
||||
borrow_place: &str,
|
||||
value_place: &str,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
self.infcx.tcx.sess.create_err(crate::session_diagnostics::MoveBorrow {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
self.dcx().create_err(crate::session_diagnostics::MoveBorrow {
|
||||
place,
|
||||
span,
|
||||
borrow_place,
|
||||
@ -28,18 +30,16 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
desc: &str,
|
||||
borrow_span: Span,
|
||||
borrow_desc: &str,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0503,
|
||||
"cannot use {} because it was mutably borrowed",
|
||||
desc,
|
||||
);
|
||||
|
||||
err.span_label(borrow_span, format!("{borrow_desc} is borrowed here"));
|
||||
err.span_label(span, format!("use of borrowed {borrow_desc}"));
|
||||
err
|
||||
)
|
||||
.with_span_label(borrow_span, format!("{borrow_desc} is borrowed here"))
|
||||
.with_span_label(span, format!("use of borrowed {borrow_desc}"))
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_mutably_borrow_multiply(
|
||||
@ -50,10 +50,10 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
old_loan_span: Span,
|
||||
old_opt_via: &str,
|
||||
old_load_end_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
new_loan_span,
|
||||
E0499,
|
||||
"cannot borrow {}{} as mutable more than once at a time",
|
||||
@ -97,9 +97,9 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
desc: &str,
|
||||
old_loan_span: Span,
|
||||
old_load_end_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
new_loan_span,
|
||||
E0524,
|
||||
"two closures require unique access to {} at the same time",
|
||||
@ -130,9 +130,9 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
noun_old: &str,
|
||||
old_opt_via: &str,
|
||||
previous_end_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
new_loan_span,
|
||||
E0500,
|
||||
"closure requires unique access to {} but {} is already borrowed{}",
|
||||
@ -162,9 +162,9 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
old_opt_via: &str,
|
||||
previous_end_span: Option<Span>,
|
||||
second_borrow_desc: &str,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
new_loan_span,
|
||||
E0501,
|
||||
"cannot borrow {}{} as {} because previous closure requires unique access",
|
||||
@ -194,10 +194,10 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
kind_old: &str,
|
||||
msg_old: &str,
|
||||
old_load_end_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0502,
|
||||
"cannot borrow {}{} as {} because {} is also borrowed as {}{}",
|
||||
@ -235,18 +235,16 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
span: Span,
|
||||
borrow_span: Span,
|
||||
desc: &str,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0506,
|
||||
"cannot assign to {} because it is borrowed",
|
||||
desc,
|
||||
);
|
||||
|
||||
err.span_label(borrow_span, format!("{desc} is borrowed here"));
|
||||
err.span_label(span, format!("{desc} is assigned to here but it was already borrowed"));
|
||||
err
|
||||
)
|
||||
.with_span_label(borrow_span, format!("{desc} is borrowed here"))
|
||||
.with_span_label(span, format!("{desc} is assigned to here but it was already borrowed"))
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_reassign_immutable(
|
||||
@ -254,25 +252,27 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
span: Span,
|
||||
desc: &str,
|
||||
is_arg: bool,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" };
|
||||
struct_span_err!(self, span, E0384, "cannot assign {} {}", msg, desc)
|
||||
struct_span_code_err!(self.dcx(), span, E0384, "cannot assign {} {}", msg, desc)
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_assign(
|
||||
&self,
|
||||
span: Span,
|
||||
desc: &str,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
struct_span_err!(self, span, E0594, "cannot assign to {}", desc)
|
||||
pub(crate) fn cannot_assign(&self, span: Span, desc: &str) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_code_err!(self.dcx(), span, E0594, "cannot assign to {}", desc)
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_move_out_of(
|
||||
&self,
|
||||
move_from_span: Span,
|
||||
move_from_desc: &str,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc)
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
move_from_span,
|
||||
E0507,
|
||||
"cannot move out of {}",
|
||||
move_from_desc
|
||||
)
|
||||
}
|
||||
|
||||
/// Signal an error due to an attempt to move out of the interior
|
||||
@ -283,38 +283,36 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
move_from_span: Span,
|
||||
ty: Ty<'_>,
|
||||
is_index: Option<bool>,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
let type_name = match (&ty.kind(), is_index) {
|
||||
(&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
|
||||
(&ty::Slice(_), _) => "slice",
|
||||
_ => span_bug!(move_from_span, "this path should not cause illegal move"),
|
||||
};
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
move_from_span,
|
||||
E0508,
|
||||
"cannot move out of type `{}`, a non-copy {}",
|
||||
ty,
|
||||
type_name,
|
||||
);
|
||||
err.span_label(move_from_span, "cannot move out of here");
|
||||
err
|
||||
)
|
||||
.with_span_label(move_from_span, "cannot move out of here")
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_move_out_of_interior_of_drop(
|
||||
&self,
|
||||
move_from_span: Span,
|
||||
container_ty: Ty<'_>,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
move_from_span,
|
||||
E0509,
|
||||
"cannot move out of type `{}`, which implements the `Drop` trait",
|
||||
container_ty,
|
||||
);
|
||||
err.span_label(move_from_span, "cannot move out of here");
|
||||
err
|
||||
)
|
||||
.with_span_label(move_from_span, "cannot move out of here")
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_act_on_moved_value(
|
||||
@ -323,11 +321,11 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
verb: &str,
|
||||
optional_adverb_for_moved: &str,
|
||||
moved_path: Option<String>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default();
|
||||
|
||||
struct_span_err!(
|
||||
self,
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
use_span,
|
||||
E0382,
|
||||
"{} of {}moved value{}",
|
||||
@ -342,8 +340,15 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
span: Span,
|
||||
path: &str,
|
||||
reason: &str,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,)
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0596,
|
||||
"cannot borrow {} as mutable{}",
|
||||
path,
|
||||
reason
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_mutate_in_immutable_section(
|
||||
@ -353,43 +358,41 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
immutable_place: &str,
|
||||
immutable_section: &str,
|
||||
action: &str,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
mutate_span,
|
||||
E0510,
|
||||
"cannot {} {} in {}",
|
||||
action,
|
||||
immutable_place,
|
||||
immutable_section,
|
||||
);
|
||||
err.span_label(mutate_span, format!("cannot {action}"));
|
||||
err.span_label(immutable_span, format!("value is immutable in {immutable_section}"));
|
||||
err
|
||||
)
|
||||
.with_span_label(mutate_span, format!("cannot {action}"))
|
||||
.with_span_label(immutable_span, format!("value is immutable in {immutable_section}"))
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_borrow_across_coroutine_yield(
|
||||
&self,
|
||||
span: Span,
|
||||
yield_span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind;
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0626,
|
||||
"borrow may still be in use when {coroutine_kind:#} yields",
|
||||
);
|
||||
err.span_label(yield_span, "possible yield occurs here");
|
||||
err
|
||||
)
|
||||
.with_span_label(yield_span, "possible yield occurs here")
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_borrow_across_destructor(
|
||||
&self,
|
||||
borrow_span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
struct_span_err!(
|
||||
self,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
borrow_span,
|
||||
E0713,
|
||||
"borrow may still be in use when destructor runs",
|
||||
@ -400,8 +403,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&self,
|
||||
span: Span,
|
||||
path: &str,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
struct_span_err!(self, span, E0597, "{} does not live long enough", path,)
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path,)
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_return_reference_to_local(
|
||||
@ -410,23 +413,20 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
return_kind: &str,
|
||||
reference_desc: &str,
|
||||
path_desc: &str,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0515,
|
||||
"cannot {RETURN} {REFERENCE} {LOCAL}",
|
||||
RETURN = return_kind,
|
||||
REFERENCE = reference_desc,
|
||||
LOCAL = path_desc,
|
||||
);
|
||||
|
||||
err.span_label(
|
||||
)
|
||||
.with_span_label(
|
||||
span,
|
||||
format!("{return_kind}s a {reference_desc} data owned by the current function"),
|
||||
);
|
||||
|
||||
err
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_capture_in_long_lived_closure(
|
||||
@ -436,42 +436,35 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
borrowed_path: &str,
|
||||
capture_span: Span,
|
||||
scope: &str,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
closure_span,
|
||||
E0373,
|
||||
"{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \
|
||||
which is owned by the current {scope}",
|
||||
);
|
||||
err.span_label(capture_span, format!("{borrowed_path} is borrowed here"))
|
||||
.span_label(closure_span, format!("may outlive borrowed value {borrowed_path}"));
|
||||
err
|
||||
)
|
||||
.with_span_label(capture_span, format!("{borrowed_path} is borrowed here"))
|
||||
.with_span_label(closure_span, format!("may outlive borrowed value {borrowed_path}"))
|
||||
}
|
||||
|
||||
pub(crate) fn thread_local_value_does_not_live_long_enough(
|
||||
&self,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",)
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0712,
|
||||
"thread-local variable borrowed past end of function",
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn temporary_value_borrowed_for_too_long(
|
||||
&self,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub(crate) fn struct_span_err_with_code<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
sp: S,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
code: DiagnosticId,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
self.infcx.tcx.sess.struct_span_err_with_code(sp, msg, code)
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed",)
|
||||
}
|
||||
}
|
||||
|
||||
@ -479,9 +472,9 @@ pub(crate) fn borrowed_data_escapes_closure<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
escape_span: Span,
|
||||
escapes_from: &str,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
escape_span,
|
||||
E0521,
|
||||
"borrowed data escapes outside of {}",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use rustc_infer::infer::region_constraints::Constraint;
|
||||
@ -77,7 +77,7 @@ impl<'tcx> UniverseInfo<'tcx> {
|
||||
// up in the existing UI tests. Consider investigating this
|
||||
// some more.
|
||||
mbcx.buffer_error(
|
||||
mbcx.infcx.tcx.sess.create_err(HigherRankedSubtypeError { span: cause.span }),
|
||||
mbcx.dcx().create_err(HigherRankedSubtypeError { span: cause.span }),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -147,11 +147,7 @@ impl<'tcx> ToUniverseInfo<'tcx> for ! {
|
||||
trait TypeOpInfo<'tcx> {
|
||||
/// Returns an error to be reported if rerunning the type op fails to
|
||||
/// recover the error's cause.
|
||||
fn fallback_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
|
||||
|
||||
fn base_universe(&self) -> ty::UniverseIndex;
|
||||
|
||||
@ -161,7 +157,7 @@ trait TypeOpInfo<'tcx> {
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
|
||||
) -> Option<DiagnosticBuilder<'tcx>>;
|
||||
|
||||
#[instrument(level = "debug", skip(self, mbcx))]
|
||||
fn report_error(
|
||||
@ -224,12 +220,8 @@ struct PredicateQuery<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
|
||||
fn fallback_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
tcx.sess.create_err(HigherRankedLifetimeError {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
tcx.dcx().create_err(HigherRankedLifetimeError {
|
||||
cause: Some(HigherRankedErrorCause::CouldNotProve {
|
||||
predicate: self.canonical_query.value.value.predicate.to_string(),
|
||||
}),
|
||||
@ -247,7 +239,7 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
let (infcx, key, _) =
|
||||
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
@ -265,12 +257,8 @@ impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
|
||||
where
|
||||
T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx,
|
||||
{
|
||||
fn fallback_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
tcx.sess.create_err(HigherRankedLifetimeError {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
tcx.dcx().create_err(HigherRankedLifetimeError {
|
||||
cause: Some(HigherRankedErrorCause::CouldNotNormalize {
|
||||
value: self.canonical_query.value.value.value.to_string(),
|
||||
}),
|
||||
@ -288,7 +276,7 @@ where
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
let (infcx, key, _) =
|
||||
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
@ -312,14 +300,10 @@ struct AscribeUserTypeQuery<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
||||
fn fallback_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
// FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
|
||||
// and is only the fallback when the nice error fails. Consider improving this some more.
|
||||
tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span })
|
||||
tcx.dcx().create_err(HigherRankedLifetimeError { cause: None, span })
|
||||
}
|
||||
|
||||
fn base_universe(&self) -> ty::UniverseIndex {
|
||||
@ -332,7 +316,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
let (infcx, key, _) =
|
||||
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
@ -342,14 +326,10 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
|
||||
fn fallback_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
// FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
|
||||
// and is only the fallback when the nice error fails. Consider improving this some more.
|
||||
tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span })
|
||||
tcx.dcx().create_err(HigherRankedLifetimeError { cause: None, span })
|
||||
}
|
||||
|
||||
fn base_universe(&self) -> ty::UniverseIndex {
|
||||
@ -362,7 +342,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
|
||||
_cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
try_extract_error_from_region_constraints(
|
||||
mbcx.infcx,
|
||||
placeholder_region,
|
||||
@ -383,7 +363,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
// We generally shouldn't have errors here because the query was
|
||||
// already run, but there's no point using `span_delayed_bug`
|
||||
// when we're going to emit an error here anyway.
|
||||
@ -407,14 +387,19 @@ fn try_extract_error_from_region_constraints<'tcx>(
|
||||
region_constraints: &RegionConstraintData<'tcx>,
|
||||
mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
|
||||
mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
let placeholder_universe = match placeholder_region.kind() {
|
||||
ty::RePlaceholder(p) => p.universe,
|
||||
ty::ReVar(vid) => universe_of_region(vid),
|
||||
_ => ty::UniverseIndex::ROOT,
|
||||
};
|
||||
let matches =
|
||||
|a_region: Region<'tcx>, b_region: Region<'tcx>| match (a_region.kind(), b_region.kind()) {
|
||||
(RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound,
|
||||
_ => a_region == b_region,
|
||||
};
|
||||
let check = |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| {
|
||||
match *constraint {
|
||||
let mut check =
|
||||
|constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match *constraint {
|
||||
Constraint::RegSubReg(sub, sup)
|
||||
if ((exact && sup == placeholder_region)
|
||||
|| (!exact && matches(sup, placeholder_region)))
|
||||
@ -422,15 +407,15 @@ fn try_extract_error_from_region_constraints<'tcx>(
|
||||
{
|
||||
Some((sub, cause.clone()))
|
||||
}
|
||||
// FIXME: Should this check the universe of the var?
|
||||
Constraint::VarSubReg(vid, sup)
|
||||
if ((exact && sup == placeholder_region)
|
||||
|| (!exact && matches(sup, placeholder_region))) =>
|
||||
if (exact
|
||||
&& sup == placeholder_region
|
||||
&& !universe_of_region(vid).can_name(placeholder_universe))
|
||||
|| (!exact && matches(sup, placeholder_region)) =>
|
||||
{
|
||||
Some((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
let mut info = region_constraints
|
||||
.constraints
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
// ignore-tidy-filelength
|
||||
|
||||
use either::Either;
|
||||
use hir::PatField;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{
|
||||
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
|
||||
codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
|
||||
use rustc_hir::{CoroutineDesugaring, PatField};
|
||||
use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
@ -26,6 +28,7 @@ use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::{BytePos, Span, Symbol};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
use std::iter;
|
||||
|
||||
@ -324,7 +327,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&mut self,
|
||||
mpi: MovePathIndex,
|
||||
move_span: Span,
|
||||
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
in_pattern: &mut bool,
|
||||
move_spans: UseSpans<'_>,
|
||||
) {
|
||||
@ -483,8 +486,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
desired_action: InitializationRequiringAction,
|
||||
span: Span,
|
||||
use_spans: UseSpans<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
// We need all statements in the body where the binding was assigned to to later find all
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
// We need all statements in the body where the binding was assigned to later find all
|
||||
// the branching code paths where the binding *wasn't* assigned to.
|
||||
let inits = &self.move_data.init_path_map[mpi];
|
||||
let move_path = &self.move_data.move_paths[mpi];
|
||||
@ -552,8 +555,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
};
|
||||
|
||||
let used = desired_action.as_general_verb_in_past_tense();
|
||||
let mut err =
|
||||
struct_span_err!(self, span, E0381, "{used} binding {desc}{isnt_initialized}");
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0381,
|
||||
"{used} binding {desc}{isnt_initialized}"
|
||||
);
|
||||
use_spans.var_path_only_subdiag(&mut err, desired_action);
|
||||
|
||||
if let InitializationRequiringAction::PartialAssignment
|
||||
@ -850,8 +857,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
move_spans.var_subdiag(None, &mut err, None, |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
Some(_) => MoveUseInCoroutine { var_span },
|
||||
None => MoveUseInClosure { var_span },
|
||||
hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span },
|
||||
hir::ClosureKind::Closure => MoveUseInClosure { var_span },
|
||||
}
|
||||
});
|
||||
|
||||
@ -873,7 +880,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
location: Location,
|
||||
(place, _span): (Place<'tcx>, Span),
|
||||
borrow: &BorrowData<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
||||
let borrow_span = borrow_spans.args_or_use();
|
||||
|
||||
@ -895,10 +902,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let place = &borrow.borrowed_place;
|
||||
let desc_place = self.describe_any_place(place.as_ref());
|
||||
match kind {
|
||||
Some(_) => {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true }
|
||||
}
|
||||
None => BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true },
|
||||
hir::ClosureKind::Closure => {
|
||||
BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -921,7 +930,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
(place, span): (Place<'tcx>, Span),
|
||||
gen_borrow_kind: BorrowKind,
|
||||
issued_borrow: &BorrowData<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
let issued_spans = self.retrieve_borrow_spans(issued_borrow);
|
||||
let issued_span = issued_spans.args_or_use();
|
||||
|
||||
@ -1042,12 +1051,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
Some(_) => BorrowUsePlaceCoroutine {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: true,
|
||||
},
|
||||
None => BorrowUsePlaceClosure {
|
||||
hir::ClosureKind::Closure => BorrowUsePlaceClosure {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: true,
|
||||
@ -1126,19 +1135,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
borrow_spans.var_subdiag(None, &mut err, Some(gen_borrow_kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
Some(_) => BorrowUsePlaceCoroutine {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: false,
|
||||
},
|
||||
None => {
|
||||
hir::ClosureKind::Closure => {
|
||||
BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false }
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
issued_spans.var_subdiag(
|
||||
Some(self.infcx.tcx.sess.dcx()),
|
||||
Some(self.dcx()),
|
||||
&mut err,
|
||||
Some(issued_borrow.kind),
|
||||
|kind, var_span| {
|
||||
@ -1146,23 +1155,29 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let borrow_place = &issued_borrow.borrowed_place;
|
||||
let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
|
||||
match kind {
|
||||
Some(_) => {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span }
|
||||
}
|
||||
None => FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span },
|
||||
hir::ClosureKind::Closure => {
|
||||
FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span }
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
borrow_spans.var_subdiag(
|
||||
Some(self.infcx.tcx.sess.dcx()),
|
||||
Some(self.dcx()),
|
||||
&mut err,
|
||||
Some(gen_borrow_kind),
|
||||
|kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
Some(_) => SecondBorrowUsePlaceCoroutine { place: desc_place, var_span },
|
||||
None => SecondBorrowUsePlaceClosure { place: desc_place, var_span },
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
SecondBorrowUsePlaceCoroutine { place: desc_place, var_span }
|
||||
}
|
||||
hir::ClosureKind::Closure => {
|
||||
SecondBorrowUsePlaceClosure { place: desc_place, var_span }
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
@ -1245,7 +1260,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
return None;
|
||||
};
|
||||
debug!("checking call args for uses of inner_param: {:?}", args);
|
||||
args.contains(&Operand::Move(inner_param)).then_some((loc, term))
|
||||
args.iter()
|
||||
.map(|a| &a.node)
|
||||
.any(|a| a == &Operand::Move(inner_param))
|
||||
.then_some((loc, term))
|
||||
})
|
||||
else {
|
||||
debug!("no uses of inner_param found as a by-move call arg");
|
||||
@ -1289,14 +1307,96 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
place: Place<'tcx>,
|
||||
borrowed_place: Place<'tcx>,
|
||||
) {
|
||||
if let ([ProjectionElem::Index(_)], [ProjectionElem::Index(_)]) =
|
||||
(&place.projection[..], &borrowed_place.projection[..])
|
||||
let tcx = self.infcx.tcx;
|
||||
let hir = tcx.hir();
|
||||
|
||||
if let ([ProjectionElem::Index(index1)], [ProjectionElem::Index(index2)])
|
||||
| (
|
||||
[ProjectionElem::Deref, ProjectionElem::Index(index1)],
|
||||
[ProjectionElem::Deref, ProjectionElem::Index(index2)],
|
||||
) = (&place.projection[..], &borrowed_place.projection[..])
|
||||
{
|
||||
let mut note_default_suggestion = || {
|
||||
err.help(
|
||||
"consider using `.split_at_mut(position)` or similar method to obtain \
|
||||
two mutable non-overlapping sub-slices",
|
||||
)
|
||||
.help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices");
|
||||
};
|
||||
|
||||
let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
let mut expr_finder =
|
||||
FindExprBySpan::new(self.body.local_decls[*index1].source_info.span);
|
||||
expr_finder.visit_expr(hir.body(body_id).value);
|
||||
let Some(index1) = expr_finder.result else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
expr_finder = FindExprBySpan::new(self.body.local_decls[*index2].source_info.span);
|
||||
expr_finder.visit_expr(hir.body(body_id).value);
|
||||
let Some(index2) = expr_finder.result else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
let sm = tcx.sess.source_map();
|
||||
|
||||
let Ok(index1_str) = sm.span_to_snippet(index1.span) else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok(index2_str) = sm.span_to_snippet(index2.span) else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(object) = hir.parent_id_iter(index1.hir_id).find_map(|id| {
|
||||
if let hir::Node::Expr(expr) = tcx.hir_node(id)
|
||||
&& let hir::ExprKind::Index(obj, ..) = expr.kind
|
||||
{
|
||||
Some(obj)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok(obj_str) = sm.span_to_snippet(object.span) else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(swap_call) = hir.parent_id_iter(object.hir_id).find_map(|id| {
|
||||
if let hir::Node::Expr(call) = tcx.hir_node(id)
|
||||
&& let hir::ExprKind::Call(callee, ..) = call.kind
|
||||
&& let hir::ExprKind::Path(qpath) = callee.kind
|
||||
&& let hir::QPath::Resolved(None, res) = qpath
|
||||
&& let hir::def::Res::Def(_, did) = res.res
|
||||
&& tcx.is_diagnostic_item(sym::mem_swap, did)
|
||||
{
|
||||
Some(call)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
err.span_suggestion(
|
||||
swap_call.span,
|
||||
"use `.swap()` to swap elements at the specified indices instead",
|
||||
format!("{obj_str}.swap({index1_str}, {index2_str})"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1653,7 +1753,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
||||
if e.span.contains(self.capture_span) {
|
||||
if let hir::ExprKind::Closure(&hir::Closure {
|
||||
movability: None,
|
||||
kind: hir::ClosureKind::Closure,
|
||||
body,
|
||||
fn_arg_span,
|
||||
fn_decl: hir::FnDecl { inputs, .. },
|
||||
@ -1688,7 +1788,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&& let Some(init) = local.init
|
||||
{
|
||||
if let hir::Expr {
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { movability: None, .. }),
|
||||
kind:
|
||||
hir::ExprKind::Closure(&hir::Closure {
|
||||
kind: hir::ClosureKind::Closure,
|
||||
..
|
||||
}),
|
||||
..
|
||||
} = init
|
||||
&& init.span.contains(self.capture_span)
|
||||
@ -2025,7 +2129,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
drop_span: Span,
|
||||
borrow_spans: UseSpans<'tcx>,
|
||||
explanation: BorrowExplanation<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
debug!(
|
||||
"report_local_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}, {:?}, {:?}, {:?}\
|
||||
@ -2200,7 +2304,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&mut self,
|
||||
drop_span: Span,
|
||||
borrow_span: Span,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
debug!(
|
||||
"report_thread_local_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}\
|
||||
@ -2208,15 +2312,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
drop_span, borrow_span
|
||||
);
|
||||
|
||||
let mut err = self.thread_local_value_does_not_live_long_enough(borrow_span);
|
||||
|
||||
err.span_label(
|
||||
self.thread_local_value_does_not_live_long_enough(borrow_span)
|
||||
.with_span_label(
|
||||
borrow_span,
|
||||
"thread-local variables cannot be borrowed beyond the end of the function",
|
||||
);
|
||||
err.span_label(drop_span, "end of enclosing function is here");
|
||||
|
||||
err
|
||||
)
|
||||
.with_span_label(drop_span, "end of enclosing function is here")
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
@ -2228,7 +2329,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
borrow_spans: UseSpans<'tcx>,
|
||||
proper_span: Span,
|
||||
explanation: BorrowExplanation<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
|
||||
explanation
|
||||
{
|
||||
@ -2395,7 +2496,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
return_span: Span,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
opt_place_desc: Option<&String>,
|
||||
) -> Option<DiagnosticBuilder<'cx, ErrorGuaranteed>> {
|
||||
) -> Option<DiagnosticBuilder<'cx>> {
|
||||
let return_kind = match category {
|
||||
ConstraintCategory::Return(_) => "return",
|
||||
ConstraintCategory::Yield => "yield",
|
||||
@ -2490,7 +2591,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
constraint_span: Span,
|
||||
captured_var: &str,
|
||||
scope: &str,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let args_span = use_span.args_or_use();
|
||||
|
||||
@ -2516,28 +2617,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
};
|
||||
let kind = match use_span.coroutine_kind() {
|
||||
Some(coroutine_kind) => match coroutine_kind {
|
||||
CoroutineKind::Gen(kind) => match kind {
|
||||
CoroutineKind::Desugared(CoroutineDesugaring::Gen, kind) => match kind {
|
||||
CoroutineSource::Block => "gen block",
|
||||
CoroutineSource::Closure => "gen closure",
|
||||
CoroutineSource::Fn => {
|
||||
bug!("gen block/closure expected, but gen function found.")
|
||||
}
|
||||
},
|
||||
CoroutineKind::AsyncGen(kind) => match kind {
|
||||
CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, kind) => match kind {
|
||||
CoroutineSource::Block => "async gen block",
|
||||
CoroutineSource::Closure => "async gen closure",
|
||||
CoroutineSource::Fn => {
|
||||
bug!("gen block/closure expected, but gen function found.")
|
||||
}
|
||||
},
|
||||
CoroutineKind::Async(async_kind) => match async_kind {
|
||||
CoroutineKind::Desugared(CoroutineDesugaring::Async, async_kind) => {
|
||||
match async_kind {
|
||||
CoroutineSource::Block => "async block",
|
||||
CoroutineSource::Closure => "async closure",
|
||||
CoroutineSource::Fn => {
|
||||
bug!("async block/closure expected, but async function found.")
|
||||
}
|
||||
},
|
||||
CoroutineKind::Coroutine => "coroutine",
|
||||
}
|
||||
}
|
||||
CoroutineKind::Coroutine(_) => "coroutine",
|
||||
},
|
||||
None => "closure",
|
||||
};
|
||||
@ -2566,7 +2669,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
ConstraintCategory::CallArgument(_) => {
|
||||
fr_name.highlight_region_name(&mut err);
|
||||
if matches!(use_span.coroutine_kind(), Some(CoroutineKind::Async(_))) {
|
||||
if matches!(
|
||||
use_span.coroutine_kind(),
|
||||
Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, _))
|
||||
) {
|
||||
err.note(
|
||||
"async blocks are not executed immediately and must either take a \
|
||||
reference or ownership of outside variables they use",
|
||||
@ -2593,7 +2699,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
upvar_span: Span,
|
||||
upvar_name: Symbol,
|
||||
escape_span: Span,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
let escapes_from = tcx.def_descr(self.mir_def_id().to_def_id());
|
||||
@ -2835,8 +2941,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
Some(_) => BorrowUseInCoroutine { var_span },
|
||||
None => BorrowUseInClosure { var_span },
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
|
||||
hir::ClosureKind::Closure => BorrowUseInClosure { var_span },
|
||||
}
|
||||
});
|
||||
|
||||
@ -2851,8 +2957,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
Some(_) => BorrowUseInCoroutine { var_span },
|
||||
None => BorrowUseInClosure { var_span },
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
|
||||
hir::ClosureKind::Closure => BorrowUseInClosure { var_span },
|
||||
}
|
||||
});
|
||||
|
||||
@ -3052,7 +3158,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
|
||||
// Define a fallback for when we can't match a closure.
|
||||
let fallback = || {
|
||||
let is_closure = self.infcx.tcx.is_closure(self.mir_def_id().to_def_id());
|
||||
let is_closure = self.infcx.tcx.is_closure_or_coroutine(self.mir_def_id().to_def_id());
|
||||
if is_closure {
|
||||
None
|
||||
} else {
|
||||
@ -3224,7 +3330,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
assigned_to, args
|
||||
);
|
||||
for operand in args {
|
||||
let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand
|
||||
let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) =
|
||||
&operand.node
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
@ -3262,7 +3369,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
sig: ty::PolyFnSig<'tcx>,
|
||||
) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
|
||||
debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
|
||||
let is_closure = self.infcx.tcx.is_closure(did.to_def_id());
|
||||
let is_closure = self.infcx.tcx.is_closure_or_coroutine(did.to_def_id());
|
||||
let fn_hir_id = self.infcx.tcx.local_def_id_to_hir_id(did);
|
||||
let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
|
||||
|
||||
@ -3575,7 +3682,7 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
|
||||
));
|
||||
} else if let Some(guard) = &arm.guard {
|
||||
self.errors.push((
|
||||
arm.pat.span.to(guard.body().span),
|
||||
arm.pat.span.to(guard.span),
|
||||
format!(
|
||||
"if this pattern and condition are matched, {} is not \
|
||||
initialized",
|
||||
|
||||
@ -315,7 +315,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
let mut failed = false;
|
||||
|
||||
let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| {
|
||||
if let Some(ty::Dynamic(obj, _, ty::DynKind::Dyn)) = arg.as_type().map(Ty::kind) {
|
||||
if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) {
|
||||
let default = tcx.object_lifetime_default(param.def_id);
|
||||
|
||||
let re_static = tcx.lifetimes.re_static;
|
||||
@ -339,7 +339,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
|
||||
has_dyn = true;
|
||||
|
||||
Ty::new_dynamic(tcx, obj, implied_region, ty::DynKind::Dyn).into()
|
||||
Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into()
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
@ -691,7 +691,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
);
|
||||
// Check if one of the arguments to this function is the target place.
|
||||
let found_target = args.iter().any(|arg| {
|
||||
if let Operand::Move(place) = arg {
|
||||
if let Operand::Move(place) = arg.node {
|
||||
if let Some(potential) = place.as_local() {
|
||||
potential == target
|
||||
} else {
|
||||
|
||||
@ -23,6 +23,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
use rustc_middle::util::{call_kind, CallDesugaringKind};
|
||||
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
|
||||
use rustc_target::abi::{FieldIdx, VariantIdx};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
@ -111,9 +112,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
debug!("add_moved_or_invoked_closure_note: id={:?}", id);
|
||||
if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() {
|
||||
let closure = match args.first() {
|
||||
Some(Operand::Copy(place) | Operand::Move(place))
|
||||
if target == place.local_or_deref_local() =>
|
||||
{
|
||||
Some(Spanned {
|
||||
node: Operand::Copy(place) | Operand::Move(place), ..
|
||||
}) if target == place.local_or_deref_local() => {
|
||||
place.local_or_deref_local().unwrap()
|
||||
}
|
||||
_ => return false,
|
||||
@ -124,7 +125,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let did = did.expect_local();
|
||||
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
||||
diag.eager_subdiagnostic(
|
||||
self.infcx.tcx.sess.dcx(),
|
||||
self.dcx(),
|
||||
OnClosureNote::InvokedTwice {
|
||||
place_name: &ty::place_to_string_for_capture(
|
||||
self.infcx.tcx,
|
||||
@ -146,7 +147,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let did = did.expect_local();
|
||||
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
||||
diag.eager_subdiagnostic(
|
||||
self.infcx.tcx.sess.dcx(),
|
||||
self.dcx(),
|
||||
OnClosureNote::MovedTwice {
|
||||
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
|
||||
span: *span,
|
||||
@ -370,7 +371,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
ty::Array(ty, _) | ty::Slice(ty) => {
|
||||
self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
|
||||
}
|
||||
ty::Closure(def_id, _) | ty::Coroutine(def_id, _, _) => {
|
||||
ty::Closure(def_id, _) | ty::Coroutine(def_id, _) => {
|
||||
// We won't be borrowck'ing here if the closure came from another crate,
|
||||
// so it's safe to call `expect_local`.
|
||||
//
|
||||
@ -505,7 +506,7 @@ pub(super) enum UseSpans<'tcx> {
|
||||
/// The access is caused by capturing a variable for a closure.
|
||||
ClosureUse {
|
||||
/// This is true if the captured variable was from a coroutine.
|
||||
coroutine_kind: Option<CoroutineKind>,
|
||||
closure_kind: hir::ClosureKind,
|
||||
/// The span of the args of the closure, including the `move` keyword if
|
||||
/// it's present.
|
||||
args_span: Span,
|
||||
@ -572,9 +573,13 @@ impl UseSpans<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(coroutines): Make this just return the `ClosureKind` directly?
|
||||
pub(super) fn coroutine_kind(self) -> Option<CoroutineKind> {
|
||||
match self {
|
||||
UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind,
|
||||
UseSpans::ClosureUse {
|
||||
closure_kind: hir::ClosureKind::Coroutine(coroutine_kind),
|
||||
..
|
||||
} => Some(coroutine_kind),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -599,9 +604,9 @@ impl UseSpans<'_> {
|
||||
) {
|
||||
use crate::InitializationRequiringAction::*;
|
||||
use CaptureVarPathUseCause::*;
|
||||
if let UseSpans::ClosureUse { coroutine_kind, path_span, .. } = self {
|
||||
match coroutine_kind {
|
||||
Some(_) => {
|
||||
if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self {
|
||||
match closure_kind {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
err.subdiagnostic(match action {
|
||||
Borrow => BorrowInCoroutine { path_span },
|
||||
MatchOn | Use => UseInCoroutine { path_span },
|
||||
@ -609,7 +614,7 @@ impl UseSpans<'_> {
|
||||
PartialAssignment => AssignPartInCoroutine { path_span },
|
||||
});
|
||||
}
|
||||
None => {
|
||||
hir::ClosureKind::Closure => {
|
||||
err.subdiagnostic(match action {
|
||||
Borrow => BorrowInClosure { path_span },
|
||||
MatchOn | Use => UseInClosure { path_span },
|
||||
@ -627,9 +632,9 @@ impl UseSpans<'_> {
|
||||
dcx: Option<&rustc_errors::DiagCtxt>,
|
||||
err: &mut Diagnostic,
|
||||
kind: Option<rustc_middle::mir::BorrowKind>,
|
||||
f: impl FnOnce(Option<CoroutineKind>, Span) -> CaptureVarCause,
|
||||
f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
|
||||
) {
|
||||
if let UseSpans::ClosureUse { coroutine_kind, capture_kind_span, path_span, .. } = self {
|
||||
if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self {
|
||||
if capture_kind_span != path_span {
|
||||
err.subdiagnostic(match kind {
|
||||
Some(kd) => match kd {
|
||||
@ -645,7 +650,7 @@ impl UseSpans<'_> {
|
||||
None => CaptureVarKind::Move { kind_span: capture_kind_span },
|
||||
});
|
||||
};
|
||||
let diag = f(coroutine_kind, path_span);
|
||||
let diag = f(closure_kind, path_span);
|
||||
match dcx {
|
||||
Some(hd) => err.eager_subdiagnostic(hd, diag),
|
||||
None => err.subdiagnostic(diag),
|
||||
@ -656,7 +661,9 @@ impl UseSpans<'_> {
|
||||
/// Returns `false` if this place is not used in a closure.
|
||||
pub(super) fn for_closure(&self) -> bool {
|
||||
match *self {
|
||||
UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind.is_none(),
|
||||
UseSpans::ClosureUse { closure_kind, .. } => {
|
||||
matches!(closure_kind, hir::ClosureKind::Closure)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -664,7 +671,10 @@ impl UseSpans<'_> {
|
||||
/// Returns `false` if this place is not used in a coroutine.
|
||||
pub(super) fn for_coroutine(&self) -> bool {
|
||||
match *self {
|
||||
UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind.is_some(),
|
||||
// FIXME(coroutines): Do we want this to apply to synthetic coroutines?
|
||||
UseSpans::ClosureUse { closure_kind, .. } => {
|
||||
matches!(closure_kind, hir::ClosureKind::Coroutine(..))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -783,15 +793,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
|
||||
if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind
|
||||
&& let AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _, _) =
|
||||
**kind
|
||||
&& let AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) = **kind
|
||||
{
|
||||
debug!("move_spans: def_id={:?} places={:?}", def_id, places);
|
||||
let def_id = def_id.expect_local();
|
||||
if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) =
|
||||
if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
|
||||
self.closure_span(def_id, moved_place, places)
|
||||
{
|
||||
return ClosureUse { coroutine_kind, args_span, capture_kind_span, path_span };
|
||||
return ClosureUse { closure_kind, args_span, capture_kind_span, path_span };
|
||||
}
|
||||
}
|
||||
|
||||
@ -803,11 +812,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
| FakeReadCause::ForLet(Some(closure_def_id)) => {
|
||||
debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
|
||||
let places = &[Operand::Move(place)];
|
||||
if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) =
|
||||
if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
|
||||
self.closure_span(closure_def_id, moved_place, IndexSlice::from_raw(places))
|
||||
{
|
||||
return ClosureUse {
|
||||
coroutine_kind,
|
||||
closure_kind,
|
||||
args_span,
|
||||
capture_kind_span,
|
||||
path_span,
|
||||
@ -919,7 +928,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind {
|
||||
let (&def_id, is_coroutine) = match kind {
|
||||
box AggregateKind::Closure(def_id, _) => (def_id, false),
|
||||
box AggregateKind::Coroutine(def_id, _, _) => (def_id, true),
|
||||
box AggregateKind::Coroutine(def_id, _) => (def_id, true),
|
||||
_ => continue,
|
||||
};
|
||||
let def_id = def_id.expect_local();
|
||||
@ -928,10 +937,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
"borrow_spans: def_id={:?} is_coroutine={:?} places={:?}",
|
||||
def_id, is_coroutine, places
|
||||
);
|
||||
if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) =
|
||||
if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
|
||||
self.closure_span(def_id, Place::from(target).as_ref(), places)
|
||||
{
|
||||
return ClosureUse { coroutine_kind, args_span, capture_kind_span, path_span };
|
||||
return ClosureUse { closure_kind, args_span, capture_kind_span, path_span };
|
||||
} else {
|
||||
return OtherUse(use_span);
|
||||
}
|
||||
@ -953,7 +962,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
def_id: LocalDefId,
|
||||
target_place: PlaceRef<'tcx>,
|
||||
places: &IndexSlice<FieldIdx, Operand<'tcx>>,
|
||||
) -> Option<(Span, Option<CoroutineKind>, Span, Span)> {
|
||||
) -> Option<(Span, hir::ClosureKind, Span, Span)> {
|
||||
debug!(
|
||||
"closure_span: def_id={:?} target_place={:?} places={:?}",
|
||||
def_id, target_place, places
|
||||
@ -961,7 +970,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id);
|
||||
let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
|
||||
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr {
|
||||
if let hir::ExprKind::Closure(&hir::Closure { kind, fn_decl_span, .. }) = expr {
|
||||
for (captured_place, place) in
|
||||
self.infcx.tcx.closure_captures(def_id).iter().zip(places)
|
||||
{
|
||||
@ -970,12 +979,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
if target_place == place.as_ref() =>
|
||||
{
|
||||
debug!("closure_span: found captured local {:?}", place);
|
||||
let body = self.infcx.tcx.hir().body(body);
|
||||
let coroutine_kind = body.coroutine_kind();
|
||||
|
||||
return Some((
|
||||
fn_decl_span,
|
||||
coroutine_kind,
|
||||
kind,
|
||||
captured_place.get_capture_kind_span(self.infcx.tcx),
|
||||
captured_place.get_path_span(self.infcx.tcx),
|
||||
));
|
||||
@ -1150,7 +1156,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&& self.infcx.can_eq(self.param_env, ty, self_ty)
|
||||
{
|
||||
err.eager_subdiagnostic(
|
||||
self.infcx.tcx.sess.dcx(),
|
||||
self.dcx(),
|
||||
CaptureReasonSuggest::FreshReborrow {
|
||||
span: move_span.shrink_to_hi(),
|
||||
},
|
||||
@ -1173,9 +1179,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
} else {
|
||||
vec![(move_span.shrink_to_hi(), ".clone()".to_string())]
|
||||
};
|
||||
if let Some(errors) =
|
||||
self.infcx.could_impl_trait(clone_trait, ty, self.param_env)
|
||||
&& !has_sugg
|
||||
if let Some(errors) = self.infcx.type_implements_trait_shallow(
|
||||
clone_trait,
|
||||
ty,
|
||||
self.param_env,
|
||||
) && !has_sugg
|
||||
{
|
||||
let msg = match &errors[..] {
|
||||
[] => "you can `clone` the value and consume it, but this \
|
||||
@ -1208,7 +1216,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
for error in errors {
|
||||
if let FulfillmentErrorCode::CodeSelectionError(
|
||||
if let FulfillmentErrorCode::SelectionError(
|
||||
SelectionError::Unimplemented,
|
||||
) = error.code
|
||||
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
|
||||
@ -1242,8 +1250,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
// another message for the same span
|
||||
if !is_loop_message {
|
||||
move_spans.var_subdiag(None, err, None, |kind, var_span| match kind {
|
||||
Some(_) => CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial },
|
||||
None => CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial },
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial }
|
||||
}
|
||||
hir::ClosureKind::Closure => {
|
||||
CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
|
||||
@ -288,7 +288,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
&mut self,
|
||||
place: Place<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
let description = if place.projection.len() == 1 {
|
||||
format!("static item {}", self.describe_any_place(place.as_ref()))
|
||||
} else {
|
||||
@ -310,7 +310,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
deref_target_place: Place<'tcx>,
|
||||
span: Span,
|
||||
use_spans: Option<UseSpans<'tcx>>,
|
||||
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
// Inspect the type of the content behind the
|
||||
// borrow to provide feedback about why this
|
||||
// was a move rather than a copy.
|
||||
@ -329,15 +329,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
if let PlaceRef { local, projection: [] } = deref_base {
|
||||
let decl = &self.body.local_decls[local];
|
||||
if decl.is_ref_for_guard() {
|
||||
let mut err = self.cannot_move_out_of(
|
||||
return self
|
||||
.cannot_move_out_of(
|
||||
span,
|
||||
&format!("`{}` in pattern guard", self.local_names[local].unwrap()),
|
||||
);
|
||||
err.note(
|
||||
)
|
||||
.with_note(
|
||||
"variables bound in patterns cannot be moved from \
|
||||
until after the end of the pattern guard",
|
||||
);
|
||||
return err;
|
||||
} else if decl.is_ref_to_static() {
|
||||
return self.report_cannot_move_from_static(move_place, span);
|
||||
}
|
||||
@ -381,15 +381,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
closure_kind_ty, closure_kind, place_description,
|
||||
);
|
||||
|
||||
let mut diag = self.cannot_move_out_of(span, &place_description);
|
||||
|
||||
diag.span_label(upvar_span, "captured outer variable");
|
||||
diag.span_label(
|
||||
self.cannot_move_out_of(span, &place_description)
|
||||
.with_span_label(upvar_span, "captured outer variable")
|
||||
.with_span_label(
|
||||
self.infcx.tcx.def_span(def_id),
|
||||
format!("captured by this `{closure_kind}` closure"),
|
||||
);
|
||||
|
||||
diag
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
let source = self.borrowed_content_source(deref_base);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use hir::ExprKind;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::Node;
|
||||
@ -711,7 +711,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
fn construct_mut_suggestion_for_local_binding_patterns(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
local: Local,
|
||||
) {
|
||||
let local_decl = &self.body.local_decls[local];
|
||||
@ -1025,13 +1025,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_using_iter_mut(&self, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>) {
|
||||
fn suggest_using_iter_mut(&self, err: &mut DiagnosticBuilder<'_>) {
|
||||
let source = self.body.source;
|
||||
let hir = self.infcx.tcx.hir();
|
||||
if let InstanceDef::Item(def_id) = source.instance
|
||||
&& let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id)
|
||||
&& let ExprKind::Closure(closure) = kind
|
||||
&& closure.movability == None
|
||||
&& let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind
|
||||
&& let Some(Node::Expr(expr)) = hir.find_parent(*hir_id)
|
||||
{
|
||||
let mut cur_expr = expr;
|
||||
@ -1067,12 +1066,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_make_local_mut(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
|
||||
local: Local,
|
||||
name: Symbol,
|
||||
) {
|
||||
fn suggest_make_local_mut(&self, err: &mut DiagnosticBuilder<'_>, local: Local, name: Symbol) {
|
||||
let local_decl = &self.body.local_decls[local];
|
||||
|
||||
let (pointer_sigil, pointer_desc) =
|
||||
@ -1223,19 +1217,22 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
{
|
||||
match self
|
||||
.infcx
|
||||
.could_impl_trait(clone_trait, ty.peel_refs(), self.param_env)
|
||||
.type_implements_trait_shallow(
|
||||
clone_trait,
|
||||
ty.peel_refs(),
|
||||
self.param_env,
|
||||
)
|
||||
.as_deref()
|
||||
{
|
||||
Some([]) => {
|
||||
// The type implements Clone.
|
||||
err.span_help(
|
||||
expr.span,
|
||||
format!(
|
||||
"you can `clone` the `{}` value and consume it, but this \
|
||||
might not be your desired behavior",
|
||||
ty.peel_refs(),
|
||||
),
|
||||
);
|
||||
// FIXME: This error message isn't useful, since we're just
|
||||
// vaguely suggesting to clone a value that already
|
||||
// implements `Clone`.
|
||||
//
|
||||
// A correct suggestion here would take into account the fact
|
||||
// that inference may be affected by missing types on bindings,
|
||||
// etc., to improve "tests/ui/borrowck/issue-91206.stderr", for
|
||||
// example.
|
||||
}
|
||||
None => {
|
||||
if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) =
|
||||
@ -1294,7 +1291,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
// The type doesn't implement Clone because of unmet obligations.
|
||||
for error in errors {
|
||||
if let traits::FulfillmentErrorCode::CodeSelectionError(
|
||||
if let traits::FulfillmentErrorCode::SelectionError(
|
||||
traits::SelectionError::Unimplemented,
|
||||
) = error.code
|
||||
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
|
||||
|
||||
@ -206,7 +206,7 @@ impl OutlivesSuggestionBuilder {
|
||||
// If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a
|
||||
// list of diagnostics.
|
||||
let mut diag = if suggested.len() == 1 {
|
||||
mbcx.infcx.tcx.sess.dcx().struct_help(match suggested.last().unwrap() {
|
||||
mbcx.dcx().struct_help(match suggested.last().unwrap() {
|
||||
SuggestedConstraint::Outlives(a, bs) => {
|
||||
let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
|
||||
format!("add bound `{a}: {}`", bs.join(" + "))
|
||||
@ -222,7 +222,6 @@ impl OutlivesSuggestionBuilder {
|
||||
let mut diag = mbcx
|
||||
.infcx
|
||||
.tcx
|
||||
.sess
|
||||
.dcx()
|
||||
.struct_help("the following changes may resolve your lifetime errors");
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
//! Error reporting machinery for lifetime errors.
|
||||
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res::Def;
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -27,7 +27,7 @@ use rustc_middle::ty::TypeVisitor;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty};
|
||||
use rustc_middle::ty::{Region, TyCtxt};
|
||||
use rustc_span::symbol::{kw, Ident};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::borrowck_errors;
|
||||
use crate::session_diagnostics::{
|
||||
@ -84,7 +84,7 @@ impl<'tcx> RegionErrors<'tcx> {
|
||||
#[track_caller]
|
||||
pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) {
|
||||
let val = val.into();
|
||||
self.1.sess.span_delayed_bug(DUMMY_SP, format!("{val:?}"));
|
||||
self.1.sess.dcx().delayed_bug(format!("{val:?}"));
|
||||
self.0.push(val);
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
@ -202,7 +202,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
// and the span which bounded to the trait for adding 'static lifetime suggestion
|
||||
fn suggest_static_lifetime_for_gat_from_hrtb(
|
||||
&self,
|
||||
diag: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
|
||||
diag: &mut DiagnosticBuilder<'_>,
|
||||
lower_bound: RegionVid,
|
||||
) {
|
||||
let mut suggestions = vec![];
|
||||
@ -327,8 +327,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
// to report it; we could probably handle it by
|
||||
// iterating over the universal regions and reporting
|
||||
// an error that multiple bounds are required.
|
||||
let mut diag =
|
||||
self.infcx.tcx.sess.create_err(GenericDoesNotLiveLongEnough {
|
||||
let mut diag = self.dcx().create_err(GenericDoesNotLiveLongEnough {
|
||||
kind: type_test.generic_kind.to_string(),
|
||||
span: type_test_span,
|
||||
});
|
||||
@ -349,7 +348,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
|
||||
let named_key = self.regioncx.name_regions(self.infcx.tcx, key);
|
||||
let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
|
||||
let mut diag = unexpected_hidden_region_diagnostic(
|
||||
let diag = unexpected_hidden_region_diagnostic(
|
||||
self.infcx.tcx,
|
||||
span,
|
||||
named_ty,
|
||||
@ -573,7 +572,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
&self,
|
||||
errci: &ErrorConstraintInfo<'tcx>,
|
||||
kind: ReturnConstraint,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
|
||||
|
||||
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
|
||||
@ -596,7 +595,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
},
|
||||
};
|
||||
|
||||
let mut diag = self.infcx.tcx.sess.create_err(err);
|
||||
let mut diag = self.dcx().create_err(err);
|
||||
|
||||
if let ReturnConstraint::ClosureUpvar(upvar_field) = kind {
|
||||
let def_id = match self.regioncx.universal_regions().defining_ty {
|
||||
@ -645,7 +644,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
fn report_escaping_data_error(
|
||||
&self,
|
||||
errci: &ErrorConstraintInfo<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let ErrorConstraintInfo { span, category, .. } = errci;
|
||||
|
||||
let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region(
|
||||
@ -744,10 +743,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
/// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
|
||||
/// | is returning data with lifetime `'b`
|
||||
/// ```
|
||||
fn report_general_error(
|
||||
&self,
|
||||
errci: &ErrorConstraintInfo<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> DiagnosticBuilder<'tcx> {
|
||||
let ErrorConstraintInfo {
|
||||
fr,
|
||||
fr_is_local,
|
||||
@ -761,7 +757,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
let mir_def_name = self.infcx.tcx.def_descr(self.mir_def_id().to_def_id());
|
||||
|
||||
let err = LifetimeOutliveErr { span: *span };
|
||||
let mut diag = self.infcx.tcx.sess.create_err(err);
|
||||
let mut diag = self.dcx().create_err(err);
|
||||
|
||||
// In certain scenarios, such as the one described in issue #118021,
|
||||
// we might encounter a lifetime that cannot be named.
|
||||
@ -1045,11 +1041,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
hir::ExprKind::Closure(hir::Closure {
|
||||
capture_clause: hir::CaptureBy::Ref,
|
||||
body,
|
||||
kind,
|
||||
..
|
||||
}) => {
|
||||
let body = map.body(*body);
|
||||
if !matches!(body.coroutine_kind, Some(hir::CoroutineKind::Async(..))) {
|
||||
if !matches!(
|
||||
kind,
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
_
|
||||
),)
|
||||
) {
|
||||
closure_span = Some(expr.span.shrink_to_lo());
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,7 +188,7 @@ impl Display for RegionName {
|
||||
}
|
||||
|
||||
impl rustc_errors::IntoDiagnosticArg for RegionName {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue {
|
||||
self.to_string().into_diagnostic_arg()
|
||||
}
|
||||
}
|
||||
@ -620,7 +620,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
) => {
|
||||
// HIR lowering sometimes doesn't catch this in erroneous
|
||||
// programs, so we need to use span_delayed_bug here. See #82126.
|
||||
self.infcx.tcx.sess.span_delayed_bug(
|
||||
self.dcx().span_delayed_bug(
|
||||
hir_arg.span(),
|
||||
format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"),
|
||||
);
|
||||
@ -674,7 +674,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
|
||||
let (return_span, mir_description, hir_ty) = match tcx.hir_node(mir_hir_id) {
|
||||
hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, body, fn_decl_span, .. }),
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, kind, fn_decl_span, .. }),
|
||||
..
|
||||
}) => {
|
||||
let (mut span, mut hir_ty) = match fn_decl.output {
|
||||
@ -683,11 +683,21 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
}
|
||||
hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)),
|
||||
};
|
||||
let mir_description = match hir.body(body).coroutine_kind {
|
||||
Some(hir::CoroutineKind::Async(src)) => match src {
|
||||
hir::CoroutineSource::Block => " of async block",
|
||||
hir::CoroutineSource::Closure => " of async closure",
|
||||
hir::CoroutineSource::Fn => {
|
||||
let mir_description = match kind {
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Block,
|
||||
)) => " of async block",
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Closure,
|
||||
)) => " of async closure",
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Fn,
|
||||
)) => {
|
||||
let parent_item =
|
||||
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||
let output = &parent_item
|
||||
@ -700,11 +710,21 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
}
|
||||
" of async function"
|
||||
}
|
||||
},
|
||||
Some(hir::CoroutineKind::Gen(src)) => match src {
|
||||
hir::CoroutineSource::Block => " of gen block",
|
||||
hir::CoroutineSource::Closure => " of gen closure",
|
||||
hir::CoroutineSource::Fn => {
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Gen,
|
||||
hir::CoroutineSource::Block,
|
||||
)) => " of gen block",
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Gen,
|
||||
hir::CoroutineSource::Closure,
|
||||
)) => " of gen closure",
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Gen,
|
||||
hir::CoroutineSource::Fn,
|
||||
)) => {
|
||||
let parent_item =
|
||||
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||
let output = &parent_item
|
||||
@ -714,12 +734,21 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
span = output.span();
|
||||
" of gen function"
|
||||
}
|
||||
},
|
||||
|
||||
Some(hir::CoroutineKind::AsyncGen(src)) => match src {
|
||||
hir::CoroutineSource::Block => " of async gen block",
|
||||
hir::CoroutineSource::Closure => " of async gen closure",
|
||||
hir::CoroutineSource::Fn => {
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::AsyncGen,
|
||||
hir::CoroutineSource::Block,
|
||||
)) => " of async gen block",
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::AsyncGen,
|
||||
hir::CoroutineSource::Closure,
|
||||
)) => " of async gen closure",
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::AsyncGen,
|
||||
hir::CoroutineSource::Fn,
|
||||
)) => {
|
||||
let parent_item =
|
||||
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||
let output = &parent_item
|
||||
@ -729,9 +758,11 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
span = output.span();
|
||||
" of async gen function"
|
||||
}
|
||||
},
|
||||
Some(hir::CoroutineKind::Coroutine) => " of coroutine",
|
||||
None => " of closure",
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => {
|
||||
" of coroutine"
|
||||
}
|
||||
hir::ClosureKind::Closure => " of closure",
|
||||
};
|
||||
(span, mir_description, hir_ty)
|
||||
}
|
||||
|
||||
@ -8,12 +8,9 @@
|
||||
#![feature(let_chains)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(never_type)]
|
||||
#![feature(lazy_cell)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(trusted_step)]
|
||||
#![feature(try_blocks)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_middle;
|
||||
@ -274,11 +271,12 @@ fn do_mir_borrowck<'tcx>(
|
||||
// The first argument is the coroutine type passed by value
|
||||
if let Some(local) = body.local_decls.raw.get(1)
|
||||
// Get the interior types and args which typeck computed
|
||||
&& let ty::Coroutine(_, _, hir::Movability::Static) = local.ty.kind()
|
||||
&& let ty::Coroutine(def_id, _) = *local.ty.kind()
|
||||
&& tcx.coroutine_movability(def_id) == hir::Movability::Movable
|
||||
{
|
||||
false
|
||||
} else {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
for (idx, move_data) in promoted_move_data {
|
||||
@ -414,7 +412,7 @@ fn do_mir_borrowck<'tcx>(
|
||||
|
||||
let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
|
||||
|
||||
tcx.emit_spanned_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span })
|
||||
tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span })
|
||||
}
|
||||
|
||||
let tainted_by_errors = mbcx.emit_errors();
|
||||
@ -702,7 +700,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
|
||||
} => {
|
||||
self.consume_operand(loc, (func, span), flow_state);
|
||||
for arg in args {
|
||||
self.consume_operand(loc, (arg, span), flow_state);
|
||||
self.consume_operand(loc, (&arg.node, arg.span), flow_state);
|
||||
}
|
||||
self.mutate_place(loc, (*destination, span), Deep, flow_state);
|
||||
}
|
||||
@ -1306,7 +1304,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
// moved into the closure and subsequently used by the closure,
|
||||
// in order to populate our used_mut set.
|
||||
match **aggregate_kind {
|
||||
AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _, _) => {
|
||||
AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) => {
|
||||
let def_id = def_id.expect_local();
|
||||
let BorrowCheckResult { used_mut_upvars, .. } =
|
||||
self.infcx.tcx.mir_borrowck(def_id);
|
||||
@ -1612,7 +1610,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
| ty::FnPtr(_)
|
||||
| ty::Dynamic(_, _, _)
|
||||
| ty::Closure(_, _)
|
||||
| ty::Coroutine(_, _, _)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
@ -1636,7 +1634,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
ty::Closure(_, _) | ty::Coroutine(_, _, _) | ty::Tuple(_) => (),
|
||||
ty::Closure(_, _) | ty::Coroutine(_, _) | ty::Tuple(_) => (),
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
@ -2134,7 +2132,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
// dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug`
|
||||
// enabled. We don't want to ICE for that case, as other errors will have
|
||||
// been emitted (#52262).
|
||||
self.infcx.tcx.sess.span_delayed_bug(
|
||||
self.dcx().span_delayed_bug(
|
||||
span,
|
||||
format!(
|
||||
"Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible",
|
||||
@ -2398,18 +2396,19 @@ mod error {
|
||||
/// and we want only the best of those errors.
|
||||
///
|
||||
/// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
|
||||
/// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
|
||||
/// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
|
||||
/// all move errors have been reported, any diagnostics in this map are added to the buffer
|
||||
/// to be emitted.
|
||||
/// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of
|
||||
/// the `Place` of the previous most diagnostic. This happens instead of buffering the
|
||||
/// error. Once all move errors have been reported, any diagnostics in this map are added
|
||||
/// to the buffer to be emitted.
|
||||
///
|
||||
/// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
|
||||
/// when errors in the map are being re-added to the error buffer so that errors with the
|
||||
/// same primary span come out in a consistent order.
|
||||
buffered_move_errors:
|
||||
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>)>,
|
||||
buffered_mut_errors: FxIndexMap<Span, (DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)>,
|
||||
/// Diagnostics to be reported buffer.
|
||||
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>,
|
||||
buffered_mut_errors: FxIndexMap<Span, (DiagnosticBuilder<'tcx>, usize)>,
|
||||
/// Buffer of diagnostics to be reported. Uses `Diagnostic` rather than `DiagnosticBuilder`
|
||||
/// because it has a mixture of error diagnostics and non-error diagnostics.
|
||||
buffered: Vec<Diagnostic>,
|
||||
/// Set to Some if we emit an error during borrowck
|
||||
tainted_by_errors: Option<ErrorGuaranteed>,
|
||||
@ -2426,18 +2425,18 @@ mod error {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_, ErrorGuaranteed>) {
|
||||
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
|
||||
if let None = self.tainted_by_errors {
|
||||
self.tainted_by_errors = Some(self.tcx.sess.span_delayed_bug(
|
||||
self.tainted_by_errors = Some(self.tcx.dcx().span_delayed_bug(
|
||||
t.span.clone_ignoring_labels(),
|
||||
"diagnostic buffered but not emitted",
|
||||
))
|
||||
}
|
||||
t.buffer(&mut self.buffered);
|
||||
self.buffered.push(t.into_diagnostic());
|
||||
}
|
||||
|
||||
pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) {
|
||||
t.buffer(&mut self.buffered);
|
||||
self.buffered.push(t.into_diagnostic());
|
||||
}
|
||||
|
||||
pub fn set_tainted_by_errors(&mut self, e: ErrorGuaranteed) {
|
||||
@ -2446,7 +2445,7 @@ mod error {
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_, ErrorGuaranteed>) {
|
||||
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
|
||||
self.errors.buffer_error(t);
|
||||
}
|
||||
|
||||
@ -2457,7 +2456,7 @@ mod error {
|
||||
pub fn buffer_move_error(
|
||||
&mut self,
|
||||
move_out_indices: Vec<MoveOutIndex>,
|
||||
place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>),
|
||||
place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>),
|
||||
) -> bool {
|
||||
if let Some((_, diag)) =
|
||||
self.errors.buffered_move_errors.insert(move_out_indices, place_and_err)
|
||||
@ -2473,16 +2472,11 @@ mod error {
|
||||
pub fn get_buffered_mut_error(
|
||||
&mut self,
|
||||
span: Span,
|
||||
) -> Option<(DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)> {
|
||||
) -> Option<(DiagnosticBuilder<'tcx>, usize)> {
|
||||
self.errors.buffered_mut_errors.remove(&span)
|
||||
}
|
||||
|
||||
pub fn buffer_mut_error(
|
||||
&mut self,
|
||||
span: Span,
|
||||
t: DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||
count: usize,
|
||||
) {
|
||||
pub fn buffer_mut_error(&mut self, span: Span, t: DiagnosticBuilder<'tcx>, count: usize) {
|
||||
self.errors.buffered_mut_errors.insert(span, (t, count));
|
||||
}
|
||||
|
||||
@ -2490,20 +2484,21 @@ mod error {
|
||||
// Buffer any move errors that we collected and de-duplicated.
|
||||
for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
|
||||
// We have already set tainted for this error, so just buffer it.
|
||||
diag.buffer(&mut self.errors.buffered);
|
||||
self.errors.buffered.push(diag.into_diagnostic());
|
||||
}
|
||||
for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
|
||||
if count > 10 {
|
||||
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
|
||||
}
|
||||
diag.buffer(&mut self.errors.buffered);
|
||||
self.errors.buffered.push(diag.into_diagnostic());
|
||||
}
|
||||
|
||||
if !self.errors.buffered.is_empty() {
|
||||
self.errors.buffered.sort_by_key(|diag| diag.sort_span);
|
||||
|
||||
let dcx = self.dcx();
|
||||
for diag in self.errors.buffered.drain(..) {
|
||||
self.infcx.tcx.sess.dcx().emit_diagnostic(diag);
|
||||
dcx.emit_diagnostic(diag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2517,7 +2512,7 @@ mod error {
|
||||
pub fn has_move_error(
|
||||
&self,
|
||||
move_out_indices: &[MoveOutIndex],
|
||||
) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx, ErrorGuaranteed>)> {
|
||||
) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx>)> {
|
||||
self.errors.buffered_move_errors.get(move_out_indices)
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt};
|
||||
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
|
||||
use rustc_mir_dataflow::move_paths::MoveData;
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_mir_dataflow::ResultsCursor;
|
||||
use rustc_span::symbol::sym;
|
||||
use std::env;
|
||||
@ -27,7 +28,7 @@ use crate::{
|
||||
facts::{AllFacts, AllFactsExt, RustcFacts},
|
||||
location::LocationTable,
|
||||
polonius,
|
||||
region_infer::{values::RegionValueElements, RegionInferenceContext},
|
||||
region_infer::RegionInferenceContext,
|
||||
renumber,
|
||||
type_check::{self, MirTypeckRegionConstraints, MirTypeckResults},
|
||||
universal_regions::UniversalRegions,
|
||||
@ -98,7 +99,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
|
||||
|
||||
let universal_regions = Rc::new(universal_regions);
|
||||
|
||||
let elements = &Rc::new(RegionValueElements::new(body));
|
||||
let elements = &Rc::new(DenseLocationMap::new(body));
|
||||
|
||||
// Run the MIR type-checker.
|
||||
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
|
||||
@ -187,7 +188,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
|
||||
|
||||
if !nll_errors.is_empty() {
|
||||
// Suppress unhelpful extra errors in `infer_opaque_types`.
|
||||
infcx.set_tainted_by_errors(infcx.tcx.sess.span_delayed_bug(
|
||||
infcx.set_tainted_by_errors(infcx.dcx().span_delayed_bug(
|
||||
body.span,
|
||||
"`compute_regions` tainted `infcx` with errors but did not emit any errors",
|
||||
));
|
||||
@ -280,7 +281,7 @@ pub(super) fn dump_annotation<'tcx>(
|
||||
|
||||
let def_span = tcx.def_span(body.source.def_id());
|
||||
let mut err = if let Some(closure_region_requirements) = closure_region_requirements {
|
||||
let mut err = tcx.sess.dcx().struct_span_note(def_span, "external requirements");
|
||||
let mut err = tcx.dcx().struct_span_note(def_span, "external requirements");
|
||||
|
||||
regioncx.annotate(tcx, &mut err);
|
||||
|
||||
@ -299,7 +300,7 @@ pub(super) fn dump_annotation<'tcx>(
|
||||
|
||||
err
|
||||
} else {
|
||||
let mut err = tcx.sess.dcx().struct_span_note(def_span, "no external requirements");
|
||||
let mut err = tcx.dcx().struct_span_note(def_span, "no external requirements");
|
||||
regioncx.annotate(tcx, &mut err);
|
||||
|
||||
err
|
||||
|
||||
@ -120,7 +120,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> {
|
||||
} => {
|
||||
self.consume_operand(location, func);
|
||||
for arg in args {
|
||||
self.consume_operand(location, arg);
|
||||
self.consume_operand(location, &arg.node);
|
||||
}
|
||||
self.mutate_place(location, *destination, Deep);
|
||||
}
|
||||
|
||||
@ -18,7 +18,8 @@ use rustc_middle::mir::{
|
||||
};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::traits::ObligationCauseCode;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph};
|
||||
@ -30,8 +31,7 @@ use crate::{
|
||||
nll::PoloniusOutput,
|
||||
region_infer::reverse_sccs::ReverseSccGraph,
|
||||
region_infer::values::{
|
||||
LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues,
|
||||
ToElementIndex,
|
||||
LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex,
|
||||
},
|
||||
type_check::{free_region_relations::UniversalRegionRelations, Locations},
|
||||
universal_regions::UniversalRegions,
|
||||
@ -330,7 +330,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
|
||||
type_tests: Vec<TypeTest<'tcx>>,
|
||||
liveness_constraints: LivenessValues,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
) -> Self {
|
||||
debug!("universal_regions: {:#?}", universal_regions);
|
||||
debug!("outlives constraints: {:#?}", outlives_constraints);
|
||||
@ -1145,6 +1145,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
|
||||
let ty = ty.fold_with(&mut OpaqueFolder { tcx });
|
||||
let mut failed = false;
|
||||
|
||||
let ty = tcx.fold_regions(ty, |r, _depth| {
|
||||
let r_vid = self.to_region_vid(r);
|
||||
@ -1160,15 +1161,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
.filter(|&u_r| !self.universal_regions.is_local_free_region(u_r))
|
||||
.find(|&u_r| self.eval_equal(u_r, r_vid))
|
||||
.map(|u_r| ty::Region::new_var(tcx, u_r))
|
||||
// In the case of a failure, use `ReErased`. We will eventually
|
||||
// return `None` in this case.
|
||||
.unwrap_or(tcx.lifetimes.re_erased)
|
||||
// In case we could not find a named region to map to,
|
||||
// we will return `None` below.
|
||||
.unwrap_or_else(|| {
|
||||
failed = true;
|
||||
r
|
||||
})
|
||||
});
|
||||
|
||||
debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
|
||||
|
||||
// This will be true if we failed to promote some region.
|
||||
if ty.has_erased_regions() {
|
||||
if failed {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
@ -402,7 +402,7 @@ fn check_opaque_type_parameter_valid(
|
||||
let opaque_param = opaque_generics.param_at(i, tcx);
|
||||
let kind = opaque_param.kind.descr();
|
||||
|
||||
return Err(tcx.sess.emit_err(NonGenericOpaqueTypeParam {
|
||||
return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam {
|
||||
ty: arg,
|
||||
kind,
|
||||
span,
|
||||
@ -419,9 +419,9 @@ fn check_opaque_type_parameter_valid(
|
||||
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
|
||||
.collect();
|
||||
return Err(tcx
|
||||
.sess
|
||||
.dcx()
|
||||
.struct_span_err(span, "non-defining opaque type use in defining scope")
|
||||
.span_note(spans, format!("{descr} used multiple times"))
|
||||
.with_span_note(spans, format!("{descr} used multiple times"))
|
||||
.emit());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,101 +1,18 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_index::bit_set::SparseBitMatrix;
|
||||
use rustc_index::interval::IntervalSet;
|
||||
use rustc_index::interval::SparseIntervalMatrix;
|
||||
use rustc_index::Idx;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::{BasicBlock, Body, Location};
|
||||
use rustc_middle::mir::{BasicBlock, Location};
|
||||
use rustc_middle::ty::{self, RegionVid};
|
||||
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
|
||||
use std::fmt::Debug;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::dataflow::BorrowIndex;
|
||||
|
||||
/// Maps between a `Location` and a `PointIndex` (and vice versa).
|
||||
pub(crate) struct RegionValueElements {
|
||||
/// For each basic block, how many points are contained within?
|
||||
statements_before_block: IndexVec<BasicBlock, usize>,
|
||||
|
||||
/// Map backward from each point to the basic block that it
|
||||
/// belongs to.
|
||||
basic_blocks: IndexVec<PointIndex, BasicBlock>,
|
||||
|
||||
num_points: usize,
|
||||
}
|
||||
|
||||
impl RegionValueElements {
|
||||
pub(crate) fn new(body: &Body<'_>) -> Self {
|
||||
let mut num_points = 0;
|
||||
let statements_before_block: IndexVec<BasicBlock, usize> = body
|
||||
.basic_blocks
|
||||
.iter()
|
||||
.map(|block_data| {
|
||||
let v = num_points;
|
||||
num_points += block_data.statements.len() + 1;
|
||||
v
|
||||
})
|
||||
.collect();
|
||||
debug!("RegionValueElements: statements_before_block={:#?}", statements_before_block);
|
||||
debug!("RegionValueElements: num_points={:#?}", num_points);
|
||||
|
||||
let mut basic_blocks = IndexVec::with_capacity(num_points);
|
||||
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
|
||||
basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
|
||||
}
|
||||
|
||||
Self { statements_before_block, basic_blocks, num_points }
|
||||
}
|
||||
|
||||
/// Total number of point indices
|
||||
pub(crate) fn num_points(&self) -> usize {
|
||||
self.num_points
|
||||
}
|
||||
|
||||
/// Converts a `Location` into a `PointIndex`. O(1).
|
||||
pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
|
||||
let Location { block, statement_index } = location;
|
||||
let start_index = self.statements_before_block[block];
|
||||
PointIndex::new(start_index + statement_index)
|
||||
}
|
||||
|
||||
/// Converts a `Location` into a `PointIndex`. O(1).
|
||||
pub(crate) fn entry_point(&self, block: BasicBlock) -> PointIndex {
|
||||
let start_index = self.statements_before_block[block];
|
||||
PointIndex::new(start_index)
|
||||
}
|
||||
|
||||
/// Return the PointIndex for the block start of this index.
|
||||
pub(crate) fn to_block_start(&self, index: PointIndex) -> PointIndex {
|
||||
PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
|
||||
}
|
||||
|
||||
/// Converts a `PointIndex` back to a location. O(1).
|
||||
pub(crate) fn to_location(&self, index: PointIndex) -> Location {
|
||||
assert!(index.index() < self.num_points);
|
||||
let block = self.basic_blocks[index];
|
||||
let start_index = self.statements_before_block[block];
|
||||
let statement_index = index.index() - start_index;
|
||||
Location { block, statement_index }
|
||||
}
|
||||
|
||||
/// Sometimes we get point-indices back from bitsets that may be
|
||||
/// out of range (because they round up to the nearest 2^N number
|
||||
/// of bits). Use this function to filter such points out if you
|
||||
/// like.
|
||||
pub(crate) fn point_in_range(&self, index: PointIndex) -> bool {
|
||||
index.index() < self.num_points
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A single integer representing a `Location` in the MIR control-flow
|
||||
/// graph. Constructed efficiently from `RegionValueElements`.
|
||||
#[orderable]
|
||||
#[debug_format = "PointIndex({})"]
|
||||
pub struct PointIndex {}
|
||||
}
|
||||
use crate::BorrowIndex;
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A single integer representing a `ty::Placeholder`.
|
||||
@ -123,10 +40,17 @@ pub(crate) enum RegionElement {
|
||||
/// an interval matrix storing liveness ranges for each region-vid.
|
||||
pub(crate) struct LivenessValues {
|
||||
/// The map from locations to points.
|
||||
elements: Rc<RegionValueElements>,
|
||||
elements: Rc<DenseLocationMap>,
|
||||
|
||||
/// Which regions are live. This is exclusive with the fine-grained tracking in `points`, and
|
||||
/// currently only used for validating promoteds (which don't care about more precise tracking).
|
||||
live_regions: Option<FxHashSet<RegionVid>>,
|
||||
|
||||
/// For each region: the points where it is live.
|
||||
points: SparseIntervalMatrix<RegionVid, PointIndex>,
|
||||
///
|
||||
/// This is not initialized for promoteds, because we don't care *where* within a promoted a
|
||||
/// region is live, only that it is.
|
||||
points: Option<SparseIntervalMatrix<RegionVid, PointIndex>>,
|
||||
|
||||
/// When using `-Zpolonius=next`, for each point: the loans flowing into the live regions at
|
||||
/// that point.
|
||||
@ -155,24 +79,52 @@ impl LiveLoans {
|
||||
|
||||
impl LivenessValues {
|
||||
/// Create an empty map of regions to locations where they're live.
|
||||
pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self {
|
||||
pub(crate) fn with_specific_points(elements: Rc<DenseLocationMap>) -> Self {
|
||||
LivenessValues {
|
||||
points: SparseIntervalMatrix::new(elements.num_points),
|
||||
live_regions: None,
|
||||
points: Some(SparseIntervalMatrix::new(elements.num_points())),
|
||||
elements,
|
||||
loans: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an empty map of regions to locations where they're live.
|
||||
///
|
||||
/// Unlike `with_specific_points`, does not track exact locations where something is live, only
|
||||
/// which regions are live.
|
||||
pub(crate) fn without_specific_points(elements: Rc<DenseLocationMap>) -> Self {
|
||||
LivenessValues {
|
||||
live_regions: Some(Default::default()),
|
||||
points: None,
|
||||
elements,
|
||||
loans: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate through each region that has a value in this set.
|
||||
pub(crate) fn regions(&self) -> impl Iterator<Item = RegionVid> {
|
||||
self.points.rows()
|
||||
pub(crate) fn regions(&self) -> impl Iterator<Item = RegionVid> + '_ {
|
||||
self.points.as_ref().expect("use with_specific_points").rows()
|
||||
}
|
||||
|
||||
/// Iterate through each region that has a value in this set.
|
||||
// We are passing query instability implications to the caller.
|
||||
#[rustc_lint_query_instability]
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
pub(crate) fn live_regions_unordered(&self) -> impl Iterator<Item = RegionVid> + '_ {
|
||||
self.live_regions.as_ref().unwrap().iter().copied()
|
||||
}
|
||||
|
||||
/// Records `region` as being live at the given `location`.
|
||||
pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) {
|
||||
debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location);
|
||||
let point = self.elements.point_from_location(location);
|
||||
self.points.insert(region, point);
|
||||
debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location);
|
||||
if let Some(points) = &mut self.points {
|
||||
points.insert(region, point);
|
||||
} else {
|
||||
if self.elements.point_in_range(point) {
|
||||
self.live_regions.as_mut().unwrap().insert(region);
|
||||
}
|
||||
}
|
||||
|
||||
// When available, record the loans flowing into this region as live at the given point.
|
||||
if let Some(loans) = self.loans.as_mut() {
|
||||
@ -185,7 +137,13 @@ impl LivenessValues {
|
||||
/// Records `region` as being live at all the given `points`.
|
||||
pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet<PointIndex>) {
|
||||
debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points);
|
||||
self.points.union_row(region, points);
|
||||
if let Some(this) = &mut self.points {
|
||||
this.union_row(region, points);
|
||||
} else {
|
||||
if points.iter().any(|point| self.elements.point_in_range(point)) {
|
||||
self.live_regions.as_mut().unwrap().insert(region);
|
||||
}
|
||||
}
|
||||
|
||||
// When available, record the loans flowing into this region as live at the given points.
|
||||
if let Some(loans) = self.loans.as_mut() {
|
||||
@ -201,23 +159,33 @@ impl LivenessValues {
|
||||
|
||||
/// Records `region` as being live at all the control-flow points.
|
||||
pub(crate) fn add_all_points(&mut self, region: RegionVid) {
|
||||
self.points.insert_all_into_row(region);
|
||||
if let Some(points) = &mut self.points {
|
||||
points.insert_all_into_row(region);
|
||||
} else {
|
||||
self.live_regions.as_mut().unwrap().insert(region);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether `region` is marked live at the given `location`.
|
||||
pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
|
||||
let point = self.elements.point_from_location(location);
|
||||
self.points.row(region).is_some_and(|r| r.contains(point))
|
||||
if let Some(points) = &self.points {
|
||||
points.row(region).is_some_and(|r| r.contains(point))
|
||||
} else {
|
||||
unreachable!(
|
||||
"Should be using LivenessValues::with_specific_points to ask whether live at a location"
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns whether `region` is marked live at any location.
|
||||
pub(crate) fn is_live_anywhere(&self, region: RegionVid) -> bool {
|
||||
self.live_points(region).next().is_some()
|
||||
}
|
||||
|
||||
/// Returns an iterator of all the points where `region` is live.
|
||||
fn live_points(&self, region: RegionVid) -> impl Iterator<Item = PointIndex> + '_ {
|
||||
self.points
|
||||
let Some(points) = &self.points else {
|
||||
unreachable!(
|
||||
"Should be using LivenessValues::with_specific_points to ask whether live at a location"
|
||||
)
|
||||
};
|
||||
points
|
||||
.row(region)
|
||||
.into_iter()
|
||||
.flat_map(|set| set.iter())
|
||||
@ -298,7 +266,7 @@ impl PlaceholderIndices {
|
||||
/// it would also contain various points from within the function.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct RegionValues<N: Idx> {
|
||||
elements: Rc<RegionValueElements>,
|
||||
elements: Rc<DenseLocationMap>,
|
||||
placeholder_indices: Rc<PlaceholderIndices>,
|
||||
points: SparseIntervalMatrix<N, PointIndex>,
|
||||
free_regions: SparseBitMatrix<N, RegionVid>,
|
||||
@ -313,14 +281,14 @@ impl<N: Idx> RegionValues<N> {
|
||||
/// Each of the regions in num_region_variables will be initialized with an
|
||||
/// empty set of points and no causal information.
|
||||
pub(crate) fn new(
|
||||
elements: &Rc<RegionValueElements>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
num_universal_regions: usize,
|
||||
placeholder_indices: &Rc<PlaceholderIndices>,
|
||||
) -> Self {
|
||||
let num_placeholders = placeholder_indices.len();
|
||||
Self {
|
||||
elements: elements.clone(),
|
||||
points: SparseIntervalMatrix::new(elements.num_points),
|
||||
points: SparseIntervalMatrix::new(elements.num_points()),
|
||||
placeholder_indices: placeholder_indices.clone(),
|
||||
free_regions: SparseBitMatrix::new(num_universal_regions),
|
||||
placeholders: SparseBitMatrix::new(num_placeholders),
|
||||
@ -372,7 +340,10 @@ impl<N: Idx> RegionValues<N> {
|
||||
/// elements for the region `from` from `values` and add them to
|
||||
/// the region `to` in `self`.
|
||||
pub(crate) fn merge_liveness(&mut self, to: N, from: RegionVid, values: &LivenessValues) {
|
||||
if let Some(set) = values.points.row(from) {
|
||||
let Some(value_points) = &values.points else {
|
||||
panic!("LivenessValues must track specific points for use in merge_liveness");
|
||||
};
|
||||
if let Some(set) = value_points.row(from) {
|
||||
self.points.union_row(to, set);
|
||||
}
|
||||
}
|
||||
@ -486,7 +457,7 @@ impl ToElementIndex for ty::PlaceholderRegion {
|
||||
|
||||
/// For debugging purposes, returns a pretty-printed string of the given points.
|
||||
pub(crate) fn pretty_print_points(
|
||||
elements: &RegionValueElements,
|
||||
elements: &DenseLocationMap,
|
||||
points: impl IntoIterator<Item = PointIndex>,
|
||||
) -> String {
|
||||
pretty_print_region_elements(
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_errors::{codes::*, MultiSpan};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::{GenericArg, Ty};
|
||||
use rustc_span::Span;
|
||||
@ -6,7 +6,7 @@ use rustc_span::Span;
|
||||
use crate::diagnostics::RegionName;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(borrowck_move_unsized, code = "E0161")]
|
||||
#[diag(borrowck_move_unsized, code = E0161)]
|
||||
pub(crate) struct MoveUnsized<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
#[primary_span]
|
||||
@ -281,7 +281,7 @@ pub(crate) enum CaptureVarCause {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(borrowck_cannot_move_when_borrowed, code = "E0505")]
|
||||
#[diag(borrowck_cannot_move_when_borrowed, code = E0505)]
|
||||
pub(crate) struct MoveBorrow<'a> {
|
||||
pub place: &'a str,
|
||||
pub borrow_place: &'a str,
|
||||
@ -294,7 +294,7 @@ pub(crate) struct MoveBorrow<'a> {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(borrowck_opaque_type_non_generic_param, code = "E0792")]
|
||||
#[diag(borrowck_opaque_type_non_generic_param, code = E0792)]
|
||||
pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
|
||||
pub ty: GenericArg<'tcx>,
|
||||
pub kind: &'a str,
|
||||
|
||||
@ -33,7 +33,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
||||
/// our special inference variable there, we would mess that up.
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
locations: Locations,
|
||||
span: Span,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
@ -47,7 +47,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
locations: Locations,
|
||||
span: Span,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
@ -59,7 +59,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
universal_regions,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
locations,
|
||||
span,
|
||||
category,
|
||||
@ -136,7 +136,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
|
||||
// Extract out various useful fields we'll need below.
|
||||
let ConstraintConversion {
|
||||
tcx, region_bound_pairs, implicit_region_bound, param_env, ..
|
||||
tcx,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
known_type_outlives_obligations,
|
||||
..
|
||||
} = *self;
|
||||
|
||||
let ty::OutlivesPredicate(k1, r2) = predicate;
|
||||
@ -157,7 +161,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
tcx,
|
||||
region_bound_pairs,
|
||||
Some(implicit_region_bound),
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
)
|
||||
.type_must_outlive(origin, t1, r2, constraint_category);
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use rustc_data_structures::frozen::Frozen;
|
||||
use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_infer::infer::outlives;
|
||||
use rustc_infer::infer::outlives::env::RegionBoundPairs;
|
||||
@ -44,12 +45,14 @@ type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
|
||||
pub(crate) struct CreateResult<'tcx> {
|
||||
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||
pub(crate) known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
|
||||
}
|
||||
|
||||
pub(crate) fn create<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
universal_regions: &Rc<UniversalRegions<'tcx>>,
|
||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||
@ -57,6 +60,7 @@ pub(crate) fn create<'tcx>(
|
||||
UniversalRegionRelationsBuilder {
|
||||
infcx,
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
implicit_region_bound,
|
||||
constraints,
|
||||
universal_regions: universal_regions.clone(),
|
||||
@ -174,6 +178,7 @@ impl UniversalRegionRelations<'_> {
|
||||
struct UniversalRegionRelationsBuilder<'this, 'tcx> {
|
||||
infcx: &'this InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
|
||||
@ -195,9 +200,12 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn create(mut self) -> CreateResult<'tcx> {
|
||||
let span = self.infcx.tcx.def_span(self.universal_regions.defining_ty.def_id());
|
||||
let tcx = self.infcx.tcx;
|
||||
let defining_ty_def_id = self.universal_regions.defining_ty.def_id().expect_local();
|
||||
let span = tcx.def_span(defining_ty_def_id);
|
||||
|
||||
// Insert the facts we know from the predicates. Why? Why not.
|
||||
// Insert the `'a: 'b` we know from the predicates.
|
||||
// This does not consider the type-outlives.
|
||||
let param_env = self.param_env;
|
||||
self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
|
||||
|
||||
@ -275,6 +283,26 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
normalized_inputs_and_output.push(norm_ty);
|
||||
}
|
||||
|
||||
// Add implied bounds from impl header.
|
||||
if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
|
||||
for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
|
||||
let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = self
|
||||
.param_env
|
||||
.and(type_op::normalize::Normalize::new(ty))
|
||||
.fully_perform(self.infcx, span)
|
||||
else {
|
||||
tcx.dcx().span_delayed_bug(span, format!("failed to normalize {ty:?}"));
|
||||
continue;
|
||||
};
|
||||
constraints.extend(c);
|
||||
|
||||
// We currently add implied bounds from the normalized ty only.
|
||||
// This is more conservative and matches wfcheck behavior.
|
||||
let c = self.add_implied_bounds(norm_ty);
|
||||
constraints.extend(c);
|
||||
}
|
||||
}
|
||||
|
||||
for c in constraints {
|
||||
self.push_region_constraints(c, span);
|
||||
}
|
||||
@ -285,6 +313,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
outlives: self.outlives.freeze(),
|
||||
inverse_outlives: self.inverse_outlives.freeze(),
|
||||
}),
|
||||
known_type_outlives_obligations: self.known_type_outlives_obligations,
|
||||
region_bound_pairs: self.region_bound_pairs,
|
||||
normalized_inputs_and_output,
|
||||
}
|
||||
@ -299,7 +328,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
&self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
self.known_type_outlives_obligations,
|
||||
Locations::All(span),
|
||||
span,
|
||||
ConstraintCategory::Internal,
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
|
||||
//! contain revealed `impl Trait` values).
|
||||
|
||||
use itertools::Itertools;
|
||||
use rustc_infer::infer::BoundRegionConversionTime;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
@ -22,7 +23,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
#[instrument(skip(self, body), level = "debug")]
|
||||
pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
|
||||
let mir_def_id = body.source.def_id().expect_local();
|
||||
if !self.tcx().is_closure(mir_def_id.to_def_id()) {
|
||||
if !self.tcx().is_closure_or_coroutine(mir_def_id.to_def_id()) {
|
||||
return;
|
||||
}
|
||||
let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id);
|
||||
@ -39,9 +40,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
user_provided_sig,
|
||||
);
|
||||
|
||||
for (&user_ty, arg_decl) in user_provided_sig.inputs().iter().zip(
|
||||
// In MIR, closure args begin with an implicit `self`. Skip it!
|
||||
body.args_iter().skip(1).map(|local| &body.local_decls[local]),
|
||||
let is_coroutine_with_implicit_resume_ty = self.tcx().is_coroutine(mir_def_id.to_def_id())
|
||||
&& user_provided_sig.inputs().is_empty();
|
||||
|
||||
for (&user_ty, arg_decl) in user_provided_sig.inputs().iter().zip_eq(
|
||||
// In MIR, closure args begin with an implicit `self`.
|
||||
// Also, coroutines have a resume type which may be implicitly `()`.
|
||||
body.args_iter()
|
||||
.skip(1 + if is_coroutine_with_implicit_resume_ty { 1 } else { 0 })
|
||||
.map(|local| &body.local_decls[local]),
|
||||
) {
|
||||
self.ascribe_user_type_skip_wf(
|
||||
arg_decl.ty,
|
||||
@ -76,7 +83,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
|
||||
if argument_index + 1 >= body.local_decls.len() {
|
||||
self.tcx()
|
||||
.sess
|
||||
.dcx()
|
||||
.span_delayed_bug(body.span, "found more normalized_input_ty than local_decls");
|
||||
break;
|
||||
}
|
||||
@ -94,31 +101,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
debug!(
|
||||
"equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}",
|
||||
body.yield_ty(),
|
||||
universal_regions.yield_ty
|
||||
);
|
||||
|
||||
// We will not have a universal_regions.yield_ty if we yield (by accident)
|
||||
// outside of a coroutine and return an `impl Trait`, so emit a span_delayed_bug
|
||||
// because we don't want to panic in an assert here if we've already got errors.
|
||||
if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() {
|
||||
self.tcx().sess.span_delayed_bug(
|
||||
body.span,
|
||||
format!(
|
||||
"Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})",
|
||||
body.yield_ty(),
|
||||
universal_regions.yield_ty,
|
||||
),
|
||||
if let Some(mir_yield_ty) = body.yield_ty() {
|
||||
let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
|
||||
self.equate_normalized_input_or_output(
|
||||
universal_regions.yield_ty.unwrap(),
|
||||
mir_yield_ty,
|
||||
yield_span,
|
||||
);
|
||||
}
|
||||
|
||||
if let (Some(mir_yield_ty), Some(ur_yield_ty)) =
|
||||
(body.yield_ty(), universal_regions.yield_ty)
|
||||
{
|
||||
if let Some(mir_resume_ty) = body.resume_ty() {
|
||||
let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
|
||||
self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
|
||||
self.equate_normalized_input_or_output(
|
||||
universal_regions.resume_ty.unwrap(),
|
||||
mir_resume_ty,
|
||||
yield_span,
|
||||
);
|
||||
}
|
||||
|
||||
// Return types are a bit more complex. They may contain opaque `impl Trait` types.
|
||||
|
||||
@ -2,9 +2,9 @@ use rustc_data_structures::vec_linked_list as vll;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc_middle::mir::{Body, Local, Location};
|
||||
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
|
||||
|
||||
use crate::def_use::{self, DefUse};
|
||||
use crate::region_infer::values::{PointIndex, RegionValueElements};
|
||||
|
||||
/// A map that cross references each local with the locations where it
|
||||
/// is defined (assigned), used, or dropped. Used during liveness
|
||||
@ -60,7 +60,7 @@ impl vll::LinkElem for Appearance {
|
||||
impl LocalUseMap {
|
||||
pub(crate) fn build(
|
||||
live_locals: &[Local],
|
||||
elements: &RegionValueElements,
|
||||
elements: &DenseLocationMap,
|
||||
body: &Body<'_>,
|
||||
) -> Self {
|
||||
let nones = IndexVec::from_elem(None, &body.local_decls);
|
||||
@ -103,7 +103,7 @@ impl LocalUseMap {
|
||||
|
||||
struct LocalUseMapBuild<'me> {
|
||||
local_use_map: &'me mut LocalUseMap,
|
||||
elements: &'me RegionValueElements,
|
||||
elements: &'me DenseLocationMap,
|
||||
|
||||
// Vector used in `visit_local` to signal which `Local`s do we need
|
||||
// def/use/drop information on, constructed from `live_locals` (that
|
||||
@ -144,7 +144,7 @@ impl LocalUseMapBuild<'_> {
|
||||
}
|
||||
|
||||
fn insert(
|
||||
elements: &RegionValueElements,
|
||||
elements: &DenseLocationMap,
|
||||
first_appearance: &mut Option<AppearanceIndex>,
|
||||
appearances: &mut IndexVec<AppearanceIndex, Appearance>,
|
||||
location: Location,
|
||||
|
||||
@ -6,6 +6,7 @@ use rustc_middle::ty::visit::TypeVisitable;
|
||||
use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt};
|
||||
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
|
||||
use rustc_mir_dataflow::move_paths::MoveData;
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_mir_dataflow::ResultsCursor;
|
||||
use std::rc::Rc;
|
||||
|
||||
@ -13,7 +14,7 @@ use crate::{
|
||||
constraints::OutlivesConstraintSet,
|
||||
facts::{AllFacts, AllFactsExt},
|
||||
location::LocationTable,
|
||||
region_infer::values::{LivenessValues, RegionValueElements},
|
||||
region_infer::values::LivenessValues,
|
||||
universal_regions::UniversalRegions,
|
||||
};
|
||||
|
||||
@ -34,7 +35,7 @@ mod trace;
|
||||
pub(super) fn generate<'mir, 'tcx>(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
@ -183,6 +184,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'cx, 'tcx> {
|
||||
match ty_context {
|
||||
TyContext::ReturnTy(SourceInfo { span, .. })
|
||||
| TyContext::YieldTy(SourceInfo { span, .. })
|
||||
| TyContext::ResumeTy(SourceInfo { span, .. })
|
||||
| TyContext::UserTy(span)
|
||||
| TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => {
|
||||
span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context);
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::graph::WithSuccessors;
|
||||
use rustc_index::bit_set::HybridBitSet;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::interval::IntervalSet;
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_infer::infer::outlives::for_liveness;
|
||||
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
|
||||
use rustc_middle::traits::query::DropckOutlivesResult;
|
||||
use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
|
||||
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
|
||||
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
|
||||
@ -17,7 +18,7 @@ use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
|
||||
use rustc_mir_dataflow::ResultsCursor;
|
||||
|
||||
use crate::{
|
||||
region_infer::values::{self, LiveLoans, PointIndex, RegionValueElements},
|
||||
region_infer::values::{self, LiveLoans},
|
||||
type_check::liveness::local_use_map::LocalUseMap,
|
||||
type_check::liveness::polonius,
|
||||
type_check::NormalizeLocation,
|
||||
@ -41,7 +42,7 @@ use crate::{
|
||||
pub(super) fn trace<'mir, 'tcx>(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
relevant_live_locals: Vec<Local>,
|
||||
@ -105,7 +106,7 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
|
||||
typeck: &'me mut TypeChecker<'typeck, 'tcx>,
|
||||
|
||||
/// Defines the `PointIndex` mapping
|
||||
elements: &'me RegionValueElements,
|
||||
elements: &'me DenseLocationMap,
|
||||
|
||||
/// MIR we are analyzing.
|
||||
body: &'me Body<'tcx>,
|
||||
@ -134,7 +135,7 @@ struct LivenessResults<'me, 'typeck, 'flow, 'tcx> {
|
||||
cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>,
|
||||
|
||||
/// Set of points that define the current local.
|
||||
defs: HybridBitSet<PointIndex>,
|
||||
defs: BitSet<PointIndex>,
|
||||
|
||||
/// Points where the current variable is "use live" -- meaning
|
||||
/// that there is a future "full use" that may use its value.
|
||||
@ -157,7 +158,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
|
||||
let num_points = cx.elements.num_points();
|
||||
LivenessResults {
|
||||
cx,
|
||||
defs: HybridBitSet::new_empty(num_points),
|
||||
defs: BitSet::new_empty(num_points),
|
||||
use_live_at: IntervalSet::new(num_points),
|
||||
drop_live_at: IntervalSet::new(num_points),
|
||||
drop_locations: vec![],
|
||||
@ -570,7 +571,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
||||
}
|
||||
|
||||
fn make_all_regions_live(
|
||||
elements: &RegionValueElements,
|
||||
elements: &DenseLocationMap,
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
value: impl TypeVisitable<TyCtxt<'tcx>>,
|
||||
live_at: &IntervalSet<PointIndex>,
|
||||
|
||||
@ -35,7 +35,9 @@ use rustc_middle::ty::{
|
||||
OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
|
||||
};
|
||||
use rustc_middle::ty::{GenericArgsRef, UserArgs};
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
|
||||
@ -58,9 +60,7 @@ use crate::{
|
||||
location::LocationTable,
|
||||
member_constraints::MemberConstraintSet,
|
||||
path_utils,
|
||||
region_infer::values::{
|
||||
LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
|
||||
},
|
||||
region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices},
|
||||
region_infer::TypeTest,
|
||||
type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
|
||||
universal_regions::{DefiningTy, UniversalRegions},
|
||||
@ -133,7 +133,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
upvars: &[&ty::CapturedPlace<'tcx>],
|
||||
use_polonius: bool,
|
||||
) -> MirTypeckResults<'tcx> {
|
||||
@ -141,7 +141,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
let mut constraints = MirTypeckRegionConstraints {
|
||||
placeholder_indices: PlaceholderIndices::default(),
|
||||
placeholder_index_to_region: IndexVec::default(),
|
||||
liveness_constraints: LivenessValues::new(elements.clone()),
|
||||
liveness_constraints: LivenessValues::with_specific_points(elements.clone()),
|
||||
outlives_constraints: OutlivesConstraintSet::default(),
|
||||
member_constraints: MemberConstraintSet::default(),
|
||||
type_tests: Vec::default(),
|
||||
@ -152,9 +152,14 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
universal_region_relations,
|
||||
region_bound_pairs,
|
||||
normalized_inputs_and_output,
|
||||
known_type_outlives_obligations,
|
||||
} = free_region_relations::create(
|
||||
infcx,
|
||||
param_env,
|
||||
// FIXME(-Znext-solver): These are unnormalized. Normalize them.
|
||||
infcx.tcx.arena.alloc_from_iter(
|
||||
param_env.caller_bounds().iter().filter_map(|clause| clause.as_type_outlives_clause()),
|
||||
),
|
||||
implicit_region_bound,
|
||||
universal_regions,
|
||||
&mut constraints,
|
||||
@ -176,6 +181,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
body,
|
||||
param_env,
|
||||
®ion_bound_pairs,
|
||||
known_type_outlives_obligations,
|
||||
implicit_region_bound,
|
||||
&mut borrowck_context,
|
||||
);
|
||||
@ -224,7 +230,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
|
||||
trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind());
|
||||
if hidden_type.has_non_region_infer() {
|
||||
let reported = infcx.tcx.sess.span_delayed_bug(
|
||||
let reported = infcx.dcx().span_delayed_bug(
|
||||
decl.hidden_type.span,
|
||||
format!("could not resolve {:#?}", hidden_type.ty.kind()),
|
||||
);
|
||||
@ -268,7 +274,7 @@ fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: String) {
|
||||
// We sometimes see MIR failures (notably predicate failures) due to
|
||||
// the fact that we check rvalue sized predicates here. So use `span_delayed_bug`
|
||||
// to avoid reporting bugs in those cases.
|
||||
tcx.sess.dcx().span_delayed_bug(span, msg);
|
||||
tcx.dcx().span_delayed_bug(span, msg);
|
||||
}
|
||||
|
||||
enum FieldAccessError {
|
||||
@ -406,6 +412,16 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||
instantiated_predicates,
|
||||
locations,
|
||||
);
|
||||
|
||||
assert!(!matches!(
|
||||
tcx.impl_of_method(def_id).map(|imp| tcx.def_kind(imp)),
|
||||
Some(DefKind::Impl { of_trait: true })
|
||||
));
|
||||
self.cx.prove_predicates(
|
||||
args.types().map(|ty| ty::ClauseKind::WellFormed(ty.into())),
|
||||
locations,
|
||||
ConstraintCategory::Boring,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -545,7 +561,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
let all_facts = &mut None;
|
||||
let mut constraints = Default::default();
|
||||
let mut liveness_constraints =
|
||||
LivenessValues::new(Rc::new(RegionValueElements::new(promoted_body)));
|
||||
LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(promoted_body)));
|
||||
// Don't try to add borrow_region facts for the promoted MIR
|
||||
|
||||
let mut swap_constraints = |this: &mut Self| {
|
||||
@ -584,11 +600,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
}
|
||||
self.cx.borrowck_context.constraints.outlives_constraints.push(constraint)
|
||||
}
|
||||
for region in liveness_constraints.regions() {
|
||||
// If the region is live at at least one location in the promoted MIR,
|
||||
// then add a liveness constraint to the main MIR for this region
|
||||
// at the location provided as an argument to this method
|
||||
if liveness_constraints.is_live_anywhere(region) {
|
||||
//
|
||||
// add_location doesn't care about ordering so not a problem for the live regions to be
|
||||
// unordered.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
for region in liveness_constraints.live_regions_unordered() {
|
||||
self.cx
|
||||
.borrowck_context
|
||||
.constraints
|
||||
@ -596,7 +615,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
.add_location(region, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self, location), ret, level = "debug")]
|
||||
fn sanitize_projection(
|
||||
@ -762,7 +780,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
let (variant, args) = match base_ty {
|
||||
PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() {
|
||||
ty::Adt(adt_def, args) => (adt_def.variant(variant_index), args),
|
||||
ty::Coroutine(def_id, args, _) => {
|
||||
ty::Coroutine(def_id, args) => {
|
||||
let mut variants = args.as_coroutine().state_tys(def_id, tcx);
|
||||
let Some(mut variant) = variants.nth(variant_index.into()) else {
|
||||
bug!(
|
||||
@ -790,7 +808,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
}),
|
||||
};
|
||||
}
|
||||
ty::Coroutine(_, args, _) => {
|
||||
ty::Coroutine(_, args) => {
|
||||
// Only prefix fields (upvars and current state) are
|
||||
// accessible without a variant index.
|
||||
return match args.as_coroutine().prefix_tys().get(field.index()) {
|
||||
@ -838,6 +856,7 @@ struct TypeChecker<'a, 'tcx> {
|
||||
/// all of the promoted items.
|
||||
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
|
||||
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
|
||||
@ -988,6 +1007,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
body: &'a Body<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
|
||||
) -> Self {
|
||||
@ -998,6 +1018,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
user_type_annotations: &body.user_type_annotations,
|
||||
param_env,
|
||||
region_bound_pairs,
|
||||
known_type_outlives_obligations,
|
||||
implicit_region_bound,
|
||||
borrowck_context,
|
||||
reported_errors: Default::default(),
|
||||
@ -1067,7 +1088,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
);
|
||||
|
||||
if result.is_err() {
|
||||
self.infcx.tcx.sess.span_delayed_bug(
|
||||
self.infcx.dcx().span_delayed_bug(
|
||||
self.body.span,
|
||||
"failed re-defining predefined opaques in mir typeck",
|
||||
);
|
||||
@ -1087,12 +1108,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn check_user_type_annotations(&mut self) {
|
||||
debug!(?self.user_type_annotations);
|
||||
let tcx = self.tcx();
|
||||
for user_annotation in self.user_type_annotations {
|
||||
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
|
||||
let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
|
||||
if let ty::UserType::TypeOf(def, args) = annotation
|
||||
&& let DefKind::InlineConst = tcx.def_kind(def)
|
||||
{
|
||||
self.check_inline_const(inferred_ty, def.expect_local(), args, span);
|
||||
} else {
|
||||
self.ascribe_user_type(inferred_ty, annotation, span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self, data), level = "debug")]
|
||||
fn push_region_constraints(
|
||||
@ -1108,7 +1136,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.borrowck_context.universal_regions,
|
||||
self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
self.known_type_outlives_obligations,
|
||||
locations,
|
||||
locations.span(self.body),
|
||||
category,
|
||||
@ -1183,6 +1211,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_inline_const(
|
||||
&mut self,
|
||||
inferred_ty: Ty<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
args: UserArgs<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
assert!(args.user_self_ty.is_none());
|
||||
let tcx = self.tcx();
|
||||
let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args);
|
||||
if let Err(terr) =
|
||||
self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring)
|
||||
{
|
||||
span_bug!(
|
||||
span,
|
||||
"bad inline const pattern: ({:?} = {:?}) {:?}",
|
||||
const_ty,
|
||||
inferred_ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
let args = self.infcx.resolve_vars_if_possible(args.args);
|
||||
let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span));
|
||||
self.normalize_and_prove_instantiated_predicates(
|
||||
def_id.to_def_id(),
|
||||
predicates,
|
||||
Locations::All(span),
|
||||
);
|
||||
}
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
@ -1359,7 +1417,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
TerminatorKind::Call { func, args, destination, call_source, target, .. } => {
|
||||
self.check_operand(func, term_location);
|
||||
for arg in args {
|
||||
self.check_operand(arg, term_location);
|
||||
self.check_operand(&arg.node, term_location);
|
||||
}
|
||||
|
||||
let func_ty = func.ty(body, tcx);
|
||||
@ -1450,13 +1508,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
TerminatorKind::Yield { value, .. } => {
|
||||
TerminatorKind::Yield { value, resume_arg, .. } => {
|
||||
self.check_operand(value, term_location);
|
||||
|
||||
let value_ty = value.ty(body, tcx);
|
||||
match body.yield_ty() {
|
||||
None => span_mirbug!(self, term, "yield in non-coroutine"),
|
||||
Some(ty) => {
|
||||
let value_ty = value.ty(body, tcx);
|
||||
if let Err(terr) = self.sub_types(
|
||||
value_ty,
|
||||
ty,
|
||||
@ -1474,6 +1532,28 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match body.resume_ty() {
|
||||
None => span_mirbug!(self, term, "yield in non-coroutine"),
|
||||
Some(ty) => {
|
||||
let resume_ty = resume_arg.ty(body, tcx);
|
||||
if let Err(terr) = self.sub_types(
|
||||
ty,
|
||||
resume_ty.ty,
|
||||
term_location.to_locations(),
|
||||
ConstraintCategory::Yield,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
term,
|
||||
"type of resume place is {:?}, but the resume type is {:?}: {:?}",
|
||||
resume_ty,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1558,7 +1638,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
term: &Terminator<'tcx>,
|
||||
func: &Operand<'tcx>,
|
||||
sig: &ty::FnSig<'tcx>,
|
||||
args: &[Operand<'tcx>],
|
||||
args: &[Spanned<Operand<'tcx>>],
|
||||
term_location: Location,
|
||||
call_source: CallSource,
|
||||
) {
|
||||
@ -1571,9 +1651,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
if self.tcx().is_intrinsic(def_id) {
|
||||
match self.tcx().item_name(def_id) {
|
||||
sym::simd_shuffle => {
|
||||
if !matches!(args[2], Operand::Constant(_)) {
|
||||
if !matches!(args[2], Spanned { node: Operand::Constant(_), .. }) {
|
||||
self.tcx()
|
||||
.sess
|
||||
.dcx()
|
||||
.emit_err(SimdShuffleLastConst { span: term.source_info.span });
|
||||
}
|
||||
}
|
||||
@ -1584,7 +1664,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
debug!(?func_ty);
|
||||
|
||||
for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() {
|
||||
let op_arg_ty = op_arg.ty(body, self.tcx());
|
||||
let op_arg_ty = op_arg.node.ty(body, self.tcx());
|
||||
|
||||
let op_arg_ty = self.normalize(op_arg_ty, term_location);
|
||||
let category = if call_source.from_hir_call() {
|
||||
@ -1752,7 +1832,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// While this is located in `nll::typeck` this error is not
|
||||
// an NLL error, it's a required check to prevent creation
|
||||
// of unsized rvalues in a call expression.
|
||||
self.tcx().sess.emit_err(MoveUnsized { ty, span });
|
||||
self.tcx().dcx().emit_err(MoveUnsized { ty, span });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1784,7 +1864,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}),
|
||||
}
|
||||
}
|
||||
AggregateKind::Coroutine(_, args, _) => {
|
||||
AggregateKind::Coroutine(_, args) => {
|
||||
// It doesn't make sense to look at a field beyond the prefix;
|
||||
// these require a variant index, and are not initialized in
|
||||
// aggregate rvalues.
|
||||
@ -1817,7 +1897,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
let def_id = uv.def;
|
||||
if tcx.def_kind(def_id) == DefKind::InlineConst {
|
||||
let def_id = def_id.expect_local();
|
||||
let predicates = self.prove_closure_bounds(tcx, def_id, uv.args, location);
|
||||
let predicates = self.prove_closure_bounds(
|
||||
tcx,
|
||||
def_id,
|
||||
uv.args,
|
||||
location.to_locations(),
|
||||
);
|
||||
self.normalize_and_prove_instantiated_predicates(
|
||||
def_id.to_def_id(),
|
||||
predicates,
|
||||
@ -2392,7 +2477,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
AggregateKind::Array(_) => None,
|
||||
AggregateKind::Tuple => None,
|
||||
AggregateKind::Closure(_, _) => None,
|
||||
AggregateKind::Coroutine(_, _, _) => None,
|
||||
AggregateKind::Coroutine(_, _) => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -2620,9 +2705,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// desugaring. A closure gets desugared to a struct, and
|
||||
// these extra requirements are basically like where
|
||||
// clauses on the struct.
|
||||
AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args, _) => {
|
||||
(def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location))
|
||||
}
|
||||
AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => (
|
||||
def_id,
|
||||
self.prove_closure_bounds(
|
||||
tcx,
|
||||
def_id.expect_local(),
|
||||
args,
|
||||
location.to_locations(),
|
||||
),
|
||||
),
|
||||
|
||||
AggregateKind::Array(_) | AggregateKind::Tuple => {
|
||||
(CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty())
|
||||
@ -2641,7 +2732,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
location: Location,
|
||||
locations: Locations,
|
||||
) -> ty::InstantiatedPredicates<'tcx> {
|
||||
if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements {
|
||||
constraint_conversion::ConstraintConversion::new(
|
||||
@ -2649,8 +2740,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.borrowck_context.universal_regions,
|
||||
self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
location.to_locations(),
|
||||
self.known_type_outlives_obligations,
|
||||
locations,
|
||||
DUMMY_SP, // irrelevant; will be overridden.
|
||||
ConstraintCategory::Boring, // same as above.
|
||||
self.borrowck_context.constraints,
|
||||
@ -2676,7 +2767,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
if let Err(_) = self.eq_args(
|
||||
typeck_root_args,
|
||||
parent_args,
|
||||
location.to_locations(),
|
||||
locations,
|
||||
ConstraintCategory::BoringNoLocation,
|
||||
) {
|
||||
span_mirbug!(
|
||||
|
||||
@ -14,7 +14,6 @@
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::BodyOwnerKind;
|
||||
@ -77,6 +76,8 @@ pub struct UniversalRegions<'tcx> {
|
||||
pub unnormalized_input_tys: &'tcx [Ty<'tcx>],
|
||||
|
||||
pub yield_ty: Option<Ty<'tcx>>,
|
||||
|
||||
pub resume_ty: Option<Ty<'tcx>>,
|
||||
}
|
||||
|
||||
/// The "defining type" for this MIR. The key feature of the "defining
|
||||
@ -94,7 +95,7 @@ pub enum DefiningTy<'tcx> {
|
||||
/// The MIR is a coroutine. The signature is that coroutines take
|
||||
/// no parameters and return the result of
|
||||
/// `ClosureArgs::coroutine_return_ty`.
|
||||
Coroutine(DefId, GenericArgsRef<'tcx>, hir::Movability),
|
||||
Coroutine(DefId, GenericArgsRef<'tcx>),
|
||||
|
||||
/// The MIR is a fn item with the given `DefId` and args. The signature
|
||||
/// of the function can be bound then with the `fn_sig` query.
|
||||
@ -118,7 +119,7 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||
pub fn upvar_tys(self) -> &'tcx ty::List<Ty<'tcx>> {
|
||||
match self {
|
||||
DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(),
|
||||
DefiningTy::Coroutine(_, args, _) => args.as_coroutine().upvar_tys(),
|
||||
DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(),
|
||||
DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
|
||||
ty::List::empty()
|
||||
}
|
||||
@ -354,7 +355,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
err.note(format!("late-bound region is {:?}", self.to_region_vid(r)));
|
||||
});
|
||||
}
|
||||
DefiningTy::Coroutine(def_id, args, _) => {
|
||||
DefiningTy::Coroutine(def_id, args) => {
|
||||
let v = with_no_trimmed_paths!(
|
||||
args[tcx.generics_of(def_id).parent_count..]
|
||||
.iter()
|
||||
@ -526,9 +527,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
debug!("build: extern regions = {}..{}", first_extern_index, first_local_index);
|
||||
debug!("build: local regions = {}..{}", first_local_index, num_universals);
|
||||
|
||||
let yield_ty = match defining_ty {
|
||||
DefiningTy::Coroutine(_, args, _) => Some(args.as_coroutine().yield_ty()),
|
||||
_ => None,
|
||||
let (resume_ty, yield_ty) = match defining_ty {
|
||||
DefiningTy::Coroutine(_, args) => {
|
||||
let tys = args.as_coroutine();
|
||||
(Some(tys.resume_ty()), Some(tys.yield_ty()))
|
||||
}
|
||||
_ => (None, None),
|
||||
};
|
||||
|
||||
UniversalRegions {
|
||||
@ -542,6 +546,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
unnormalized_output_ty: *unnormalized_output_ty,
|
||||
unnormalized_input_tys,
|
||||
yield_ty,
|
||||
resume_ty,
|
||||
}
|
||||
}
|
||||
|
||||
@ -562,9 +567,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
|
||||
match *defining_ty.kind() {
|
||||
ty::Closure(def_id, args) => DefiningTy::Closure(def_id, args),
|
||||
ty::Coroutine(def_id, args, movability) => {
|
||||
DefiningTy::Coroutine(def_id, args, movability)
|
||||
}
|
||||
ty::Coroutine(def_id, args) => DefiningTy::Coroutine(def_id, args),
|
||||
ty::FnDef(def_id, args) => DefiningTy::FnDef(def_id, args),
|
||||
_ => span_bug!(
|
||||
tcx.def_span(self.mir_def),
|
||||
@ -620,7 +623,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
|
||||
let fr_args = match defining_ty {
|
||||
DefiningTy::Closure(_, args)
|
||||
| DefiningTy::Coroutine(_, args, _)
|
||||
| DefiningTy::Coroutine(_, args)
|
||||
| DefiningTy::InlineConst(_, args) => {
|
||||
// In the case of closures, we rely on the fact that
|
||||
// the first N elements in the ClosureArgs are
|
||||
@ -665,7 +668,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
kind: ty::BrEnv,
|
||||
};
|
||||
let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);
|
||||
let closure_ty = tcx.closure_env_ty(def_id, args, env_region).unwrap();
|
||||
let closure_ty = tcx.closure_env_ty(
|
||||
Ty::new_closure(tcx, def_id, args),
|
||||
args.as_closure().kind(),
|
||||
env_region,
|
||||
);
|
||||
|
||||
// The "inputs" of the closure in the
|
||||
// signature appear as a tuple. The MIR side
|
||||
@ -685,11 +692,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
DefiningTy::Coroutine(def_id, args, movability) => {
|
||||
DefiningTy::Coroutine(def_id, args) => {
|
||||
assert_eq!(self.mir_def.to_def_id(), def_id);
|
||||
let resume_ty = args.as_coroutine().resume_ty();
|
||||
let output = args.as_coroutine().return_ty();
|
||||
let coroutine_ty = Ty::new_coroutine(tcx, def_id, args, movability);
|
||||
let coroutine_ty = Ty::new_coroutine(tcx, def_id, args);
|
||||
let inputs_and_output =
|
||||
self.infcx.tcx.mk_type_list(&[coroutine_ty, resume_ty, output]);
|
||||
ty::Binder::dummy(inputs_and_output)
|
||||
|
||||
@ -31,7 +31,7 @@ pub fn expand(
|
||||
{
|
||||
(item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
|
||||
} else {
|
||||
ecx.sess.dcx().emit_err(errors::AllocErrorMustBeFn { span: item.span() });
|
||||
ecx.dcx().emit_err(errors::AllocErrorMustBeFn { span: item.span() });
|
||||
return vec![orig_item];
|
||||
};
|
||||
|
||||
|
||||
@ -422,7 +422,7 @@ fn parse_reg<'a>(
|
||||
ast::InlineAsmRegOrRegClass::Reg(symbol)
|
||||
}
|
||||
_ => {
|
||||
return Err(p.sess.create_err(errors::ExpectedRegisterClassOrExplicitRegister {
|
||||
return Err(p.dcx().create_err(errors::ExpectedRegisterClassOrExplicitRegister {
|
||||
span: p.token.span,
|
||||
}));
|
||||
}
|
||||
@ -458,7 +458,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
match expr_to_spanned_string(ecx, template_expr, msg) {
|
||||
Ok(template_part) => template_part,
|
||||
Err(err) => {
|
||||
if let Some((mut err, _)) = err {
|
||||
if let Some((err, _)) = err {
|
||||
err.emit();
|
||||
}
|
||||
return None;
|
||||
@ -541,7 +541,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
let err = parser.errors.remove(0);
|
||||
let err_sp = template_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
|
||||
let msg = format!("invalid asm template string: {}", err.description);
|
||||
let mut e = ecx.struct_span_err(err_sp, msg);
|
||||
let mut e = ecx.dcx().struct_span_err(err_sp, msg);
|
||||
e.span_label(err_sp, err.label + " in asm template string");
|
||||
if let Some(note) = err.note {
|
||||
e.note(note);
|
||||
@ -575,7 +575,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
|| args.reg_args.contains(idx)
|
||||
{
|
||||
let msg = format!("invalid reference to argument at index {idx}");
|
||||
let mut err = ecx.struct_span_err(span, msg);
|
||||
let mut err = ecx.dcx().struct_span_err(span, msg);
|
||||
err.span_label(span, "from here");
|
||||
|
||||
let positional_args = args.operands.len()
|
||||
@ -625,7 +625,8 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
None => {
|
||||
let msg = format!("there is no argument named `{name}`");
|
||||
let span = arg.position_span;
|
||||
ecx.struct_span_err(
|
||||
ecx.dcx()
|
||||
.struct_span_err(
|
||||
template_span
|
||||
.from_inner(InnerSpan::new(span.start, span.end)),
|
||||
msg,
|
||||
@ -645,7 +646,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
.ty_span
|
||||
.map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end)))
|
||||
.unwrap_or(template_sp);
|
||||
ecx.emit_err(errors::AsmModifierInvalid { span });
|
||||
ecx.dcx().emit_err(errors::AsmModifierInvalid { span });
|
||||
modifier = None;
|
||||
}
|
||||
|
||||
@ -692,16 +693,17 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
0 => {}
|
||||
1 => {
|
||||
let (sp, msg) = unused_operands.into_iter().next().unwrap();
|
||||
let mut err = ecx.struct_span_err(sp, msg);
|
||||
err.span_label(sp, msg);
|
||||
err.help(format!(
|
||||
ecx.dcx()
|
||||
.struct_span_err(sp, msg)
|
||||
.with_span_label(sp, msg)
|
||||
.with_help(format!(
|
||||
"if this argument is intentionally unused, \
|
||||
consider using it in an asm comment: `\"/*{help_str} */\"`"
|
||||
));
|
||||
err.emit();
|
||||
))
|
||||
.emit();
|
||||
}
|
||||
_ => {
|
||||
let mut err = ecx.struct_span_err(
|
||||
let mut err = ecx.dcx().struct_span_err(
|
||||
unused_operands.iter().map(|&(sp, _)| sp).collect::<Vec<Span>>(),
|
||||
"multiple unused asm arguments",
|
||||
);
|
||||
@ -746,7 +748,7 @@ pub(super) fn expand_asm<'cx>(
|
||||
};
|
||||
MacEager::expr(expr)
|
||||
}
|
||||
Err(mut err) => {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
@ -778,7 +780,7 @@ pub(super) fn expand_global_asm<'cx>(
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
}
|
||||
Err(mut err) => {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ pub fn expand_assert<'cx>(
|
||||
) -> Box<dyn MacResult + 'cx> {
|
||||
let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) {
|
||||
Ok(assert) => assert,
|
||||
Err(mut err) => {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
return DummyResult::any(span);
|
||||
}
|
||||
@ -115,7 +115,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes
|
||||
let mut parser = cx.new_parser_from_tts(stream);
|
||||
|
||||
if parser.token == token::Eof {
|
||||
return Err(cx.create_err(errors::AssertRequiresBoolean { span: sp }));
|
||||
return Err(cx.dcx().create_err(errors::AssertRequiresBoolean { span: sp }));
|
||||
}
|
||||
|
||||
let cond_expr = parser.parse_expr()?;
|
||||
@ -128,7 +128,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes
|
||||
//
|
||||
// Emit an error about semicolon and suggest removing it.
|
||||
if parser.token == token::Semi {
|
||||
cx.emit_err(errors::AssertRequiresExpression { span: sp, token: parser.token.span });
|
||||
cx.dcx().emit_err(errors::AssertRequiresExpression { span: sp, token: parser.token.span });
|
||||
parser.bump();
|
||||
}
|
||||
|
||||
@ -141,7 +141,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes
|
||||
let custom_message =
|
||||
if let token::Literal(token::Lit { kind: token::Str, .. }) = parser.token.kind {
|
||||
let comma = parser.prev_token.span.shrink_to_hi();
|
||||
cx.emit_err(errors::AssertMissingComma { span: parser.token.span, comma });
|
||||
cx.dcx().emit_err(errors::AssertMissingComma { span: parser.token.span, comma });
|
||||
|
||||
parse_custom_message(&mut parser)
|
||||
} else if parser.eat(&token::Comma) {
|
||||
|
||||
@ -303,7 +303,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
||||
| ExprKind::Continue(_)
|
||||
| ExprKind::Err
|
||||
| ExprKind::Field(_, _)
|
||||
| ExprKind::ForLoop(_, _, _, _)
|
||||
| ExprKind::ForLoop { .. }
|
||||
| ExprKind::FormatArgs(_)
|
||||
| ExprKind::IncludedBytes(..)
|
||||
| ExprKind::InlineAsm(_)
|
||||
|
||||
@ -22,13 +22,13 @@ pub fn expand_cfg(
|
||||
Ok(cfg) => {
|
||||
let matches_cfg = attr::cfg_matches(
|
||||
&cfg,
|
||||
&cx.sess.parse_sess,
|
||||
&cx.sess,
|
||||
cx.current_expansion.lint_node_id,
|
||||
Some(cx.ecfg.features),
|
||||
);
|
||||
MacEager::expr(cx.expr_bool(sp, matches_cfg))
|
||||
}
|
||||
Err(mut err) => {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
@ -39,7 +39,7 @@ fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<
|
||||
let mut p = cx.new_parser_from_tts(tts);
|
||||
|
||||
if p.token == token::Eof {
|
||||
return Err(cx.create_err(errors::RequiresCfgPattern { span }));
|
||||
return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
|
||||
}
|
||||
|
||||
let cfg = p.parse_meta_item()?;
|
||||
@ -47,7 +47,7 @@ fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<
|
||||
let _ = p.eat(&token::Comma);
|
||||
|
||||
if !p.eat(&token::Eof) {
|
||||
return Err(cx.create_err(errors::OneCfgPattern { span }));
|
||||
return Err(cx.dcx().create_err(errors::OneCfgPattern { span }));
|
||||
}
|
||||
|
||||
Ok(cfg)
|
||||
|
||||
@ -15,18 +15,18 @@ fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'
|
||||
match mi.meta_item_list() {
|
||||
None => {}
|
||||
Some([]) => {
|
||||
ecx.emit_err(UnspecifiedPath(mi.span));
|
||||
ecx.dcx().emit_err(UnspecifiedPath(mi.span));
|
||||
}
|
||||
Some([_, .., l]) => {
|
||||
ecx.emit_err(MultiplePaths(l.span()));
|
||||
ecx.dcx().emit_err(MultiplePaths(l.span()));
|
||||
}
|
||||
Some([nmi]) => match nmi.meta_item() {
|
||||
None => {
|
||||
ecx.emit_err(LiteralPath(nmi.span()));
|
||||
ecx.dcx().emit_err(LiteralPath(nmi.span()));
|
||||
}
|
||||
Some(mi) => {
|
||||
if !mi.is_word() {
|
||||
ecx.emit_err(HasArguments(mi.span));
|
||||
ecx.dcx().emit_err(HasArguments(mi.span));
|
||||
}
|
||||
return Some(&mi.path);
|
||||
}
|
||||
@ -61,7 +61,7 @@ impl MultiItemModifier for Expander {
|
||||
Ok(true) => ExpandResult::Ready(vec![item]),
|
||||
Ok(false) => ExpandResult::Ready(Vec::new()),
|
||||
Err(Indeterminate) if ecx.force_mode => {
|
||||
ecx.emit_err(errors::CfgAccessibleIndeterminate { span });
|
||||
ecx.dcx().emit_err(errors::CfgAccessibleIndeterminate { span });
|
||||
ExpandResult::Ready(vec![item])
|
||||
}
|
||||
Err(Indeterminate) => ExpandResult::Retry(item),
|
||||
|
||||
@ -200,7 +200,7 @@ impl CfgEval<'_, '_> {
|
||||
parser.capture_cfg = true;
|
||||
match parse_annotatable_with(&mut parser) {
|
||||
Ok(a) => annotatable = a,
|
||||
Err(mut err) => {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
return Some(annotatable);
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String])
|
||||
let start_span = parser.token.span;
|
||||
let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) {
|
||||
Ok(ai) => ai,
|
||||
Err(mut err) => {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ pub fn expand_compile_error<'cx>(
|
||||
reason = "diagnostic message is specified by user"
|
||||
)]
|
||||
#[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")]
|
||||
cx.span_err(sp, var.to_string());
|
||||
cx.dcx().span_err(sp, var.to_string());
|
||||
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
|
||||
@ -33,11 +33,11 @@ pub fn expand_concat(
|
||||
accumulator.push_str(&b.to_string());
|
||||
}
|
||||
Ok(ast::LitKind::CStr(..)) => {
|
||||
cx.emit_err(errors::ConcatCStrLit { span: e.span });
|
||||
cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span });
|
||||
has_errors = true;
|
||||
}
|
||||
Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
|
||||
cx.emit_err(errors::ConcatBytestr { span: e.span });
|
||||
cx.dcx().emit_err(errors::ConcatBytestr { span: e.span });
|
||||
has_errors = true;
|
||||
}
|
||||
Ok(ast::LitKind::Err) => {
|
||||
@ -63,7 +63,7 @@ pub fn expand_concat(
|
||||
}
|
||||
}
|
||||
ast::ExprKind::IncludedBytes(..) => {
|
||||
cx.emit_err(errors::ConcatBytestr { span: e.span });
|
||||
cx.dcx().emit_err(errors::ConcatBytestr { span: e.span });
|
||||
}
|
||||
ast::ExprKind::Err => {
|
||||
has_errors = true;
|
||||
@ -75,7 +75,7 @@ pub fn expand_concat(
|
||||
}
|
||||
|
||||
if !missing_literal.is_empty() {
|
||||
cx.emit_err(errors::ConcatMissingLiteral { spans: missing_literal });
|
||||
cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal });
|
||||
return DummyResult::any(sp);
|
||||
} else if has_errors {
|
||||
return DummyResult::any(sp);
|
||||
|
||||
@ -17,16 +17,17 @@ fn invalid_type_err(
|
||||
ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob,
|
||||
};
|
||||
let snippet = cx.sess.source_map().span_to_snippet(span).ok();
|
||||
let dcx = cx.dcx();
|
||||
match ast::LitKind::from_token_lit(token_lit) {
|
||||
Ok(ast::LitKind::CStr(_, _)) => {
|
||||
// FIXME(c_str_literals): should concatenation of C string literals
|
||||
// include the null bytes in the end?
|
||||
cx.emit_err(errors::ConcatCStrLit { span: span });
|
||||
// Avoid ambiguity in handling of terminal `NUL` by refusing to
|
||||
// concatenate C string literals as bytes.
|
||||
dcx.emit_err(errors::ConcatCStrLit { span: span });
|
||||
}
|
||||
Ok(ast::LitKind::Char(_)) => {
|
||||
let sugg =
|
||||
snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet });
|
||||
cx.sess.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg });
|
||||
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg });
|
||||
}
|
||||
Ok(ast::LitKind::Str(_, _)) => {
|
||||
// suggestion would be invalid if we are nested
|
||||
@ -35,29 +36,29 @@ fn invalid_type_err(
|
||||
} else {
|
||||
None
|
||||
};
|
||||
cx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg });
|
||||
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg });
|
||||
}
|
||||
Ok(ast::LitKind::Float(_, _)) => {
|
||||
cx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None });
|
||||
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None });
|
||||
}
|
||||
Ok(ast::LitKind::Bool(_)) => {
|
||||
cx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None });
|
||||
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None });
|
||||
}
|
||||
Ok(ast::LitKind::Err) => {}
|
||||
Ok(ast::LitKind::Int(_, _)) if !is_nested => {
|
||||
let sugg =
|
||||
snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet });
|
||||
cx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg });
|
||||
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg });
|
||||
}
|
||||
Ok(ast::LitKind::Int(
|
||||
val,
|
||||
ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
|
||||
)) => {
|
||||
assert!(val > u8::MAX.into()); // must be an error
|
||||
cx.emit_err(ConcatBytesOob { span });
|
||||
assert!(val.get() > u8::MAX.into()); // must be an error
|
||||
dcx.emit_err(ConcatBytesOob { span });
|
||||
}
|
||||
Ok(ast::LitKind::Int(_, _)) => {
|
||||
cx.emit_err(ConcatBytesNonU8 { span });
|
||||
dcx.emit_err(ConcatBytesNonU8 { span });
|
||||
}
|
||||
Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(),
|
||||
Err(err) => {
|
||||
@ -72,10 +73,11 @@ fn handle_array_element(
|
||||
missing_literals: &mut Vec<rustc_span::Span>,
|
||||
expr: &P<rustc_ast::Expr>,
|
||||
) -> Option<u8> {
|
||||
let dcx = cx.dcx();
|
||||
match expr.kind {
|
||||
ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => {
|
||||
if !*has_errors {
|
||||
cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
|
||||
dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
|
||||
}
|
||||
*has_errors = true;
|
||||
None
|
||||
@ -84,12 +86,12 @@ fn handle_array_element(
|
||||
Ok(ast::LitKind::Int(
|
||||
val,
|
||||
ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
|
||||
)) if val <= u8::MAX.into() => Some(val as u8),
|
||||
)) if val.get() <= u8::MAX.into() => Some(val.get() as u8),
|
||||
|
||||
Ok(ast::LitKind::Byte(val)) => Some(val),
|
||||
Ok(ast::LitKind::ByteStr(..)) => {
|
||||
if !*has_errors {
|
||||
cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true });
|
||||
dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true });
|
||||
}
|
||||
*has_errors = true;
|
||||
None
|
||||
@ -104,7 +106,7 @@ fn handle_array_element(
|
||||
},
|
||||
ast::ExprKind::IncludedBytes(..) => {
|
||||
if !*has_errors {
|
||||
cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
|
||||
dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
|
||||
}
|
||||
*has_errors = true;
|
||||
None
|
||||
@ -146,12 +148,12 @@ pub fn expand_concat_bytes(
|
||||
if let Some(elem) =
|
||||
handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
|
||||
{
|
||||
for _ in 0..count_val {
|
||||
for _ in 0..count_val.get() {
|
||||
accumulator.push(elem);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cx.emit_err(errors::ConcatBytesBadRepeat { span: count.value.span });
|
||||
cx.dcx().emit_err(errors::ConcatBytesBadRepeat { span: count.value.span });
|
||||
}
|
||||
}
|
||||
&ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
|
||||
@ -180,7 +182,7 @@ pub fn expand_concat_bytes(
|
||||
}
|
||||
}
|
||||
if !missing_literals.is_empty() {
|
||||
cx.emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals });
|
||||
cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals });
|
||||
return base::MacEager::expr(DummyResult::raw_expr(sp, true));
|
||||
} else if has_errors {
|
||||
return base::MacEager::expr(DummyResult::raw_expr(sp, true));
|
||||
|
||||
@ -14,7 +14,7 @@ pub fn expand_concat_idents<'cx>(
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn base::MacResult + 'cx> {
|
||||
if tts.is_empty() {
|
||||
cx.emit_err(errors::ConcatIdentsMissingArgs { span: sp });
|
||||
cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp });
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ pub fn expand_concat_idents<'cx>(
|
||||
match e {
|
||||
TokenTree::Token(Token { kind: token::Comma, .. }, _) => {}
|
||||
_ => {
|
||||
cx.emit_err(errors::ConcatIdentsMissingComma { span: sp });
|
||||
cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp });
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
}
|
||||
@ -36,7 +36,7 @@ pub fn expand_concat_idents<'cx>(
|
||||
}
|
||||
}
|
||||
|
||||
cx.emit_err(errors::ConcatIdentsIdentArgs { span: sp });
|
||||
cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp });
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ fn report_bad_target(
|
||||
let bad_target =
|
||||
!matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..)));
|
||||
if bad_target {
|
||||
return Err(sess.emit_err(errors::BadDeriveTarget { span, item: item.span() }));
|
||||
return Err(sess.dcx().emit_err(errors::BadDeriveTarget { span, item: item.span() }));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -134,7 +134,7 @@ fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) {
|
||||
}
|
||||
_ => errors::BadDeriveLitHelp::Other,
|
||||
};
|
||||
sess.emit_err(errors::BadDeriveLit { span: lit.span, help });
|
||||
sess.dcx().emit_err(errors::BadDeriveLit { span: lit.span, help });
|
||||
}
|
||||
|
||||
fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
|
||||
@ -143,10 +143,10 @@ fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
|
||||
match meta.kind {
|
||||
MetaItemKind::Word => {}
|
||||
MetaItemKind::List(..) => {
|
||||
sess.emit_err(errors::DerivePathArgsList { span });
|
||||
sess.dcx().emit_err(errors::DerivePathArgsList { span });
|
||||
}
|
||||
MetaItemKind::NameValue(..) => {
|
||||
sess.emit_err(errors::DerivePathArgsValue { span });
|
||||
sess.dcx().emit_err(errors::DerivePathArgsValue { span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,10 +62,10 @@ pub fn expand_deriving_clone(
|
||||
cs_clone_simple("Clone", c, s, sub, true)
|
||||
}));
|
||||
}
|
||||
_ => cx.span_bug(span, "`#[derive(Clone)]` on wrong item kind"),
|
||||
_ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"),
|
||||
},
|
||||
|
||||
_ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
|
||||
_ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
|
||||
}
|
||||
|
||||
let trait_def = TraitDef {
|
||||
@ -144,7 +144,7 @@ fn cs_clone_simple(
|
||||
process_variant(&variant.data);
|
||||
}
|
||||
}
|
||||
_ => cx.span_bug(
|
||||
_ => cx.dcx().span_bug(
|
||||
trait_span,
|
||||
format!("unexpected substructure in simple `derive({name})`"),
|
||||
),
|
||||
@ -180,10 +180,10 @@ fn cs_clone(
|
||||
vdata = &variant.data;
|
||||
}
|
||||
EnumTag(..) | AllFieldlessEnum(..) => {
|
||||
cx.span_bug(trait_span, format!("enum tags in `derive({name})`",))
|
||||
cx.dcx().span_bug(trait_span, format!("enum tags in `derive({name})`",))
|
||||
}
|
||||
StaticEnum(..) | StaticStruct(..) => {
|
||||
cx.span_bug(trait_span, format!("associated function in `derive({name})`"))
|
||||
cx.dcx().span_bug(trait_span, format!("associated function in `derive({name})`"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,7 +193,7 @@ fn cs_clone(
|
||||
.iter()
|
||||
.map(|field| {
|
||||
let Some(ident) = field.name else {
|
||||
cx.span_bug(
|
||||
cx.dcx().span_bug(
|
||||
trait_span,
|
||||
format!("unnamed field in normal struct in `derive({name})`",),
|
||||
);
|
||||
|
||||
@ -19,19 +19,6 @@ pub fn expand_deriving_eq(
|
||||
) {
|
||||
let span = cx.with_def_site_ctxt(span);
|
||||
|
||||
let structural_trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(marker::StructuralEq),
|
||||
skip_path_as_bound: true, // crucial!
|
||||
needs_copy_as_bound_if_packed: false,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: true,
|
||||
methods: Vec::new(),
|
||||
associated_types: Vec::new(),
|
||||
is_const: false,
|
||||
};
|
||||
structural_trait_def.expand(cx, mitem, item, push);
|
||||
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(cmp::Eq),
|
||||
@ -99,7 +86,7 @@ fn cs_total_eq_assert(
|
||||
process_variant(&variant.data);
|
||||
}
|
||||
}
|
||||
_ => cx.span_bug(trait_span, "unexpected substructure in `derive(Eq)`"),
|
||||
_ => cx.dcx().span_bug(trait_span, "unexpected substructure in `derive(Eq)`"),
|
||||
}
|
||||
BlockOrExpr::new_stmts(stmts)
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> Bl
|
||||
|cx, fold| match fold {
|
||||
CsFold::Single(field) => {
|
||||
let [other_expr] = &field.other_selflike_exprs[..] else {
|
||||
cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
|
||||
cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
|
||||
};
|
||||
let args = thin_vec![field.self_expr.clone(), other_expr.clone()];
|
||||
cx.expr_call_global(field.span, cmp_path.clone(), args)
|
||||
|
||||
@ -26,7 +26,8 @@ pub fn expand_deriving_partial_eq(
|
||||
|cx, fold| match fold {
|
||||
CsFold::Single(field) => {
|
||||
let [other_expr] = &field.other_selflike_exprs[..] else {
|
||||
cx.span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
|
||||
cx.dcx()
|
||||
.span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
|
||||
};
|
||||
|
||||
// We received arguments of type `&T`. Convert them to type `T` by stripping
|
||||
|
||||
@ -95,7 +95,7 @@ fn cs_partial_cmp(
|
||||
|cx, fold| match fold {
|
||||
CsFold::Single(field) => {
|
||||
let [other_expr] = &field.other_selflike_exprs[..] else {
|
||||
cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
|
||||
cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
|
||||
};
|
||||
let args = thin_vec![field.self_expr.clone(), other_expr.clone()];
|
||||
cx.expr_call_global(field.span, partial_cmp_path.clone(), args)
|
||||
|
||||
@ -55,7 +55,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
|
||||
EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
|
||||
AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr),
|
||||
EnumTag(..) | StaticStruct(..) | StaticEnum(..) => {
|
||||
cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
|
||||
cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -177,7 +177,7 @@ fn decodable_substructure(
|
||||
],
|
||||
)
|
||||
}
|
||||
_ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
|
||||
_ => cx.dcx().bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
|
||||
};
|
||||
BlockOrExpr::new_expr(expr)
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ pub fn expand_deriving_default(
|
||||
default_struct_substructure(cx, trait_span, substr, fields)
|
||||
}
|
||||
StaticEnum(enum_def, _) => default_enum_substructure(cx, trait_span, enum_def),
|
||||
_ => cx.span_bug(trait_span, "method in `derive(Default)`"),
|
||||
_ => cx.dcx().span_bug(trait_span, "method in `derive(Default)`"),
|
||||
}
|
||||
})),
|
||||
}],
|
||||
@ -120,7 +120,7 @@ fn extract_default_variant<'a>(
|
||||
let suggs = possible_defaults
|
||||
.map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident })
|
||||
.collect();
|
||||
cx.emit_err(errors::NoDefaultVariant { span: trait_span, suggs });
|
||||
cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, suggs });
|
||||
|
||||
return Err(());
|
||||
}
|
||||
@ -140,7 +140,7 @@ fn extract_default_variant<'a>(
|
||||
.then_some(errors::MultipleDefaultsSugg { spans, ident: variant.ident })
|
||||
})
|
||||
.collect();
|
||||
cx.emit_err(errors::MultipleDefaults {
|
||||
cx.dcx().emit_err(errors::MultipleDefaults {
|
||||
span: trait_span,
|
||||
first: first.span,
|
||||
additional: rest.iter().map(|v| v.span).collect(),
|
||||
@ -151,12 +151,12 @@ fn extract_default_variant<'a>(
|
||||
};
|
||||
|
||||
if !matches!(variant.data, VariantData::Unit(..)) {
|
||||
cx.emit_err(errors::NonUnitDefault { span: variant.ident.span });
|
||||
cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span });
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) {
|
||||
cx.emit_err(errors::NonExhaustiveDefault {
|
||||
cx.dcx().emit_err(errors::NonExhaustiveDefault {
|
||||
span: variant.ident.span,
|
||||
non_exhaustive: non_exhaustive_attr.span,
|
||||
});
|
||||
@ -176,14 +176,14 @@ fn validate_default_attribute(
|
||||
|
||||
let attr = match attrs.as_slice() {
|
||||
[attr] => attr,
|
||||
[] => cx.bug(
|
||||
[] => cx.dcx().bug(
|
||||
"this method must only be called with a variant that has a `#[default]` attribute",
|
||||
),
|
||||
[first, rest @ ..] => {
|
||||
let sugg = errors::MultipleDefaultAttrsSugg {
|
||||
spans: rest.iter().map(|attr| attr.span).collect(),
|
||||
};
|
||||
cx.emit_err(errors::MultipleDefaultAttrs {
|
||||
cx.dcx().emit_err(errors::MultipleDefaultAttrs {
|
||||
span: default_variant.ident.span,
|
||||
first: first.span,
|
||||
first_rest: rest[0].span,
|
||||
@ -196,7 +196,7 @@ fn validate_default_attribute(
|
||||
}
|
||||
};
|
||||
if !attr.is_word() {
|
||||
cx.emit_err(errors::DefaultHasArg { span: attr.span });
|
||||
cx.dcx().emit_err(errors::DefaultHasArg { span: attr.span });
|
||||
|
||||
return Err(());
|
||||
}
|
||||
@ -210,7 +210,7 @@ struct DetectNonVariantDefaultAttr<'a, 'b> {
|
||||
impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, 'b> {
|
||||
fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) {
|
||||
if attr.has_name(kw::Default) {
|
||||
self.cx.emit_err(errors::NonUnitDefault { span: attr.span });
|
||||
self.cx.dcx().emit_err(errors::NonUnitDefault { span: attr.span });
|
||||
}
|
||||
|
||||
rustc_ast::visit::walk_attribute(self, attr);
|
||||
|
||||
@ -296,6 +296,6 @@ fn encodable_substructure(
|
||||
BlockOrExpr::new_mixed(thin_vec![me], Some(expr))
|
||||
}
|
||||
|
||||
_ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"),
|
||||
_ => cx.dcx().bug("expected Struct or EnumMatching in derive(Encodable)"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -430,7 +430,7 @@ fn find_type_parameters(
|
||||
}
|
||||
|
||||
fn visit_mac_call(&mut self, mac: &ast::MacCall) {
|
||||
self.cx.emit_err(errors::DeriveMacroCall { span: mac.span() });
|
||||
self.cx.dcx().emit_err(errors::DeriveMacroCall { span: mac.span() });
|
||||
}
|
||||
}
|
||||
|
||||
@ -503,7 +503,7 @@ impl<'a> TraitDef<'a> {
|
||||
is_packed,
|
||||
)
|
||||
} else {
|
||||
cx.emit_err(errors::DeriveUnion { span: mitem.span });
|
||||
cx.dcx().emit_err(errors::DeriveUnion { span: mitem.span });
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -974,7 +974,7 @@ impl<'a> MethodDef<'a> {
|
||||
match ty {
|
||||
// Selflike (`&Self`) arguments only occur in non-static methods.
|
||||
Ref(box Self_, _) if !self.is_static() => selflike_args.push(arg_expr),
|
||||
Self_ => cx.span_bug(span, "`Self` in non-return position"),
|
||||
Self_ => cx.dcx().span_bug(span, "`Self` in non-return position"),
|
||||
_ => nonselflike_args.push(arg_expr),
|
||||
}
|
||||
}
|
||||
@ -1441,9 +1441,9 @@ impl<'a> TraitDef<'a> {
|
||||
|
||||
let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
|
||||
match (just_spans.is_empty(), named_idents.is_empty()) {
|
||||
(false, false) => {
|
||||
cx.span_bug(self.span, "a struct with named and unnamed fields in generic `derive`")
|
||||
}
|
||||
(false, false) => cx
|
||||
.dcx()
|
||||
.span_bug(self.span, "a struct with named and unnamed fields in generic `derive`"),
|
||||
// named fields
|
||||
(_, false) => Named(named_idents),
|
||||
// unnamed fields
|
||||
@ -1489,7 +1489,7 @@ impl<'a> TraitDef<'a> {
|
||||
let field_pats = pieces_iter
|
||||
.map(|(sp, ident, pat)| {
|
||||
if ident.is_none() {
|
||||
cx.span_bug(
|
||||
cx.dcx().span_bug(
|
||||
sp,
|
||||
"a braced struct with unnamed fields in `derive`",
|
||||
);
|
||||
@ -1707,7 +1707,9 @@ where
|
||||
tag_check_expr
|
||||
}
|
||||
}
|
||||
StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
|
||||
AllFieldlessEnum(..) => cx.span_bug(trait_span, "fieldless enum in `derive`"),
|
||||
StaticEnum(..) | StaticStruct(..) => {
|
||||
cx.dcx().span_bug(trait_span, "static function in `derive`")
|
||||
}
|
||||
AllFieldlessEnum(..) => cx.dcx().span_bug(trait_span, "fieldless enum in `derive`"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,8 +138,8 @@ impl Ty {
|
||||
cx.path_all(span, false, vec![self_ty], params)
|
||||
}
|
||||
Path(p) => p.to_path(cx, span, self_ty, generics),
|
||||
Ref(..) => cx.span_bug(span, "ref in a path in generic `derive`"),
|
||||
Unit => cx.span_bug(span, "unit in a path in generic `derive`"),
|
||||
Ref(..) => cx.dcx().span_bug(span, "ref in a path in generic `derive`"),
|
||||
Unit => cx.dcx().span_bug(span, "unit in a path in generic `derive`"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ fn hash_substructure(
|
||||
substr: &Substructure<'_>,
|
||||
) -> BlockOrExpr {
|
||||
let [state_expr] = substr.nonselflike_args else {
|
||||
cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`");
|
||||
cx.dcx().span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`");
|
||||
};
|
||||
let call_hash = |span, expr| {
|
||||
let hash_path = {
|
||||
@ -75,7 +75,7 @@ fn hash_substructure(
|
||||
let stmts = thin_vec![call_hash(tag_field.span, tag_field.self_expr.clone())];
|
||||
(stmts, match_expr.clone())
|
||||
}
|
||||
_ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`"),
|
||||
_ => cx.dcx().span_bug(trait_span, "impossible substructure in `derive(Hash)`"),
|
||||
};
|
||||
|
||||
BlockOrExpr::new_mixed(stmts, match_expr)
|
||||
|
||||
@ -18,7 +18,7 @@ fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Option<Symbol> {
|
||||
if let Some(value) = cx.sess.opts.logical_env.get(var) {
|
||||
return Some(Symbol::intern(value));
|
||||
}
|
||||
// If the environment variable was not defined with the `--env` option, we try to retrieve it
|
||||
// If the environment variable was not defined with the `--env-set` option, we try to retrieve it
|
||||
// from rustc's environment.
|
||||
env::var(var).ok().as_deref().map(Symbol::intern)
|
||||
}
|
||||
@ -66,7 +66,7 @@ pub fn expand_env<'cx>(
|
||||
) -> Box<dyn base::MacResult + 'cx> {
|
||||
let mut exprs = match get_exprs_from_tts(cx, tts) {
|
||||
Some(exprs) if exprs.is_empty() || exprs.len() > 2 => {
|
||||
cx.emit_err(errors::EnvTakesArgs { span: sp });
|
||||
cx.dcx().emit_err(errors::EnvTakesArgs { span: sp });
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
None => return DummyResult::any(sp),
|
||||
@ -101,15 +101,15 @@ pub fn expand_env<'cx>(
|
||||
};
|
||||
|
||||
if let Some(msg_from_user) = custom_msg {
|
||||
cx.emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user });
|
||||
cx.dcx().emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user });
|
||||
} else if is_cargo_env_var(var.as_str()) {
|
||||
cx.emit_err(errors::EnvNotDefined::CargoEnvVar {
|
||||
cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar {
|
||||
span,
|
||||
var: *symbol,
|
||||
var_expr: var_expr.ast_deref(),
|
||||
});
|
||||
} else {
|
||||
cx.emit_err(errors::EnvNotDefined::CustomEnvVar {
|
||||
cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar {
|
||||
span,
|
||||
var: *symbol,
|
||||
var_expr: var_expr.ast_deref(),
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use rustc_errors::{
|
||||
AddToDiagnostic, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
|
||||
SingleLabelManySpans,
|
||||
codes::*, AddToDiagnostic, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic,
|
||||
Level, MultiSpan, SingleLabelManySpans,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||
@ -269,7 +269,7 @@ pub(crate) struct ConcatIdentsIdentArgs {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_bad_derive_target, code = "E0774")]
|
||||
#[diag(builtin_macros_bad_derive_target, code = E0774)]
|
||||
pub(crate) struct BadDeriveTarget {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
@ -283,7 +283,7 @@ pub(crate) struct BadDeriveTarget {
|
||||
pub(crate) struct TestsNotSupport {}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_unexpected_lit, code = "E0777")]
|
||||
#[diag(builtin_macros_unexpected_lit, code = E0777)]
|
||||
pub(crate) struct BadDeriveLit {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
@ -446,15 +446,15 @@ pub(crate) struct EnvNotDefinedWithUserMessage {
|
||||
}
|
||||
|
||||
// Hand-written implementation to support custom user messages.
|
||||
impl<'a> IntoDiagnostic<'a> for EnvNotDefinedWithUserMessage {
|
||||
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMessage {
|
||||
#[track_caller]
|
||||
fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
|
||||
#[expect(
|
||||
rustc::untranslatable_diagnostic,
|
||||
reason = "cannot translate user-provided messages"
|
||||
)]
|
||||
let mut diag = dcx.struct_err(self.msg_from_user.to_string());
|
||||
diag.set_span(self.span);
|
||||
let mut diag = DiagnosticBuilder::new(dcx, level, self.msg_from_user.to_string());
|
||||
diag.span(self.span);
|
||||
diag
|
||||
}
|
||||
}
|
||||
@ -618,7 +618,7 @@ impl AddToDiagnostic for FormatUnusedArg {
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
diag.set_arg("named", self.named);
|
||||
diag.arg("named", self.named);
|
||||
let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
|
||||
diag.span_label(self.span, msg);
|
||||
}
|
||||
@ -801,22 +801,25 @@ pub(crate) struct AsmClobberNoReg {
|
||||
pub(crate) clobbers: Vec<Span>,
|
||||
}
|
||||
|
||||
impl<'a> IntoDiagnostic<'a> for AsmClobberNoReg {
|
||||
fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
let mut diag = dcx.struct_err(crate::fluent_generated::builtin_macros_asm_clobber_no_reg);
|
||||
diag.set_span(self.spans.clone());
|
||||
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg {
|
||||
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
|
||||
// eager translation as `span_labels` takes `AsRef<str>`
|
||||
let lbl1 = dcx.eagerly_translate_to_string(
|
||||
crate::fluent_generated::builtin_macros_asm_clobber_abi,
|
||||
[].into_iter(),
|
||||
);
|
||||
diag.span_labels(self.clobbers, &lbl1);
|
||||
let lbl2 = dcx.eagerly_translate_to_string(
|
||||
crate::fluent_generated::builtin_macros_asm_clobber_outputs,
|
||||
[].into_iter(),
|
||||
);
|
||||
diag.span_labels(self.spans, &lbl2);
|
||||
diag
|
||||
DiagnosticBuilder::new(
|
||||
dcx,
|
||||
level,
|
||||
crate::fluent_generated::builtin_macros_asm_clobber_no_reg,
|
||||
)
|
||||
.with_span(self.spans.clone())
|
||||
.with_span_labels(self.clobbers, &lbl1)
|
||||
.with_span_labels(self.spans, &lbl2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8,9 +8,7 @@ use rustc_ast::{
|
||||
FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait,
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{
|
||||
Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, PResult, SingleLabelManySpans,
|
||||
};
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan, PResult, SingleLabelManySpans};
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_parse_format as parse;
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
@ -71,7 +69,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
||||
let mut p = ecx.new_parser_from_tts(tts);
|
||||
|
||||
if p.token == token::Eof {
|
||||
return Err(ecx.create_err(errors::FormatRequiresString { span: sp }));
|
||||
return Err(ecx.dcx().create_err(errors::FormatRequiresString { span: sp }));
|
||||
}
|
||||
|
||||
let first_token = &p.token;
|
||||
@ -101,7 +99,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
||||
}
|
||||
|
||||
match p.expect(&token::Comma) {
|
||||
Err(mut err) => {
|
||||
Err(err) => {
|
||||
match token::TokenKind::Comma.similar_tokens() {
|
||||
Some(tks) if tks.contains(&p.token.kind) => {
|
||||
// If a similar token is found, then it may be a typo. We
|
||||
@ -128,7 +126,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
||||
p.expect(&token::Eq)?;
|
||||
let expr = p.parse_expr()?;
|
||||
if let Some((_, prev)) = args.by_name(ident.name) {
|
||||
ecx.emit_err(errors::FormatDuplicateArg {
|
||||
ecx.dcx().emit_err(errors::FormatDuplicateArg {
|
||||
span: ident.span,
|
||||
prev: prev.kind.ident().unwrap().span,
|
||||
duplicate: ident.span,
|
||||
@ -141,7 +139,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
||||
_ => {
|
||||
let expr = p.parse_expr()?;
|
||||
if !args.named_args().is_empty() {
|
||||
ecx.emit_err(errors::PositionalAfterNamed {
|
||||
return Err(ecx.dcx().create_err(errors::PositionalAfterNamed {
|
||||
span: expr.span,
|
||||
args: args
|
||||
.named_args()
|
||||
@ -149,7 +147,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
||||
.filter_map(|a| a.kind.ident().map(|ident| (a, ident)))
|
||||
.map(|(arg, n)| n.span.to(arg.expr.span))
|
||||
.collect(),
|
||||
});
|
||||
}));
|
||||
}
|
||||
args.add(FormatArgument { kind: FormatArgumentKind::Normal, expr });
|
||||
}
|
||||
@ -295,7 +293,7 @@ fn make_format_args(
|
||||
}
|
||||
}
|
||||
}
|
||||
ecx.emit_err(e);
|
||||
ecx.dcx().emit_err(e);
|
||||
return Err(());
|
||||
}
|
||||
|
||||
@ -315,6 +313,8 @@ fn make_format_args(
|
||||
}
|
||||
use ArgRef::*;
|
||||
|
||||
let mut unnamed_arg_after_named_arg = false;
|
||||
|
||||
let mut lookup_arg = |arg: ArgRef<'_>,
|
||||
span: Option<Span>,
|
||||
used_as: PositionUsedAs,
|
||||
@ -353,7 +353,8 @@ fn make_format_args(
|
||||
} else {
|
||||
// For the moment capturing variables from format strings expanded from macros is
|
||||
// disabled (see RFC #2795)
|
||||
ecx.emit_err(errors::FormatNoArgNamed { span, name });
|
||||
ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name });
|
||||
unnamed_arg_after_named_arg = true;
|
||||
DummyResult::raw_expr(span, true)
|
||||
};
|
||||
Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr }))
|
||||
@ -512,7 +513,8 @@ fn make_format_args(
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !unused.is_empty() {
|
||||
let has_unused = !unused.is_empty();
|
||||
if has_unused {
|
||||
// If there's a lot of unused arguments,
|
||||
// let's check if this format arguments looks like another syntax (printf / shell).
|
||||
let detect_foreign_fmt = unused.len() > args.explicit_args().len() / 2;
|
||||
@ -531,7 +533,7 @@ fn make_format_args(
|
||||
|
||||
// Only check for unused named argument names if there are no other errors to avoid causing
|
||||
// too much noise in output errors, such as when a named argument is entirely unused.
|
||||
if invalid_refs.is_empty() && ecx.sess.err_count() == 0 {
|
||||
if invalid_refs.is_empty() && !has_unused && !unnamed_arg_after_named_arg {
|
||||
for &(index, span, used_as) in &numeric_refences_to_named_arg {
|
||||
let (position_sp_to_replace, position_sp_for_msg) = match used_as {
|
||||
Placeholder(pspan) => (span, pspan),
|
||||
@ -587,7 +589,7 @@ fn invalid_placeholder_type_error(
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
ecx.emit_err(errors::FormatUnknownTrait { span: sp.unwrap_or(fmt_span), ty, suggs });
|
||||
ecx.dcx().emit_err(errors::FormatUnknownTrait { span: sp.unwrap_or(fmt_span), ty, suggs });
|
||||
}
|
||||
|
||||
fn report_missing_placeholders(
|
||||
@ -602,12 +604,12 @@ fn report_missing_placeholders(
|
||||
fmt_span: Span,
|
||||
) {
|
||||
let mut diag = if let &[(span, named)] = &unused[..] {
|
||||
ecx.create_err(errors::FormatUnusedArg { span, named })
|
||||
ecx.dcx().create_err(errors::FormatUnusedArg { span, named })
|
||||
} else {
|
||||
let unused_labels =
|
||||
unused.iter().map(|&(span, named)| errors::FormatUnusedArg { span, named }).collect();
|
||||
let unused_spans = unused.iter().map(|&(span, _)| span).collect();
|
||||
ecx.create_err(errors::FormatUnusedArgs {
|
||||
ecx.dcx().create_err(errors::FormatUnusedArgs {
|
||||
fmt: fmt_span,
|
||||
unused: unused_spans,
|
||||
unused_labels,
|
||||
@ -632,8 +634,7 @@ fn report_missing_placeholders(
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !placeholders.is_empty() {
|
||||
if let Some(mut new_diag) = report_redundant_format_arguments(ecx, args, used, placeholders)
|
||||
{
|
||||
if let Some(new_diag) = report_redundant_format_arguments(ecx, args, used, placeholders) {
|
||||
diag.cancel();
|
||||
new_diag.emit();
|
||||
return;
|
||||
@ -726,7 +727,7 @@ fn report_redundant_format_arguments<'a>(
|
||||
args: &FormatArguments,
|
||||
used: &[bool],
|
||||
placeholders: Vec<(Span, &str)>,
|
||||
) -> Option<DiagnosticBuilder<'a, ErrorGuaranteed>> {
|
||||
) -> Option<DiagnosticBuilder<'a>> {
|
||||
let mut fmt_arg_indices = vec![];
|
||||
let mut args_spans = vec![];
|
||||
let mut fmt_spans = vec![];
|
||||
@ -778,7 +779,7 @@ fn report_redundant_format_arguments<'a>(
|
||||
None
|
||||
};
|
||||
|
||||
return Some(ecx.create_err(errors::FormatRedundantArgs {
|
||||
return Some(ecx.dcx().create_err(errors::FormatRedundantArgs {
|
||||
n: args_spans.len(),
|
||||
span: MultiSpan::from(args_spans),
|
||||
note: multispan,
|
||||
@ -878,14 +879,13 @@ fn report_invalid_references(
|
||||
} else {
|
||||
MultiSpan::from_spans(spans)
|
||||
};
|
||||
e = ecx.create_err(errors::FormatPositionalMismatch {
|
||||
e = ecx.dcx().create_err(errors::FormatPositionalMismatch {
|
||||
span,
|
||||
n: num_placeholders,
|
||||
desc: num_args_desc,
|
||||
highlight: SingleLabelManySpans {
|
||||
spans: args.explicit_args().iter().map(|arg| arg.expr.span).collect(),
|
||||
label: "",
|
||||
kind: rustc_errors::LabelKind::Label,
|
||||
},
|
||||
});
|
||||
// Point out `{:.*}` placeholders: those take an extra argument.
|
||||
@ -945,7 +945,7 @@ fn report_invalid_references(
|
||||
head = indexes.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(", ")
|
||||
)
|
||||
};
|
||||
e = ecx.struct_span_err(
|
||||
e = ecx.dcx().struct_span_err(
|
||||
span,
|
||||
format!("invalid reference to positional {arg_list} ({num_args_desc})"),
|
||||
);
|
||||
@ -979,7 +979,7 @@ fn expand_format_args_impl<'cx>(
|
||||
MacEager::expr(DummyResult::raw_expr(sp, true))
|
||||
}
|
||||
}
|
||||
Err(mut err) => {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ pub fn expand(
|
||||
{
|
||||
(item, true, ecx.with_def_site_ctxt(ty.span))
|
||||
} else {
|
||||
ecx.sess.dcx().emit_err(errors::AllocMustStatics { span: item.span() });
|
||||
ecx.dcx().emit_err(errors::AllocMustStatics { span: item.span() });
|
||||
return vec![orig_item];
|
||||
};
|
||||
|
||||
|
||||
@ -5,16 +5,14 @@
|
||||
#![feature(rustdoc_internals)]
|
||||
#![doc(rust_logo)]
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![feature(array_windows)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(is_sorted)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(lint_reasons)]
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(proc_macro_quote)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
|
||||
@ -194,7 +194,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
|
||||
|
||||
self.dcx
|
||||
.struct_span_err(attr.span, msg)
|
||||
.span_label(prev_attr.span, "previous attribute here")
|
||||
.with_span_label(prev_attr.span, "previous attribute here")
|
||||
.emit();
|
||||
|
||||
return;
|
||||
|
||||
@ -107,9 +107,9 @@ pub fn expand_include<'cx>(
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
// The file will be added to the code map by the parser
|
||||
let file = match resolve_path(&cx.sess.parse_sess, file.as_str(), sp) {
|
||||
let file = match resolve_path(&cx.sess, file.as_str(), sp) {
|
||||
Ok(f) => f,
|
||||
Err(mut err) => {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
@ -146,7 +146,7 @@ pub fn expand_include<'cx>(
|
||||
let mut ret = SmallVec::new();
|
||||
loop {
|
||||
match self.p.parse_item(ForceCollect::No) {
|
||||
Err(mut err) => {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
break;
|
||||
}
|
||||
@ -155,7 +155,7 @@ pub fn expand_include<'cx>(
|
||||
if self.p.token != token::Eof {
|
||||
let token = pprust::token_to_string(&self.p.token);
|
||||
let msg = format!("expected item, found `{token}`");
|
||||
self.p.struct_span_err(self.p.token.span, msg).emit();
|
||||
self.p.dcx().span_err(self.p.token.span, msg);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -179,9 +179,9 @@ pub fn expand_include_str(
|
||||
let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_str!") else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
let file = match resolve_path(&cx.sess.parse_sess, file.as_str(), sp) {
|
||||
let file = match resolve_path(&cx.sess, file.as_str(), sp) {
|
||||
Ok(f) => f,
|
||||
Err(mut err) => {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
@ -193,12 +193,12 @@ pub fn expand_include_str(
|
||||
base::MacEager::expr(cx.expr_str(sp, interned_src))
|
||||
}
|
||||
Err(_) => {
|
||||
cx.span_err(sp, format!("{} wasn't a utf-8 file", file.display()));
|
||||
cx.dcx().span_err(sp, format!("{} wasn't a utf-8 file", file.display()));
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e));
|
||||
cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
}
|
||||
@ -213,9 +213,9 @@ pub fn expand_include_bytes(
|
||||
let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_bytes!") else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
let file = match resolve_path(&cx.sess.parse_sess, file.as_str(), sp) {
|
||||
let file = match resolve_path(&cx.sess, file.as_str(), sp) {
|
||||
Ok(f) => f,
|
||||
Err(mut err) => {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
@ -226,7 +226,7 @@ pub fn expand_include_bytes(
|
||||
base::MacEager::expr(expr)
|
||||
}
|
||||
Err(e) => {
|
||||
cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e));
|
||||
cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,10 +5,11 @@ use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, attr, GenericParamKind};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder, Level};
|
||||
use rustc_expand::base::*;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span};
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::iter;
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
||||
@ -43,7 +44,7 @@ pub fn expand_test_case(
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
ecx.emit_err(errors::TestCaseNonItem { span: anno_item.span() });
|
||||
ecx.dcx().emit_err(errors::TestCaseNonItem { span: anno_item.span() });
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
@ -182,6 +183,16 @@ pub fn expand_test_or_bench(
|
||||
// creates $name: $expr
|
||||
let field = |name, expr| cx.field_imm(sp, Ident::from_str_and_span(name, sp), expr);
|
||||
|
||||
// Adds `#[coverage(off)]` to a closure, so it won't be instrumented in
|
||||
// `-Cinstrument-coverage` builds.
|
||||
// This requires `#[allow_internal_unstable(coverage_attribute)]` on the
|
||||
// corresponding macro declaration in `core::macros`.
|
||||
let coverage_off = |mut expr: P<ast::Expr>| {
|
||||
assert_matches!(expr.kind, ast::ExprKind::Closure(_));
|
||||
expr.attrs.push(cx.attr_nested_word(sym::coverage, sym::off, sp));
|
||||
expr
|
||||
};
|
||||
|
||||
let test_fn = if is_bench {
|
||||
// A simple ident for a lambda
|
||||
let b = Ident::from_str_and_span("b", attr_sp);
|
||||
@ -190,8 +201,9 @@ pub fn expand_test_or_bench(
|
||||
sp,
|
||||
cx.expr_path(test_path("StaticBenchFn")),
|
||||
thin_vec![
|
||||
// #[coverage(off)]
|
||||
// |b| self::test::assert_test_result(
|
||||
cx.lambda1(
|
||||
coverage_off(cx.lambda1(
|
||||
sp,
|
||||
cx.expr_call(
|
||||
sp,
|
||||
@ -206,7 +218,7 @@ pub fn expand_test_or_bench(
|
||||
],
|
||||
),
|
||||
b,
|
||||
), // )
|
||||
)), // )
|
||||
],
|
||||
)
|
||||
} else {
|
||||
@ -214,8 +226,9 @@ pub fn expand_test_or_bench(
|
||||
sp,
|
||||
cx.expr_path(test_path("StaticTestFn")),
|
||||
thin_vec![
|
||||
// #[coverage(off)]
|
||||
// || {
|
||||
cx.lambda0(
|
||||
coverage_off(cx.lambda0(
|
||||
sp,
|
||||
// test::assert_test_result(
|
||||
cx.expr_call(
|
||||
@ -230,7 +243,7 @@ pub fn expand_test_or_bench(
|
||||
), // )
|
||||
],
|
||||
), // }
|
||||
), // )
|
||||
)), // )
|
||||
],
|
||||
)
|
||||
};
|
||||
@ -389,17 +402,16 @@ pub fn expand_test_or_bench(
|
||||
}
|
||||
|
||||
fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) {
|
||||
let dcx = cx.sess.dcx();
|
||||
let dcx = cx.dcx();
|
||||
let msg = "the `#[test]` attribute may only be used on a non-associated function";
|
||||
let mut err = match item.map(|i| &i.kind) {
|
||||
let level = match item.map(|i| &i.kind) {
|
||||
// These were a warning before #92959 and need to continue being that to avoid breaking
|
||||
// stable user code (#94508).
|
||||
Some(ast::ItemKind::MacCall(_)) => dcx.struct_span_warn(attr_sp, msg),
|
||||
// `.forget_guarantee()` needed to get these two arms to match types. Because of how
|
||||
// locally close the `.emit()` call is I'm comfortable with it, but if it can be
|
||||
// reworked in the future to not need it, it'd be nice.
|
||||
_ => dcx.struct_span_err(attr_sp, msg).forget_guarantee(),
|
||||
Some(ast::ItemKind::MacCall(_)) => Level::Warning,
|
||||
_ => Level::Error,
|
||||
};
|
||||
let mut err = DiagnosticBuilder::<()>::new(dcx, level, msg);
|
||||
err.span(attr_sp);
|
||||
if let Some(item) = item {
|
||||
err.span_label(
|
||||
item.span,
|
||||
@ -410,8 +422,8 @@ fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>)
|
||||
),
|
||||
);
|
||||
}
|
||||
err.span_label(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions")
|
||||
.span_suggestion(attr_sp,
|
||||
err.with_span_label(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions")
|
||||
.with_span_suggestion(attr_sp,
|
||||
"replace with conditional compilation to make the item only exist when tests are being run",
|
||||
"#[cfg(test)]",
|
||||
Applicability::MaybeIncorrect)
|
||||
@ -466,8 +478,6 @@ fn should_ignore_message(i: &ast::Item) -> Option<Symbol> {
|
||||
fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
|
||||
match attr::find_by_name(&i.attrs, sym::should_panic) {
|
||||
Some(attr) => {
|
||||
let dcx = cx.sess.dcx();
|
||||
|
||||
match attr.meta_item_list() {
|
||||
// Handle #[should_panic(expected = "foo")]
|
||||
Some(list) => {
|
||||
@ -477,12 +487,13 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
|
||||
.and_then(|mi| mi.meta_item())
|
||||
.and_then(|mi| mi.value_str());
|
||||
if list.len() != 1 || msg.is_none() {
|
||||
dcx.struct_span_warn(
|
||||
cx.dcx()
|
||||
.struct_span_warn(
|
||||
attr.span,
|
||||
"argument must be of the form: \
|
||||
`expected = \"error message\"`",
|
||||
)
|
||||
.note(
|
||||
.with_note(
|
||||
"errors in this attribute were erroneously \
|
||||
allowed and will become a hard error in a \
|
||||
future release",
|
||||
@ -535,7 +546,7 @@ fn check_test_signature(
|
||||
f: &ast::Fn,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
|
||||
let dcx = cx.sess.dcx();
|
||||
let dcx = cx.dcx();
|
||||
|
||||
if let ast::Unsafe::Yes(span) = f.sig.header.unsafety {
|
||||
return Err(dcx.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" }));
|
||||
@ -601,7 +612,7 @@ fn check_bench_signature(
|
||||
// N.B., inadequate check, but we're running
|
||||
// well before resolve, can't get too deep.
|
||||
if f.sig.decl.inputs.len() != 1 {
|
||||
return Err(cx.sess.dcx().emit_err(errors::BenchSig { span: i.span }));
|
||||
return Err(cx.dcx().emit_err(errors::BenchSig { span: i.span }));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ pub fn expand_trace_macros(
|
||||
};
|
||||
err |= cursor.next().is_some();
|
||||
if err {
|
||||
cx.emit_err(errors::TraceMacros { span: sp });
|
||||
cx.dcx().emit_err(errors::TraceMacros { span: sp });
|
||||
} else {
|
||||
cx.set_trace_macros(value);
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ pub fn expand_type_ascribe(
|
||||
) -> Box<dyn base::MacResult + 'static> {
|
||||
let (expr, ty) = match parse_ascribe(cx, tts) {
|
||||
Ok(parsed) => parsed,
|
||||
Err(mut err) => {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
return DummyResult::any(span);
|
||||
}
|
||||
|
||||
@ -33,14 +33,14 @@ jobs:
|
||||
TARGET_TRIPLE: x86_64-pc-windows-gnu
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: CPU features
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user