New upstream version 1.77.2+dfsg1

This commit is contained in:
Fabian Grünbichler 2024-06-19 10:24:51 +02:00
parent 4b01247206
commit c0240ec034
8194 changed files with 257292 additions and 208830 deletions

313
Cargo.lock generated
View File

@ -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"

View File

@ -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
View File

@ -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

View File

@ -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>

View File

@ -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 }

File diff suppressed because it is too large Load Diff

View File

@ -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,

View File

@ -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.
///

View File

@ -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" }

View File

@ -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);

View File

@ -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)]

View File

@ -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);

View File

@ -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 {

View File

@ -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

View File

@ -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;
}

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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,16 +60,11 @@ 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",
)
.emit();
feature_err(&self.tcx.sess, sym::asm_unwind, sp, "the `may_unwind` option is unstable")
.emit();
}
let mut clobber_abis = FxIndexMap::default();
@ -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),

View 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);
}
}

View File

@ -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,
}

View File

@ -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,110 +586,71 @@ 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));
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 = 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,
};
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(
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];
(inputs, params, Some(task_context_hid))
}
hir::CoroutineDesugaring::Gen => (&[], &[], None),
};
let output =
return_ty.unwrap_or_else(|| 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: &[],
inputs,
output,
c_variadic: false,
implicit_self: hir::ImplicitSelfKind::None,
@ -724,94 +658,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
});
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));
// 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::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(
span,
hir::LangItem::FuturePoll,
arena_vec![self; new_unchecked, get_context],
);
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(
span,
hir::LangItem::IntoFutureIntoFuture,
arena_vec![self; expr],
);
let into_future_expr = match await_kind {
FutureKind::Future => self.expr_call_lang_item_fn(
span,
hir::LangItem::IntoFutureIntoFuture,
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 ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
let next_expr = self.expr_call_lang_item_fn(
head_span,
hir::LangItem::IteratorNext,
arena_vec![self; ref_mut_iter],
);
let next_expr = match loop_kind {
ForLoopKind::For => {
// `Iterator::next(&mut iter)`
let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
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 = {
self.expr_call_lang_item_fn(
head_span,
hir::LangItem::IntoIterIntoIter,
arena_vec![self; head],
)
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,
}

View File

@ -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 {

View File

@ -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,23 +585,25 @@ 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 => {
self.host_param_id = generics
.params
.iter()
.find(|param| {
matches!(
param.kind,
hir::GenericParamKind::Const { is_host_effect: true, .. }
)
})
.map(|param| param.def_id);
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, .. })
})
.map(|param| param.def_id);
}
match ctxt {
@ -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,207 +1082,224 @@ 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 mut parameters: Vec<hir::Param<'_>> = Vec::new();
let mut statements: Vec<hir::Stmt<'_>> = Vec::new();
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,
);
// Async function parameters are lowered into the closure body so that they are
// captured and so that the drop order matches the equivalent non-async functions.
// 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();
// Async function parameters are lowered into the closure body so that they are
// captured and so that the drop order matches the equivalent non-async functions.
//
// from:
//
// async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
// <body>
// }
//
// into:
//
// fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
// async move {
// let __arg2 = __arg2;
// let <pattern> = __arg2;
// let __arg1 = __arg1;
// let <pattern> = __arg1;
// let __arg0 = __arg0;
// let <pattern> = __arg0;
// drop-temps { <body> } // see comments later in fn for details
// }
// }
//
// If `<pattern>` is a simple ident, then it is lowered to a single
// `let <pattern> = <pattern>;` statement as an optimization.
//
// Note that the body is embedded in `drop-temps`; an
// equivalent desugaring would be `return { <body>
// };`. The key point is that we wish to drop all the
// let-bound variables and temporaries created in the body
// (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 = 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
// `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
let (ident, is_simple_parameter) = match parameter.pat.kind {
hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => {
(ident, true)
}
// For `ref mut` or wildcard arguments, we can't reuse the binding, but
// we can keep the same name for the parameter.
// This lets rustdoc render it correctly in documentation.
hir::PatKind::Binding(_, _, ident, _) => (ident, false),
hir::PatKind::Wild => {
(Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false)
}
_ => {
// Replace the ident for bindings that aren't simple.
let name = format!("__arg{index}");
let ident = Ident::from_str(&name);
(ident, false)
}
};
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.
//
// from:
//
// async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
// <body>
// }
//
// into:
//
// fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
// async move {
// let __arg2 = __arg2;
// let <pattern> = __arg2;
// let __arg1 = __arg1;
// let <pattern> = __arg1;
// let __arg0 = __arg0;
// let <pattern> = __arg0;
// drop-temps { <body> } // see comments later in fn for details
// }
// }
//
// If `<pattern>` is a simple ident, then it is lowered to a single
// `let <pattern> = <pattern>;` statement as an optimization.
//
// Note that the body is embedded in `drop-temps`; an
// equivalent desugaring would be `return { <body>
// };`. The key point is that we wish to drop all the
// let-bound variables and temporaries created in the body
// (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 span = parameter.pat.span;
// 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 = self.attrs.get(&parameter.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: self.lower_span(parameter.ty_span),
span: self.lower_span(parameter.span),
};
// Check if this is a binding pattern, if so, we can optimize and avoid adding a
// `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
let (ident, is_simple_parameter) = match parameter.pat.kind {
hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => {
(ident, true)
}
// For `ref mut` or wildcard arguments, we can't reuse the binding, but
// we can keep the same name for the parameter.
// This lets rustdoc render it correctly in documentation.
hir::PatKind::Binding(_, _, ident, _) => (ident, false),
hir::PatKind::Wild => {
(Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false)
}
_ => {
// Replace the ident for bindings that aren't simple.
let name = format!("__arg{index}");
let ident = Ident::from_str(&name);
(ident, false)
}
};
let desugared_span = this.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(&parameter.hir_id.local_id).copied();
let (new_parameter_pat, new_parameter_id) = this.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),
};
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(
stmt_attrs,
desugared_span,
Some(expr),
parameter.pat,
hir::LocalSource::AsyncFn,
);
statements.push(stmt);
} else {
// If this is not the simple case, then we construct two statements:
//
// ```
// let __argN = __argN;
// let <pat> = __argN;
// ```
//
// The first statement moves the parameter into the closure and thus ensures
// that the drop order is correct.
//
// The second statement creates the bindings that the user wrote.
// 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(
None,
desugared_span,
Some(move_expr),
move_pat,
hir::LocalSource::AsyncFn,
);
// 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(
stmt_attrs,
desugared_span,
Some(pattern_expr),
parameter.pat,
hir::LocalSource::AsyncFn,
);
statements.push(move_stmt);
statements.push(pattern_stmt);
};
parameters.push(new_parameter);
}
let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
// Create a block from the user's function body:
let user_body = this.lower_block_expr(body);
// Transform into `drop-temps { <user-body> }`, an expression:
let desugared_span =
this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None);
let user_body = this.expr_drop_temps(desugared_span, this.arena.alloc(user_body));
// As noted above, create the final block like
//
// ```
// {
// let $param_pattern = $raw_param;
// ...
// drop-temps { <user-body> }
// }
// ```
let body = this.block_all(
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 = self.expr_ident(desugared_span, ident, new_parameter_id);
let stmt = self.stmt_let_pat(
stmt_attrs,
desugared_span,
this.arena.alloc_from_iter(statements),
Some(user_body),
Some(expr),
parameter.pat,
hir::LocalSource::AsyncFn,
);
statements.push(stmt);
} else {
// If this is not the simple case, then we construct two statements:
//
// ```
// let __argN = __argN;
// let <pat> = __argN;
// ```
//
// The first statement moves the parameter into the closure and thus ensures
// that the drop order is correct.
//
// The second statement creates the bindings that the user wrote.
// 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) =
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),
move_pat,
hir::LocalSource::AsyncFn,
);
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(
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
closure_id,
None,
body.span,
hir::CoroutineSource::Fn,
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,
),
// Construct the `let <pat> = __argN;` statement. We re-use the original
// parameter's pattern so that `HirId`s are densely assigned.
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),
parameter.pat,
hir::LocalSource::AsyncFn,
);
statements.push(move_stmt);
statements.push(pattern_stmt);
};
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) };
parameters.push(new_parameter);
}
(this.arena.alloc_from_iter(parameters), expr)
})
let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
// Create a block from the user's function body:
let user_body = lower_body(this);
// Transform into `drop-temps { <user-body> }`, an expression:
let desugared_span =
this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None);
let user_body = this.expr_drop_temps(desugared_span, this.arena.alloc(user_body));
// As noted above, create the final block like
//
// ```
// {
// let $param_pattern = $raw_param;
// ...
// drop-temps { <user-body> }
// }
// ```
let body = this.block_all(
desugared_span,
this.arena.alloc_from_iter(statements),
Some(user_body),
);
this.expr_block(body)
};
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,
return_type_hint,
body_span,
desugaring_kind,
coroutine_source,
mkbody,
);
let expr = hir::Expr {
hir_id: self.lower_node_id(closure_id),
kind: coroutine_expr,
span: self.lower_span(body_span),
};
(self.arena.alloc_from_iter(parameters), expr)
}
fn lower_method_sig(
@ -1253,11 +1311,13 @@ 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| {
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
});
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() });
}
}
}

View File

@ -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(
ty,
modifier @ (TraitBoundModifier::None
| TraitBoundModifier::MaybeConst(_)
| TraitBoundModifier::Negative),
) => {
Some(this.lower_poly_trait_ref(ty, itctx, modifier.to_constness()))
}
// `~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,
// 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,
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,
))
}
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() {
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,
})
let itctx = match kind {
FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => {
ImplTraitContext::Universal
}
FnDeclKind::ExternFn => {
ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnParam)
}
FnDeclKind::Closure => {
ImplTraitContext::Disallowed(ImplTraitPosition::ClosureParam)
}
FnDeclKind::Pointer => {
ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam)
}
};
self.lower_ty_direct(&param.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),
let itctx = match kind {
FnDeclKind::Fn
| FnDeclKind::Inherent
| FnDeclKind::Trait
| 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)
}
} else {
ImplTraitContext::Disallowed(match kind {
FnDeclKind::Fn
| FnDeclKind::Inherent
| FnDeclKind::Trait
| FnDeclKind::Impl => {
unreachable!("fn should allow return-position impl trait in traits")
}
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, &param.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 &param.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 span = lcx.lower_span(span);
let body = hir::ExprKind::Lit(
lcx.arena.alloc(hir::Lit { node: LitKind::Bool(false), span }),
);
let id = lcx.next_node_id();
let hir_id = lcx.next_id();
(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(
span,
"no host param id for call in const yet no errors reported",
);
return;
};
let Some(host_param_id) = lcx.host_param_id else {
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,

View File

@ -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));
}
}

View File

@ -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(),

View File

@ -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

View File

@ -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,35 +925,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
only_trait: only_trait.then_some(()),
};
self.visibility_not_permitted(
&item.vis,
errors::VisibilityNotPermittedNote::IndividualImplItems,
);
if let &Unsafe::Yes(span) = unsafety {
self.dcx().emit_err(errors::InherentImplCannotUnsafe {
span: self_ty.span,
annotation_span: span,
annotation: "unsafe",
self_ty: self_ty.span,
});
}
if let &ImplPolarity::Negative(span) = polarity {
self.dcx().emit_err(error(span, "negative", false));
}
if let &Defaultness::Default(def_span) = defaultness {
self.dcx().emit_err(error(def_span, "`default`", true));
}
if let &Const::Yes(span) = constness {
self.dcx().emit_err(error(span, "`const`", true));
}
self.with_in_trait_impl(None, |this| {
this.visibility_not_permitted(
&item.vis,
errors::VisibilityNotPermittedNote::IndividualImplItems,
);
if let &Unsafe::Yes(span) = unsafety {
this.dcx().emit_err(errors::InherentImplCannotUnsafe {
span: self_ty.span,
annotation_span: span,
annotation: "unsafe",
self_ty: self_ty.span,
});
}
if let &ImplPolarity::Negative(span) = polarity {
this.dcx().emit_err(error(span, "negative", false));
}
if let &Defaultness::Default(def_span) = defaultness {
this.dcx().emit_err(error(def_span, "`default`", true));
}
if let &Const::Yes(span) = constness {
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,15 +1327,27 @@ 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()
{
for arg in &args.args {
if let ast::AngleBracketedArg::Constraint(constraint) = arg {
self.dcx()
.emit_err(errors::ConstraintOnNegativeBound { span: constraint.span });
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,
});
}
}
}
// 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 => {}
}
}
@ -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 &param.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),

View File

@ -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 {

View File

@ -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",
)
.emit();
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,
});
}
}
}

View File

@ -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)]

View File

@ -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);
}

View File

@ -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;

View File

@ -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),

View File

@ -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,26 +160,25 @@ 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:
//
// if (return Struct {}) {}
//
// then there is no need for parenthesizing the individual struct
// expressions within. On the other hand if the whole cond is not
// parenthesized, then print_expr must parenthesize exterior struct
// literals.
//
// if x == (Struct {}) {}
//
fixup = FixupContext::default();
}
// If we are surrounding the whole cond in parentheses, such as:
//
// if (return Struct {}) {}
//
// then there is no need for parenthesizing the individual struct
// expressions within. On the other hand if the whole cond is not
// parenthesized, then print_expr must parenthesize exterior struct
// literals.
//
// if x == (Struct {}) {}
//
let fixup = FixupContext {
parenthesize_exterior_struct_lit: fixup.parenthesize_exterior_struct_lit && !needs_par,
};
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(",");
}
}

View File

@ -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,

View File

@ -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 {
span: mi.span,
is_nightly: sess.is_nightly_build().then_some(()),
details: (),
});
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 {
span: meta_item.span,
});
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")
}

View File

@ -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,

View File

@ -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 {}",

View File

@ -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,16 +407,16 @@ 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
.iter()

View File

@ -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[..])
{
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 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(
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
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",
)
.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 {
CoroutineSource::Block => "async block",
CoroutineSource::Closure => "async closure",
CoroutineSource::Fn => {
bug!("async block/closure expected, but async function found.")
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",

View File

@ -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 {

View File

@ -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 }
}
})
}
}

View File

@ -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(
span,
&format!("`{}` in pattern guard", self.local_names[local].unwrap()),
);
err.note(
"variables bound in patterns cannot be moved from \
until after the end of the pattern guard",
);
return err;
return self
.cannot_move_out_of(
span,
&format!("`{}` in pattern guard", self.local_names[local].unwrap()),
)
.with_note(
"variables bound in patterns cannot be moved from \
until after the end of the pattern guard",
);
} 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.infcx.tcx.def_span(def_id),
format!("captured by this `{closure_kind}` closure"),
);
diag
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"),
)
}
_ => {
let source = self.borrowed_content_source(deref_base);

View File

@ -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(

View File

@ -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");

View File

@ -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,11 +327,10 @@ 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 {
kind: type_test.generic_kind.to_string(),
span: type_test_span,
});
let mut diag = self.dcx().create_err(GenericDoesNotLiveLongEnough {
kind: type_test.generic_kind.to_string(),
span: type_test_span,
});
// Add notes and suggestions for the case of 'static lifetime
// implied but not specified when a generic associated types
@ -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());
}
}

View File

@ -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,55 +683,86 @@ 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 parent_item =
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
let output = &parent_item
.fn_decl()
.expect("coroutine lowered from async fn should be in fn")
.output;
span = output.span();
if let hir::FnRetTy::Return(ret) = output {
hir_ty = Some(self.get_future_inner_return_ty(*ret));
}
" 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 => {
let parent_item =
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
let output = &parent_item
.fn_decl()
.expect("coroutine lowered from gen fn should be in fn")
.output;
span = output.span();
" of gen function"
}
},
let mir_description = match kind {
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::Async,
hir::CoroutineSource::Block,
)) => " of async block",
Some(hir::CoroutineKind::AsyncGen(src)) => match src {
hir::CoroutineSource::Block => " of async gen block",
hir::CoroutineSource::Closure => " of async gen closure",
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
.fn_decl()
.expect("coroutine lowered from async gen fn should be in fn")
.output;
span = output.span();
" of async gen function"
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
.fn_decl()
.expect("coroutine lowered from async fn should be in fn")
.output;
span = output.span();
if let hir::FnRetTy::Return(ret) = output {
hir_ty = Some(self.get_future_inner_return_ty(*ret));
}
},
Some(hir::CoroutineKind::Coroutine) => " of coroutine",
None => " of closure",
" of async function"
}
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
.fn_decl()
.expect("coroutine lowered from gen fn should be in fn")
.output;
span = output.span();
" of gen function"
}
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
.fn_decl()
.expect("coroutine lowered from async gen fn should be in fn")
.output;
span = output.span();
" of async gen function"
}
hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => {
" of coroutine"
}
hir::ClosureKind::Closure => " of closure",
};
(span, mir_description, hir_ty)
}

View File

@ -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)
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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))
}
/// 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()
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 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(

View File

@ -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,

View File

@ -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);
}

View File

@ -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,

View File

@ -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.

View File

@ -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,

View File

@ -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);

View File

@ -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>,

View File

@ -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,
&region_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,17 +600,19 @@ 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) {
self.cx
.borrowck_context
.constraints
.liveness_constraints
.add_location(region, location);
}
// 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
//
// 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
.liveness_constraints
.add_location(region, location);
}
}
@ -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,10 +1108,17 @@ 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);
self.ascribe_user_type(inferred_ty, annotation, span);
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);
}
}
}
@ -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!(

View File

@ -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)

View File

@ -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];
};

View File

@ -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,12 +625,13 @@ 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(
template_span
.from_inner(InnerSpan::new(span.start, span.end)),
msg,
)
.emit();
ecx.dcx()
.struct_span_err(
template_span
.from_inner(InnerSpan::new(span.start, span.end)),
msg,
)
.emit();
None
}
}
@ -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!(
"if this argument is intentionally unused, \
consider using it in an asm comment: `\"/*{help_str} */\"`"
));
err.emit();
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} */\"`"
))
.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)
}

View File

@ -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) {

View File

@ -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(_)

View File

@ -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)

View File

@ -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),

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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)
}

View File

@ -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);

View File

@ -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));

View File

@ -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);
}
}

View File

@ -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 });
}
}
}

View File

@ -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})`",),
);

View File

@ -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)
}

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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)]`")
}
};

View File

@ -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)
}

View File

@ -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);

View File

@ -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)"),
}
}

View File

@ -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`"),
}
}

View File

@ -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`"),
}
}
}

View File

@ -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)

View File

@ -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(),

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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];
};

View File

@ -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;

View File

@ -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;

View File

@ -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)
}
}

View File

@ -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,17 +487,18 @@ 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(
attr.span,
"argument must be of the form: \
cx.dcx()
.struct_span_warn(
attr.span,
"argument must be of the form: \
`expected = \"error message\"`",
)
.note(
"errors in this attribute were erroneously \
)
.with_note(
"errors in this attribute were erroneously \
allowed and will become a hard error in a \
future release",
)
.emit();
)
.emit();
ShouldPanic::Yes(None)
} else {
ShouldPanic::Yes(msg)
@ -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(())
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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