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", "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]] [[package]]
name = "ansi_term" name = "ansi_term"
version = "0.12.1" version = "0.12.1"
@ -202,9 +212,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]] [[package]]
name = "askama" name = "askama"
version = "0.12.0" version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47cbc3cf73fa8d9833727bbee4835ba5c421a0d65b72daf9a7b5d0e0f9cfb57e" checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28"
dependencies = [ dependencies = [
"askama_derive", "askama_derive",
"askama_escape", "askama_escape",
@ -212,14 +222,14 @@ dependencies = [
[[package]] [[package]]
name = "askama_derive" name = "askama_derive"
version = "0.12.1" version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c22fbe0413545c098358e56966ff22cdd039e10215ae213cfbd65032b119fc94" checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83"
dependencies = [ dependencies = [
"askama_parser",
"basic-toml", "basic-toml",
"mime", "mime",
"mime_guess", "mime_guess",
"nom",
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde", "serde",
@ -232,6 +242,15 @@ version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" 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]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -285,9 +304,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.4.0" version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
@ -363,9 +382,9 @@ dependencies = [
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.4.3" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "bytes" name = "bytes"
@ -537,7 +556,7 @@ checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
[[package]] [[package]]
name = "clippy" name = "clippy"
version = "0.1.76" version = "0.1.77"
dependencies = [ dependencies = [
"anstream", "anstream",
"clippy_config", "clippy_config",
@ -565,7 +584,7 @@ dependencies = [
[[package]] [[package]]
name = "clippy_config" name = "clippy_config"
version = "0.1.76" version = "0.1.77"
dependencies = [ dependencies = [
"rustc-semver", "rustc-semver",
"serde", "serde",
@ -577,21 +596,21 @@ dependencies = [
name = "clippy_dev" name = "clippy_dev"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"aho-corasick 0.7.20", "aho-corasick 1.0.2",
"clap", "clap",
"indoc", "indoc",
"itertools", "itertools",
"opener 0.5.2", "opener",
"shell-escape", "shell-escape",
"walkdir", "walkdir",
] ]
[[package]] [[package]]
name = "clippy_lints" name = "clippy_lints"
version = "0.1.76" version = "0.1.77"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"cargo_metadata 0.15.4", "cargo_metadata 0.18.0",
"clippy_config", "clippy_config",
"clippy_utils", "clippy_utils",
"declare_clippy_lint", "declare_clippy_lint",
@ -613,7 +632,7 @@ dependencies = [
[[package]] [[package]]
name = "clippy_utils" name = "clippy_utils"
version = "0.1.76" version = "0.1.77"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"clippy_config", "clippy_config",
@ -704,9 +723,9 @@ checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335"
[[package]] [[package]]
name = "compiler_builtins" name = "compiler_builtins"
version = "0.1.103" version = "0.1.105"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3b73c3443a5fd2438d7ba4853c64e4c8efc2404a9e28a9234cc2d5eebc6c242" checksum = "3686cc48897ce1950aa70fd595bd2dc9f767a3c4cca4cd17b2cb52a2d37e6eb4"
dependencies = [ dependencies = [
"cc", "cc",
"rustc-std-workspace-core", "rustc-std-workspace-core",
@ -868,12 +887,12 @@ dependencies = [
[[package]] [[package]]
name = "ctrlc" name = "ctrlc"
version = "3.4.0" version = "3.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e" checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b"
dependencies = [ dependencies = [
"nix", "nix",
"windows-sys 0.48.0", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -984,7 +1003,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
[[package]] [[package]]
name = "declare_clippy_lint" name = "declare_clippy_lint"
version = "0.1.76" version = "0.1.77"
dependencies = [ dependencies = [
"itertools", "itertools",
"quote", "quote",
@ -1249,7 +1268,6 @@ name = "error_index_generator"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"mdbook", "mdbook",
"rustc_error_codes",
] ]
[[package]] [[package]]
@ -2072,9 +2090,9 @@ dependencies = [
[[package]] [[package]]
name = "jobserver" name = "jobserver"
version = "0.1.27" version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@ -2177,16 +2195,6 @@ dependencies = [
"cc", "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]] [[package]]
name = "libloading" name = "libloading"
version = "0.8.1" version = "0.8.1"
@ -2342,7 +2350,7 @@ dependencies = [
"log", "log",
"memchr", "memchr",
"once_cell", "once_cell",
"opener 0.6.1", "opener",
"pathdiff", "pathdiff",
"pulldown-cmark", "pulldown-cmark",
"regex", "regex",
@ -2356,9 +2364,9 @@ dependencies = [
[[package]] [[package]]
name = "measureme" name = "measureme"
version = "10.1.2" version = "11.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45e381dcdad44c3c435f8052b08c5c4a1449c48ab56f312345eae12d7a693dbe" checksum = "dfa4a40f09af7aa6faef38285402a78847d0d72bf8827006cd2a332e1e6e4a8d"
dependencies = [ dependencies = [
"log", "log",
"memmap2", "memmap2",
@ -2465,16 +2473,16 @@ dependencies = [
"ctrlc", "ctrlc",
"env_logger", "env_logger",
"getrandom", "getrandom",
"jemalloc-sys",
"lazy_static", "lazy_static",
"libc", "libc",
"libffi", "libffi",
"libloading 0.8.1", "libloading",
"log", "log",
"measureme", "measureme",
"rand", "rand",
"regex", "regex",
"rustc_version", "rustc_version",
"serde",
"smallvec", "smallvec",
"ui_test", "ui_test",
] ]
@ -2512,14 +2520,13 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.26.2" version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"cfg-if", "cfg-if",
"libc", "libc",
"static_assertions",
] ]
[[package]] [[package]]
@ -2588,9 +2595,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]] [[package]]
name = "object" name = "object"
version = "0.32.1" version = "0.32.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"crc32fast", "crc32fast",
@ -2618,16 +2625,6 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 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]] [[package]]
name = "opener" name = "opener"
version = "0.6.1" version = "0.6.1"
@ -2641,11 +2638,11 @@ dependencies = [
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.55" version = "0.10.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"cfg-if", "cfg-if",
"foreign-types", "foreign-types",
"libc", "libc",
@ -2673,9 +2670,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.90" version = "0.9.99"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -3006,11 +3003,11 @@ dependencies = [
[[package]] [[package]]
name = "pulldown-cmark" name = "pulldown-cmark"
version = "0.9.3" version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"memchr", "memchr",
"unicase", "unicase",
] ]
@ -3280,9 +3277,9 @@ dependencies = [
[[package]] [[package]]
name = "rustc-build-sysroot" name = "rustc-build-sysroot"
version = "0.4.2" version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ed2a90dfa5232ed5ff21d53d4df655f315ab316ea06fc508f1c74bcedb1ce6c" checksum = "39dcf8d82b1f79a179bdb284dc44db440a9666eefa5a6df5ef282d6db930d544"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"rustc_version", "rustc_version",
@ -3370,7 +3367,7 @@ dependencies = [
name = "rustc_abi" name = "rustc_abi"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"rand", "rand",
"rand_xoshiro", "rand_xoshiro",
"rustc_data_structures", "rustc_data_structures",
@ -3401,7 +3398,7 @@ dependencies = [
name = "rustc_ast" name = "rustc_ast"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"memchr", "memchr",
"rustc_data_structures", "rustc_data_structures",
"rustc_index", "rustc_index",
@ -3552,7 +3549,7 @@ dependencies = [
name = "rustc_codegen_llvm" name = "rustc_codegen_llvm"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"itertools", "itertools",
"libc", "libc",
"measureme", "measureme",
@ -3587,7 +3584,7 @@ name = "rustc_codegen_ssa"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"ar_archive_writer", "ar_archive_writer",
"bitflags 1.3.2", "bitflags 2.4.1",
"cc", "cc",
"itertools", "itertools",
"jobserver", "jobserver",
@ -3654,11 +3651,11 @@ name = "rustc_data_structures"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"bitflags 1.3.2", "bitflags 2.4.1",
"either",
"elsa", "elsa",
"ena", "ena",
"indexmap", "indexmap",
"itertools",
"jobserver", "jobserver",
"libc", "libc",
"measureme", "measureme",
@ -3703,7 +3700,6 @@ dependencies = [
"rustc_codegen_ssa", "rustc_codegen_ssa",
"rustc_const_eval", "rustc_const_eval",
"rustc_data_structures", "rustc_data_structures",
"rustc_error_codes",
"rustc_errors", "rustc_errors",
"rustc_expand", "rustc_expand",
"rustc_feature", "rustc_feature",
@ -3738,6 +3734,7 @@ dependencies = [
"rustc_trait_selection", "rustc_trait_selection",
"rustc_ty_utils", "rustc_ty_utils",
"serde_json", "serde_json",
"shlex",
"time", "time",
"tracing", "tracing",
"windows", "windows",
@ -3770,14 +3767,16 @@ dependencies = [
name = "rustc_errors" name = "rustc_errors"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"annotate-snippets", "annotate-snippets 0.10.1",
"derive_setters", "derive_setters",
"rustc_ast", "rustc_ast",
"rustc_ast_pretty", "rustc_ast_pretty",
"rustc_data_structures", "rustc_data_structures",
"rustc_error_codes",
"rustc_error_messages", "rustc_error_messages",
"rustc_fluent_macro", "rustc_fluent_macro",
"rustc_hir", "rustc_hir",
"rustc_index",
"rustc_lint_defs", "rustc_lint_defs",
"rustc_macros", "rustc_macros",
"rustc_serialize", "rustc_serialize",
@ -3797,7 +3796,6 @@ dependencies = [
name = "rustc_expand" name = "rustc_expand"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"crossbeam-channel",
"rustc_ast", "rustc_ast",
"rustc_ast_passes", "rustc_ast_passes",
"rustc_ast_pretty", "rustc_ast_pretty",
@ -3831,7 +3829,7 @@ dependencies = [
name = "rustc_fluent_macro" name = "rustc_fluent_macro"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"annotate-snippets", "annotate-snippets 0.10.1",
"fluent-bundle", "fluent-bundle",
"fluent-syntax", "fluent-syntax",
"proc-macro2", "proc-macro2",
@ -3869,6 +3867,7 @@ dependencies = [
name = "rustc_hir_analysis" name = "rustc_hir_analysis"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"itertools",
"rustc_arena", "rustc_arena",
"rustc_ast", "rustc_ast",
"rustc_attr", "rustc_attr",
@ -3877,6 +3876,7 @@ dependencies = [
"rustc_feature", "rustc_feature",
"rustc_fluent_macro", "rustc_fluent_macro",
"rustc_hir", "rustc_hir",
"rustc_hir_pretty",
"rustc_index", "rustc_index",
"rustc_infer", "rustc_infer",
"rustc_lint_defs", "rustc_lint_defs",
@ -3906,6 +3906,7 @@ dependencies = [
name = "rustc_hir_typeck" name = "rustc_hir_typeck"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"itertools",
"rustc_ast", "rustc_ast",
"rustc_attr", "rustc_attr",
"rustc_data_structures", "rustc_data_structures",
@ -3992,7 +3993,7 @@ dependencies = [
name = "rustc_interface" name = "rustc_interface"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"libloading 0.7.4", "libloading",
"rustc-rayon", "rustc-rayon",
"rustc-rayon-core", "rustc-rayon-core",
"rustc_ast", "rustc_ast",
@ -4121,8 +4122,8 @@ dependencies = [
name = "rustc_metadata" name = "rustc_metadata"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"libloading 0.7.4", "libloading",
"odht", "odht",
"rustc_ast", "rustc_ast",
"rustc_attr", "rustc_attr",
@ -4151,7 +4152,7 @@ dependencies = [
name = "rustc_middle" name = "rustc_middle"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"derive_more", "derive_more",
"either", "either",
"field-offset", "field-offset",
@ -4189,6 +4190,7 @@ name = "rustc_mir_build"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"either", "either",
"itertools",
"rustc_apfloat", "rustc_apfloat",
"rustc_arena", "rustc_arena",
"rustc_ast", "rustc_ast",
@ -4286,7 +4288,7 @@ dependencies = [
name = "rustc_parse" name = "rustc_parse"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"rustc_ast", "rustc_ast",
"rustc_ast_pretty", "rustc_ast_pretty",
"rustc_data_structures", "rustc_data_structures",
@ -4340,6 +4342,7 @@ dependencies = [
name = "rustc_pattern_analysis" name = "rustc_pattern_analysis"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"rustc-hash",
"rustc_apfloat", "rustc_apfloat",
"rustc_arena", "rustc_arena",
"rustc_data_structures", "rustc_data_structures",
@ -4354,7 +4357,6 @@ dependencies = [
"rustc_target", "rustc_target",
"smallvec", "smallvec",
"tracing", "tracing",
"typed-arena",
] ]
[[package]] [[package]]
@ -4423,7 +4425,7 @@ dependencies = [
name = "rustc_resolve" name = "rustc_resolve"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"pulldown-cmark", "pulldown-cmark",
"rustc_arena", "rustc_arena",
"rustc_ast", "rustc_ast",
@ -4462,7 +4464,7 @@ dependencies = [
name = "rustc_session" name = "rustc_session"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"getopts", "getopts",
"libc", "libc",
"rustc_ast", "rustc_ast",
@ -4520,7 +4522,7 @@ dependencies = [
name = "rustc_symbol_mangling" name = "rustc_symbol_mangling"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"punycode", "punycode",
"rustc-demangle", "rustc-demangle",
"rustc_data_structures", "rustc_data_structures",
@ -4538,7 +4540,7 @@ dependencies = [
name = "rustc_target" name = "rustc_target"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"object", "object",
"rustc_abi", "rustc_abi",
"rustc_data_structures", "rustc_data_structures",
@ -4562,6 +4564,8 @@ checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f"
name = "rustc_trait_selection" name = "rustc_trait_selection"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 2.4.1",
"itertools",
"rustc_ast", "rustc_ast",
"rustc_attr", "rustc_attr",
"rustc_data_structures", "rustc_data_structures",
@ -4636,12 +4640,13 @@ dependencies = [
name = "rustc_type_ir" name = "rustc_type_ir"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"derivative", "derivative",
"rustc_data_structures", "rustc_data_structures",
"rustc_index", "rustc_index",
"rustc_macros", "rustc_macros",
"rustc_serialize", "rustc_serialize",
"rustc_span",
"smallvec", "smallvec",
] ]
@ -4734,7 +4739,7 @@ dependencies = [
name = "rustfmt-nightly" name = "rustfmt-nightly"
version = "1.7.0" version = "1.7.0"
dependencies = [ dependencies = [
"annotate-snippets", "annotate-snippets 0.9.1",
"anyhow", "anyhow",
"bytecount", "bytecount",
"cargo_metadata 0.15.4", "cargo_metadata 0.15.4",
@ -4766,7 +4771,7 @@ version = "0.38.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed" checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed"
dependencies = [ dependencies = [
"bitflags 2.4.0", "bitflags 2.4.1",
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
@ -4781,12 +4786,12 @@ checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
[[package]] [[package]]
name = "ruzstd" name = "ruzstd"
version = "0.4.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3ffab8f9715a0d455df4bbb9d21e91135aab3cd3ca187af0cd0c3c3f868fdc" checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"thiserror-core", "derive_more",
"twox-hash", "twox-hash",
] ]
@ -5204,9 +5209,9 @@ dependencies = [
[[package]] [[package]]
name = "sysinfo" name = "sysinfo"
version = "0.29.2" version = "0.29.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9557d0845b86eea8182f7b10dff120214fb6cd9fd937b6f4917714e546a38695" checksum = "cd727fc423c2060f6c92d9534cef765c65a6ed3f428a03d7def74a8c4348e666"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"core-foundation-sys", "core-foundation-sys",
@ -5336,9 +5341,9 @@ dependencies = [
[[package]] [[package]]
name = "thin-vec" name = "thin-vec"
version = "0.2.12" version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aac81b6fd6beb5884b0cf3321b8117e6e5d47ecb6fc89f414cfdcca8b2fe2dd8" checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
@ -5349,26 +5354,6 @@ dependencies = [
"thiserror-impl", "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]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.47" version = "1.0.47"
@ -5690,12 +5675,6 @@ dependencies = [
"rustc-hash", "rustc-hash",
] ]
[[package]]
name = "typed-arena"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.16.0" version = "1.16.0"
@ -5724,7 +5703,7 @@ version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aaf4bf7c184b8dfc7a4d3b90df789b1eb992ee42811cd115f32a7a1eb781058d" checksum = "aaf4bf7c184b8dfc7a4d3b90df789b1eb992ee42811cd115f32a7a1eb781058d"
dependencies = [ dependencies = [
"annotate-snippets", "annotate-snippets 0.9.1",
"anyhow", "anyhow",
"bstr", "bstr",
"cargo-platform", "cargo-platform",
@ -5747,9 +5726,9 @@ dependencies = [
[[package]] [[package]]
name = "unic-langid" name = "unic-langid"
version = "0.9.1" version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "398f9ad7239db44fd0f80fe068d12ff22d78354080332a5077dc6f52f14dcf2f" checksum = "238722e6d794ed130f91f4ea33e01fcff4f188d92337a21297892521c72df516"
dependencies = [ dependencies = [
"unic-langid-impl", "unic-langid-impl",
"unic-langid-macros", "unic-langid-macros",
@ -5757,18 +5736,18 @@ dependencies = [
[[package]] [[package]]
name = "unic-langid-impl" name = "unic-langid-impl"
version = "0.9.1" version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e35bfd2f2b8796545b55d7d3fd3e89a0613f68a0d1c8bc28cb7ff96b411a35ff" checksum = "4bd55a2063fdea4ef1f8633243a7b0524cbeef1905ae04c31a1c9b9775c55bc6"
dependencies = [ dependencies = [
"tinystr", "tinystr",
] ]
[[package]] [[package]]
name = "unic-langid-macros" name = "unic-langid-macros"
version = "0.9.1" version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "055e618bf694161ffff0466d95cef3e1a5edc59f6ba1888e97801f2b4ebdc4fe" checksum = "5c854cefb82ff2816410ce606acbad1b3af065140907b29be9229040752b83ec"
dependencies = [ dependencies = [
"proc-macro-hack", "proc-macro-hack",
"tinystr", "tinystr",
@ -5778,13 +5757,13 @@ dependencies = [
[[package]] [[package]]
name = "unic-langid-macros-impl" name = "unic-langid-macros-impl"
version = "0.9.1" version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f5cdec05b907f4e2f6843f4354f4ce6a5bebe1a56df320a49134944477ce4d8" checksum = "fea2a4c80deb4fb3ca51f66b5e2dd91e3642bbce52234bcf22e41668281208e4"
dependencies = [ dependencies = [
"proc-macro-hack", "proc-macro-hack",
"quote", "quote",
"syn 1.0.109", "syn 2.0.32",
"unic-langid-impl", "unic-langid-impl",
] ]
@ -5855,9 +5834,9 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.10" version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"rustc-std-workspace-core", "rustc-std-workspace-core",
@ -6141,6 +6120,15 @@ dependencies = [
"windows-targets 0.48.1", "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]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.42.2" version = "0.42.2"
@ -6171,6 +6159,21 @@ dependencies = [
"windows_x86_64_msvc 0.48.0", "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]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.42.2" version = "0.42.2"
@ -6183,6 +6186,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.42.2" version = "0.42.2"
@ -6195,6 +6204,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.42.2" version = "0.42.2"
@ -6207,6 +6222,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.42.2" version = "0.42.2"
@ -6219,6 +6240,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.42.2" version = "0.42.2"
@ -6231,6 +6258,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" 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]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.42.2" version = "0.42.2"
@ -6243,6 +6276,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" 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]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.42.2" version = "0.42.2"
@ -6255,6 +6294,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" 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]] [[package]]
name = "winnow" name = "winnow"
version = "0.4.7" version = "0.4.7"

View File

@ -64,7 +64,7 @@ exclude = [
] ]
[profile.release.package.compiler_builtins] [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 # verify that this is the case. This requires, however, that the crate is built
# without overflow checks and debug assertions. Forcefully disable debug # without overflow checks and debug assertions. Forcefully disable debug
# assertions and overflow checks here which should ensure that even if these # assertions and overflow checks here which should ensure that even if these
@ -104,6 +104,14 @@ gimli.debug = 0
miniz_oxide.debug = 0 miniz_oxide.debug = 0
object.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] [patch.crates-io]
# See comments in `library/rustc-std-workspace-core/README.md` for what's going on # See comments in `library/rustc-std-workspace-core/README.md` for what's going on
# here # 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) - [Quick Start](#quick-start)
- [Installing from Source](#installing-from-source) - [Installing from Source](#installing-from-source)
- [Building Documentation](#building-documentation)
- [Notes](#notes)
- [Getting Help](#getting-help) - [Getting Help](#getting-help)
- [Contributing](#contributing) - [Contributing](#contributing)
- [License](#license) - [License](#license)
@ -34,253 +32,8 @@ Read ["Installation"] from [The Book].
## Installing from Source ## Installing from Source
The Rust build system uses a Python script called `x.py` to build the compiler, If you really want to install from source (though this is not recommended), see
which manages the bootstrapping process. It lives at the root of the project. [INSTALL.md](INSTALL.md).
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.
## Getting Help ## 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) 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/) - [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/) - [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> <a id="1.76.0-Compiler"></a>

View File

@ -5,7 +5,7 @@ edition = "2021"
[dependencies] [dependencies]
# tidy-alphabetical-start # tidy-alphabetical-start
bitflags = "1.2.1" bitflags = "2.4.1"
rand = { version = "0.8.4", default-features = false, optional = true } rand = { version = "0.8.4", default-features = false, optional = true }
rand_xoshiro = { version = "0.6.0", optional = true } rand_xoshiro = { version = "0.6.0", optional = true }
rustc_data_structures = { path = "../rustc_data_structures", 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")] #[cfg(feature = "nightly")]
use rustc_macros::HashStable_Generic; use rustc_macros::HashStable_Generic;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use rustc_macros::{Decodable, Encodable}; use rustc_macros::{Decodable_Generic, Encodable_Generic};
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use std::iter::Step; use std::iter::Step;
@ -29,10 +29,12 @@ pub use layout::LayoutCalculator;
/// instead of implementing everything in `rustc_middle`. /// instead of implementing everything in `rustc_middle`.
pub trait HashStableContext {} 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! { bitflags! {
#[derive(Default)] impl ReprFlags: u8 {
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
pub struct ReprFlags: u8 {
const IS_C = 1 << 0; const IS_C = 1 << 0;
const IS_SIMD = 1 << 1; const IS_SIMD = 1 << 1;
const IS_TRANSPARENT = 1 << 2; const IS_TRANSPARENT = 1 << 2;
@ -42,14 +44,22 @@ bitflags! {
// the seed stored in `ReprOptions.layout_seed` // the seed stored in `ReprOptions.layout_seed`
const RANDOMIZE_LAYOUT = 1 << 4; const RANDOMIZE_LAYOUT = 1 << 4;
// Any of these flags being set prevent field reordering optimisation. // Any of these flags being set prevent field reordering optimisation.
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits()
| ReprFlags::IS_SIMD.bits | ReprFlags::IS_SIMD.bits()
| ReprFlags::IS_LINEAR.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)] #[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 { pub enum IntegerType {
/// Pointer-sized integer type, i.e. `isize` and `usize`. The field shows signedness, e.g. /// Pointer-sized integer type, i.e. `isize` and `usize`. The field shows signedness, e.g.
/// `Pointer(true)` means `isize`. /// `Pointer(true)` means `isize`.
@ -70,7 +80,7 @@ impl IntegerType {
/// Represents the repr options provided by the user. /// Represents the repr options provided by the user.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] #[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 struct ReprOptions {
pub int: Option<IntegerType>, pub int: Option<IntegerType>,
pub align: Option<Align>, pub align: Option<Align>,
@ -409,7 +419,7 @@ impl FromStr for Endian {
/// Size of a type in bytes. /// Size of a type in bytes.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[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 { pub struct Size {
raw: u64, raw: u64,
} }
@ -633,7 +643,7 @@ impl Step for Size {
/// Alignment of a type in bytes (always a power of two). /// Alignment of a type in bytes (always a power of two).
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[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 { pub struct Align {
pow2: u8, pow2: u8,
} }
@ -774,7 +784,7 @@ impl AbiAndPrefAlign {
/// Integers, also used for enum discriminants. /// Integers, also used for enum discriminants.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[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 { pub enum Integer {
I8, I8,
I16, 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 /// Allocates a string slice that is copied into the `DroplessArena`, returning a
/// reference to it. Will panic if passed an empty string. /// reference to it. Will panic if passed an empty string.
/// ///

View File

@ -5,7 +5,7 @@ edition = "2021"
[dependencies] [dependencies]
# tidy-alphabetical-start # tidy-alphabetical-start
bitflags = "1.2.1" bitflags = "2.4.1"
memchr = "2.5.0" memchr = "2.5.0"
rustc_data_structures = { path = "../rustc_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" }
rustc_index = { path = "../rustc_index" } rustc_index = { path = "../rustc_index" }

View File

@ -20,17 +20,18 @@
pub use crate::format::*; pub use crate::format::*;
pub use crate::util::parser::ExprPrecedence; pub use crate::util::parser::ExprPrecedence;
pub use rustc_span::AttrId;
pub use GenericArgs::*; pub use GenericArgs::*;
pub use UnsafeSource::*; pub use UnsafeSource::*;
use crate::ptr::P; use crate::ptr::P;
use crate::token::{self, CommentKind, Delimiter}; use crate::token::{self, CommentKind, Delimiter};
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream}; use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
use rustc_data_structures::packed::Pu128;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_macros::HashStable_Generic; use rustc_macros::HashStable_Generic;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_span::source_map::{respan, Spanned}; use rustc_span::source_map::{respan, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; 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}; pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
/// A modifier on a bound, e.g., `?Trait` or `~const Trait`. /// Modifiers on a trait bound like `~const`, `?` and `!`.
///
/// Negative bounds should also be handled here.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
pub enum TraitBoundModifier { pub struct TraitBoundModifiers {
/// No modifiers pub constness: BoundConstness,
None, pub polarity: BoundPolarity,
/// `!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,
} }
impl TraitBoundModifier { impl TraitBoundModifiers {
pub fn to_constness(self) -> Const { pub const NONE: Self =
match self { Self { constness: BoundConstness::Never, polarity: BoundPolarity::Positive };
Self::MaybeConst(span) => Const::Yes(span),
_ => Const::No,
}
}
} }
/// The AST represents all type param bounds as types. /// The AST represents all type param bounds as types.
@ -329,7 +305,7 @@ impl TraitBoundModifier {
/// detects `Copy`, `Send` and `Sync`. /// detects `Copy`, `Send` and `Sync`.
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub enum GenericBound { pub enum GenericBound {
Trait(PolyTraitRef, TraitBoundModifier), Trait(PolyTraitRef, TraitBoundModifiers),
Outlives(Lifetime), Outlives(Lifetime),
} }
@ -650,7 +626,8 @@ impl Pat {
| PatKind::Range(..) | PatKind::Range(..)
| PatKind::Ident(..) | PatKind::Ident(..)
| PatKind::Path(..) | PatKind::Path(..)
| PatKind::MacCall(_) => {} | PatKind::MacCall(_)
| PatKind::Err(_) => {}
} }
} }
@ -779,8 +756,7 @@ pub enum PatKind {
Ident(BindingAnnotation, Ident, Option<P<Pat>>), Ident(BindingAnnotation, Ident, Option<P<Pat>>),
/// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). /// 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>, PatFieldsRest),
Struct(Option<P<QSelf>>, Path, ThinVec<PatField>, /* recovered */ bool),
/// A tuple struct/variant pattern (`Variant(x, y, .., z)`). /// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
TupleStruct(Option<P<QSelf>>, Path, ThinVec<P<Pat>>), TupleStruct(Option<P<QSelf>>, Path, ThinVec<P<Pat>>),
@ -835,6 +811,18 @@ pub enum PatKind {
/// A macro pattern; pre-expansion. /// A macro pattern; pre-expansion.
MacCall(P<MacCall>), 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, /// The kind of borrow in an `AddrOf` expression,
@ -1193,7 +1181,7 @@ impl Expr {
match &self.kind { match &self.kind {
ExprKind::Path(None, path) => Some(GenericBound::Trait( ExprKind::Path(None, path) => Some(GenericBound::Trait(
PolyTraitRef::new(ThinVec::new(), path.clone(), self.span), PolyTraitRef::new(ThinVec::new(), path.clone(), self.span),
TraitBoundModifier::None, TraitBoundModifiers::NONE,
)), )),
_ => None, _ => None,
} }
@ -1274,7 +1262,7 @@ impl Expr {
ExprKind::Let(..) => ExprPrecedence::Let, ExprKind::Let(..) => ExprPrecedence::Let,
ExprKind::If(..) => ExprPrecedence::If, ExprKind::If(..) => ExprPrecedence::If,
ExprKind::While(..) => ExprPrecedence::While, ExprKind::While(..) => ExprPrecedence::While,
ExprKind::ForLoop(..) => ExprPrecedence::ForLoop, ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop,
ExprKind::Loop(..) => ExprPrecedence::Loop, ExprKind::Loop(..) => ExprPrecedence::Loop,
ExprKind::Match(..) => ExprPrecedence::Match, ExprKind::Match(..) => ExprPrecedence::Match,
ExprKind::Closure(..) => ExprPrecedence::Closure, ExprKind::Closure(..) => ExprPrecedence::Closure,
@ -1436,10 +1424,10 @@ pub enum ExprKind {
While(P<Expr>, P<Block>, Option<Label>), While(P<Expr>, P<Block>, Option<Label>),
/// A `for` loop, with an optional 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. /// 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`). /// Conditionless loop (can be exited with `break`, `continue`, or `return`).
/// ///
/// `'label: loop { block }` /// `'label: loop { block }`
@ -1542,6 +1530,13 @@ pub enum ExprKind {
Err, 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. /// Used to differentiate between `async {}` blocks and `gen {}` blocks.
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
pub enum GenBlockKind { pub enum GenBlockKind {
@ -1839,7 +1834,7 @@ pub enum LitKind {
/// A character literal (`'a'`). /// A character literal (`'a'`).
Char(char), Char(char),
/// An integer literal (`1`). /// An integer literal (`1`).
Int(u128, LitIntType), Int(Pu128, LitIntType),
/// A float literal (`1.0`, `1f64` or `1E10f64`). The pre-suffix part is /// 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` /// stored as a symbol rather than `f64` so that `LitKind` can impl `Eq`
/// and `Hash`. /// and `Hash`.
@ -2181,9 +2176,10 @@ pub enum InlineAsmRegOrRegClass {
RegClass(Symbol), RegClass(Symbol),
} }
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
pub struct InlineAsmOptions(u16);
bitflags::bitflags! { bitflags::bitflags! {
#[derive(Encodable, Decodable, HashStable_Generic)] impl InlineAsmOptions: u16 {
pub struct InlineAsmOptions: u16 {
const PURE = 1 << 0; const PURE = 1 << 0;
const NOMEM = 1 << 1; const NOMEM = 1 << 1;
const READONLY = 1 << 2; 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)] #[derive(Clone, PartialEq, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
pub enum InlineAsmTemplatePiece { pub enum InlineAsmTemplatePiece {
String(String), 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 { pub enum BoundPolarity {
/// `Type: Trait` /// `Type: Trait`
Positive, Positive,
@ -2526,6 +2530,38 @@ pub enum BoundPolarity {
Maybe(Span), 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)] #[derive(Clone, Encodable, Decodable, Debug)]
pub enum FnRetTy { pub enum FnRetTy {
/// Returns type is not specified. /// Returns type is not specified.
@ -2651,22 +2687,6 @@ pub enum AttrStyle {
Inner, 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. /// A list of attributes.
pub type AttrVec = ThinVec<Attribute>; pub type AttrVec = ThinVec<Attribute>;
@ -2858,6 +2878,7 @@ impl Item {
| ItemKind::ForeignMod(_) | ItemKind::ForeignMod(_)
| ItemKind::GlobalAsm(_) | ItemKind::GlobalAsm(_)
| ItemKind::MacCall(_) | ItemKind::MacCall(_)
| ItemKind::Delegation(_)
| ItemKind::MacroDef(_) => None, | ItemKind::MacroDef(_) => None,
ItemKind::Static(_) => None, ItemKind::Static(_) => None,
ItemKind::Const(i) => Some(&i.generics), ItemKind::Const(i) => Some(&i.generics),
@ -3004,6 +3025,15 @@ pub struct Fn {
pub body: Option<P<Block>>, 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)] #[derive(Clone, Encodable, Decodable, Debug)]
pub struct StaticItem { pub struct StaticItem {
pub ty: P<Ty>, pub ty: P<Ty>,
@ -3089,6 +3119,11 @@ pub enum ItemKind {
/// A macro definition. /// A macro definition.
MacroDef(MacroDef), MacroDef(MacroDef),
/// A delegation item (`reuse`).
///
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
Delegation(Box<Delegation>),
} }
impl ItemKind { impl ItemKind {
@ -3096,7 +3131,8 @@ impl ItemKind {
use ItemKind::*; use ItemKind::*;
match self { match self {
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..) 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", ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
} }
} }
@ -3120,6 +3156,7 @@ impl ItemKind {
ItemKind::MacCall(..) => "item macro invocation", ItemKind::MacCall(..) => "item macro invocation",
ItemKind::MacroDef(..) => "macro definition", ItemKind::MacroDef(..) => "macro definition",
ItemKind::Impl { .. } => "implementation", ItemKind::Impl { .. } => "implementation",
ItemKind::Delegation(..) => "delegated function",
} }
} }
@ -3161,6 +3198,8 @@ pub enum AssocItemKind {
Type(Box<TyAlias>), Type(Box<TyAlias>),
/// A macro expanding to associated items. /// A macro expanding to associated items.
MacCall(P<MacCall>), MacCall(P<MacCall>),
/// An associated delegation item.
Delegation(Box<Delegation>),
} }
impl AssocItemKind { impl AssocItemKind {
@ -3169,7 +3208,7 @@ impl AssocItemKind {
Self::Const(box ConstItem { defaultness, .. }) Self::Const(box ConstItem { defaultness, .. })
| Self::Fn(box Fn { defaultness, .. }) | Self::Fn(box Fn { defaultness, .. })
| Self::Type(box TyAlias { defaultness, .. }) => 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::Fn(fn_kind) => ItemKind::Fn(fn_kind),
AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind), AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
AssocItemKind::MacCall(a) => ItemKind::MacCall(a), 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::Fn(fn_kind) => AssocItemKind::Fn(fn_kind),
ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind), ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
ItemKind::MacCall(a) => AssocItemKind::MacCall(a), ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
ItemKind::Delegation(d) => AssocItemKind::Delegation(d),
_ => return Err(item_kind), _ => return Err(item_kind),
}) })
} }
@ -3259,7 +3300,7 @@ mod size_asserts {
static_assert_size!(ForeignItem, 96); static_assert_size!(ForeignItem, 96);
static_assert_size!(ForeignItemKind, 24); static_assert_size!(ForeignItemKind, 24);
static_assert_size!(GenericArg, 24); static_assert_size!(GenericArg, 24);
static_assert_size!(GenericBound, 64); static_assert_size!(GenericBound, 72);
static_assert_size!(Generics, 40); static_assert_size!(Generics, 40);
static_assert_size!(Impl, 136); static_assert_size!(Impl, 136);
static_assert_size!(Item, 136); static_assert_size!(Item, 136);

View File

@ -13,13 +13,11 @@
#![feature(rustdoc_internals)] #![feature(rustdoc_internals)]
#![feature(associated_type_bounds)] #![feature(associated_type_bounds)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(const_trait_impl)]
#![feature(if_let_guard)] #![feature(if_let_guard)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(min_specialization)] #![feature(min_specialization)]
#![feature(negative_impls)] #![feature(negative_impls)]
#![feature(stmt_expr_attributes)] #![feature(stmt_expr_attributes)]
#![recursion_limit = "256"]
#![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)] #![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::MacCall(m) => vis.visit_mac_call(m),
ItemKind::MacroDef(def) => vis.visit_macro_def(def), 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)); visit_opt(ty, |ty| visitor.visit_ty(ty));
} }
AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac), 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); visitor.visit_span(span);
visit_lazy_tts(tokens, visitor); 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(); let Pat { id, kind, span, tokens } = pat.deref_mut();
vis.visit_id(id); vis.visit_id(id);
match kind { match kind {
PatKind::Wild | PatKind::Rest | PatKind::Never => {} PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {}
PatKind::Ident(_binding_mode, ident, sub) => { PatKind::Ident(_binding_mode, ident, sub) => {
vis.visit_ident(ident); vis.visit_ident(ident);
visit_opt(sub, |sub| vis.visit_pat(sub)); visit_opt(sub, |sub| vis.visit_pat(sub));
@ -1389,7 +1405,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
vis.visit_block(body); vis.visit_block(body);
visit_opt(label, |label| vis.visit_label(label)); 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_pat(pat);
vis.visit_expr(iter); vis.visit_expr(iter);
vis.visit_block(body); 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. /// Returns `true` if the token can appear at the start of an item.
pub fn can_begin_item(&self) -> bool { pub fn can_begin_item(&self) -> bool {
match self.kind { match self.kind {

View File

@ -21,12 +21,12 @@ use crate::AttrVec;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{self, Lrc}; use rustc_data_structures::sync::{self, Lrc};
use rustc_macros::HashStable_Generic; use rustc_macros::HashStable_Generic;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_serialize::{Decodable, Encodable};
use rustc_span::{sym, Span, Symbol, DUMMY_SP}; use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use std::borrow::Cow; 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 /// 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 /// 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. /// Create a `TokenTree::Token` with alone spacing.
pub fn token_alone(kind: TokenKind, span: Span) -> TokenTree { pub fn token_alone(kind: TokenKind, span: Span) -> TokenTree {
TokenTree::Token(Token::new(kind, span), Spacing::Alone) 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) { fn encode(&self, s: &mut S) {
// Used by AST json printing. // Used by AST json printing.
Encodable::encode(&self.to_attr_token_stream(), s); 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 { fn decode(_d: &mut D) -> Self {
panic!("Attempted to decode LazyAttrTokenStream"); panic!("Attempted to decode LazyAttrTokenStream");
} }
@ -461,19 +453,6 @@ impl TokenStream {
t1.next().is_none() && t2.next().is_none() 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 /// 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 /// spacing used for the final token in a constructed stream doesn't matter
/// because it's never used. In practice we arbitrarily use /// 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 // 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 /// Does this expression require a semicolon to be treated
/// as a statement? The negation of this: 'can this expression /// 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::Block(..)
| ast::ExprKind::While(..) | ast::ExprKind::While(..)
| ast::ExprKind::Loop(..) | ast::ExprKind::Loop(..)
| ast::ExprKind::ForLoop(..) | ast::ExprKind::ForLoop { .. }
| ast::ExprKind::TryBlock(..) | ast::ExprKind::TryBlock(..)
| ast::ExprKind::ConstBlock(..) | ast::ExprKind::ConstBlock(..)
) )
@ -48,11 +48,23 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
Closure(closure) => { Closure(closure) => {
expr = &closure.body; expr = &closure.body;
} }
Gen(..) | Block(..) | ForLoop(..) | If(..) | Loop(..) | Match(..) | Struct(..) Gen(..)
| TryBlock(..) | While(..) | ConstBlock(_) => break Some(expr), | Block(..)
| ForLoop { .. }
| If(..)
| Loop(..)
| Match(..)
| Struct(..)
| TryBlock(..)
| While(..)
| ConstBlock(_) => break Some(expr),
// FIXME: These can end in `}`, but changing these would break stable code. MacCall(mac) => {
InlineAsm(_) | OffsetOf(_, _) | MacCall(_) | IncludedBytes(_) | FormatArgs(_) => { break (mac.args.delim == Delimiter::Brace).then_some(expr);
}
InlineAsm(_) | OffsetOf(_, _) | IncludedBytes(_) | FormatArgs(_) => {
// These should have been denied pre-expansion.
break None; break None;
} }

View File

@ -3,12 +3,10 @@
use crate::ast::{self, LitKind, MetaItemLit, StrStyle}; use crate::ast::{self, LitKind, MetaItemLit, StrStyle};
use crate::token::{self, Token}; use crate::token::{self, Token};
use rustc_lexer::unescape::{ use rustc_lexer::unescape::{
byte_from_char, unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, MixedUnit, Mode,
Mode,
}; };
use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span; use rustc_span::Span;
use std::ops::Range;
use std::{ascii, fmt, str}; use std::{ascii, fmt, str};
// Escapes a string, represented as a symbol. Reuses the original symbol, // Escapes a string, represented as a symbol. Reuses the original symbol,
@ -39,7 +37,6 @@ pub enum LitError {
InvalidFloatSuffix, InvalidFloatSuffix,
NonDecimalFloat(u32), NonDecimalFloat(u32),
IntTooLarge(u32), IntTooLarge(u32),
NulInCStr(Range<usize>),
} }
impl LitKind { impl LitKind {
@ -50,6 +47,9 @@ impl LitKind {
return Err(LitError::InvalidSuffix); 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 { Ok(match kind {
token::Bool => { token::Bool => {
assert!(symbol.is_bool_lit()); assert!(symbol.is_bool_lit());
@ -58,12 +58,12 @@ impl LitKind {
token::Byte => { token::Byte => {
return unescape_byte(symbol.as_str()) return unescape_byte(symbol.as_str())
.map(LitKind::Byte) .map(LitKind::Byte)
.map_err(|_| LitError::LexerError); .map_err(|_| panic!("failed to unescape byte literal"));
} }
token::Char => { token::Char => {
return unescape_char(symbol.as_str()) return unescape_char(symbol.as_str())
.map(LitKind::Char) .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, // There are some valid suffixes for integer and float literals,
@ -79,26 +79,22 @@ impl LitKind {
let s = symbol.as_str(); let s = symbol.as_str();
// Vanilla strings are so common we optimize for the common case where no chars // Vanilla strings are so common we optimize for the common case where no chars
// requiring special behaviour are present. // 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 buf = String::with_capacity(s.len());
let mut error = Ok(());
// Force-inlining here is aggressive but the closure is // Force-inlining here is aggressive but the closure is
// called on every char in the string, so it can be // called on every char in the string, so it can be hot in
// hot in programs with many long strings. // programs with many long strings containing escapes.
unescape_literal( unescape_unicode(
s, s,
Mode::Str, Mode::Str,
&mut #[inline(always)] &mut #[inline(always)]
|_, unescaped_char| match unescaped_char { |_, c| match c {
Ok(c) => buf.push(c), Ok(c) => buf.push(c),
Err(err) => { Err(err) => {
if err.is_fatal() { assert!(!err.is_fatal(), "failed to unescape string literal")
error = Err(LitError::LexerError);
}
} }
}, },
); );
error?;
Symbol::intern(&buf) Symbol::intern(&buf)
} else { } else {
symbol symbol
@ -106,92 +102,46 @@ impl LitKind {
LitKind::Str(symbol, ast::StrStyle::Cooked) LitKind::Str(symbol, ast::StrStyle::Cooked)
} }
token::StrRaw(n) => { token::StrRaw(n) => {
// Raw strings have no escapes, so we only need to check for invalid chars, and we // Raw strings have no escapes so no work is needed here.
// 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?;
LitKind::Str(symbol, ast::StrStyle::Raw(n)) LitKind::Str(symbol, ast::StrStyle::Raw(n))
} }
token::ByteStr => { token::ByteStr => {
let s = symbol.as_str(); let s = symbol.as_str();
let mut buf = Vec::with_capacity(s.len()); let mut buf = Vec::with_capacity(s.len());
let mut error = Ok(()); unescape_unicode(s, Mode::ByteStr, &mut |_, c| match c {
unescape_literal(s, Mode::ByteStr, &mut |_, c| match c {
Ok(c) => buf.push(byte_from_char(c)), Ok(c) => buf.push(byte_from_char(c)),
Err(err) => { Err(err) => {
if err.is_fatal() { assert!(!err.is_fatal(), "failed to unescape string literal")
error = Err(LitError::LexerError);
}
} }
}); });
error?;
LitKind::ByteStr(buf.into(), StrStyle::Cooked) LitKind::ByteStr(buf.into(), StrStyle::Cooked)
} }
token::ByteStrRaw(n) => { token::ByteStrRaw(n) => {
// Raw strings have no escapes, so we only need to check for invalid chars, and we // Raw strings have no escapes so we can convert the symbol
// can convert the symbol directly to a `Lrc<u8>` on success. // directly to a `Lrc<u8>`.
let s = symbol.as_str(); let buf = symbol.as_str().to_owned().into_bytes();
let mut error = Ok(()); LitKind::ByteStr(buf.into(), StrStyle::Raw(n))
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))
} }
token::CStr => { token::CStr => {
let s = symbol.as_str(); let s = symbol.as_str();
let mut buf = Vec::with_capacity(s.len()); let mut buf = Vec::with_capacity(s.len());
let mut error = Ok(()); unescape_mixed(s, Mode::CStr, &mut |_span, c| match c {
unescape_c_string(s, Mode::CStr, &mut |span, c| match c { Ok(MixedUnit::Char(c)) => {
Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
error = Err(LitError::NulInCStr(span));
}
Ok(CStrUnit::Byte(b)) => buf.push(b),
Ok(CStrUnit::Char(c)) => {
buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
} }
Ok(MixedUnit::HighByte(b)) => buf.push(b),
Err(err) => { Err(err) => {
if err.is_fatal() { assert!(!err.is_fatal(), "failed to unescape C string literal")
error = Err(LitError::LexerError);
}
} }
}); });
error?;
buf.push(0); buf.push(0);
LitKind::CStr(buf.into(), StrStyle::Cooked) LitKind::CStr(buf.into(), StrStyle::Cooked)
} }
token::CStrRaw(n) => { token::CStrRaw(n) => {
// Raw strings have no escapes, so we only need to check for invalid chars, and we // Raw strings have no escapes so we can convert the symbol
// can convert the symbol directly to a `Lrc<u8>` on success. // directly to a `Lrc<u8>` after appending the terminating NUL
let s = symbol.as_str(); // char.
let mut error = Ok(()); let mut buf = symbol.as_str().to_owned().into_bytes();
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();
buf.push(0); buf.push(0);
LitKind::CStr(buf.into(), StrStyle::Raw(n)) 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 }..]; 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 // 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, // might be `0b10201`. This will cause the conversion above to fail,
// but these kinds of errors are already reported by the lexer. // 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::MacCall(mac) => visitor.visit_mac_call(mac),
ItemKind::MacroDef(ts) => visitor.visit_mac_def(ts, item.id), 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); walk_list!(visitor, visit_attribute, &item.attrs);
} }
@ -493,7 +502,7 @@ where
} }
GenericArgs::Parenthesized(data) => { GenericArgs::Parenthesized(data) => {
walk_list!(visitor, visit_ty, &data.inputs); 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, lower_bound);
walk_list!(visitor, visit_expr, upper_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) => { PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
walk_list!(visitor, visit_pat, 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) => { AssocItemKind::MacCall(mac) => {
visitor.visit_mac_call(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_expr(subexpression);
visitor.visit_block(block); visitor.visit_block(block);
} }
ExprKind::ForLoop(pattern, subexpression, block, opt_label) => { ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
walk_list!(visitor, visit_label, opt_label); walk_list!(visitor, visit_label, label);
visitor.visit_pat(pattern); visitor.visit_pat(pat);
visitor.visit_expr(subexpression); visitor.visit_expr(iter);
visitor.visit_block(block); visitor.visit_block(body);
} }
ExprKind::Loop(block, opt_label, _) => { ExprKind::Loop(block, opt_label, _) => {
walk_list!(visitor, visit_label, 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 = ast_lowering_async_coroutines_not_supported =
`async` coroutines are not yet 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 = ast_lowering_att_syntax_only_x86 =
the `att_syntax` option is only supported on 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 = ast_lowering_base_expression_double_dot =
base expression required after `..` base expression required after `..`
.label = add a base expression here .suggestion = add a base expression here
ast_lowering_clobber_abi_not_supported = ast_lowering_clobber_abi_not_supported =
`clobber_abi` is not supported on this target `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 functional record updates are not allowed in destructuring assignments
.suggestion = consider removing the trailing pattern .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 = ast_lowering_generic_type_with_parentheses =
parenthesized type parameters may only be used with a `Fn` trait parenthesized type parameters may only be used with a `Fn` trait
.label = only `Fn` traits may use parentheses .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 .note = only allowed in tuple, tuple struct, and slice patterns
ast_lowering_misplaced_impl_trait = 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 = ast_lowering_misplaced_relax_trait_bound =
`?Trait` bounds are only permitted at the point where a type parameter is declared `?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 = let asm_arch =
if self.tcx.sess.opts.actually_rustdoc { None } else { self.tcx.sess.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 { 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 { if let Some(asm_arch) = asm_arch {
// Inline assembly is currently only stable for these architectures. // 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 { if !is_stable && !self.tcx.features().asm_experimental_arch {
feature_err( feature_err(
&self.tcx.sess.parse_sess, &self.tcx.sess,
sym::asm_experimental_arch, sym::asm_experimental_arch,
sp, sp,
"inline assembly is not stable yet on this architecture", "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)) && !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
&& !self.tcx.sess.opts.actually_rustdoc && !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 { if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind {
feature_err( feature_err(&self.tcx.sess, sym::asm_unwind, sp, "the `may_unwind` option is unstable")
&self.tcx.sess.parse_sess, .emit();
sym::asm_unwind,
sp,
"the `may_unwind` option is unstable",
)
.emit();
} }
let mut clobber_abis = FxIndexMap::default(); let mut clobber_abis = FxIndexMap::default();
@ -87,7 +82,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
!= source_map.span_to_snippet(*abi_span)) != source_map.span_to_snippet(*abi_span))
.then_some(()); .then_some(());
self.tcx.sess.emit_err(AbiSpecifiedMultipleTimes { self.dcx().emit_err(AbiSpecifiedMultipleTimes {
abi_span: *abi_span, abi_span: *abi_span,
prev_name: *prev_name, prev_name: *prev_name,
prev_span: *prev_sp, prev_span: *prev_sp,
@ -100,14 +95,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
} }
Err(&[]) => { Err(&[]) => {
self.tcx.sess.emit_err(ClobberAbiNotSupported { abi_span: *abi_span }); self.dcx().emit_err(ClobberAbiNotSupported { abi_span: *abi_span });
} }
Err(supported_abis) => { Err(supported_abis) => {
let mut abis = format!("`{}`", supported_abis[0]); let mut abis = format!("`{}`", supported_abis[0]);
for m in &supported_abis[1..] { for m in &supported_abis[1..] {
let _ = write!(abis, ", `{m}`"); let _ = write!(abis, ", `{m}`");
} }
self.tcx.sess.emit_err(InvalidAbiClobberAbi { self.dcx().emit_err(InvalidAbiClobberAbi {
abi_span: *abi_span, abi_span: *abi_span,
supported_abis: abis, supported_abis: abis,
}); });
@ -128,7 +123,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
InlineAsmRegOrRegClass::Reg(reg) => { InlineAsmRegOrRegClass::Reg(reg) => {
asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch { asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
asm::InlineAsmReg::parse(asm_arch, reg).unwrap_or_else(|error| { 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 asm::InlineAsmReg::Err
}) })
} else { } else {
@ -139,7 +138,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch { asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch {
asm::InlineAsmRegClass::parse(asm_arch, reg_class).unwrap_or_else( asm::InlineAsmRegClass::parse(asm_arch, reg_class).unwrap_or_else(
|error| { |error| {
sess.emit_err(InvalidRegisterClass { self.dcx().emit_err(InvalidRegisterClass {
op_span: *op_sp, op_span: *op_sp,
reg_class, reg_class,
error, error,
@ -179,7 +178,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
InlineAsmOperand::Const { anon_const } => { InlineAsmOperand::Const { anon_const } => {
if !self.tcx.features().asm_const { if !self.tcx.features().asm_const {
feature_err( feature_err(
&sess.parse_sess, sess,
sym::asm_const, sym::asm_const,
*op_sp, *op_sp,
"const operands for inline assembly are unstable", "const operands for inline assembly are unstable",
@ -276,7 +275,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
class_name: class.name(), class_name: class.name(),
} }
}; };
sess.emit_err(InvalidAsmTemplateModifierRegClass { self.dcx().emit_err(InvalidAsmTemplateModifierRegClass {
placeholder_span, placeholder_span,
op_span: op_sp, op_span: op_sp,
sub, sub,
@ -284,14 +283,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
} }
hir::InlineAsmOperand::Const { .. } => { hir::InlineAsmOperand::Const { .. } => {
sess.emit_err(InvalidAsmTemplateModifierConst { self.dcx().emit_err(InvalidAsmTemplateModifierConst {
placeholder_span, placeholder_span,
op_span: op_sp, op_span: op_sp,
}); });
} }
hir::InlineAsmOperand::SymFn { .. } hir::InlineAsmOperand::SymFn { .. }
| hir::InlineAsmOperand::SymStatic { .. } => { | hir::InlineAsmOperand::SymStatic { .. } => {
sess.emit_err(InvalidAsmTemplateModifierSym { self.dcx().emit_err(InvalidAsmTemplateModifierSym {
placeholder_span, placeholder_span,
op_span: op_sp, op_span: op_sp,
}); });
@ -315,7 +314,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// require that the operand name an explicit register, not a // require that the operand name an explicit register, not a
// register class. // register class.
if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() { 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, op_span: op_sp,
reg_class_name: reg_class.name(), 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_span1: op_sp,
op_span2: op_sp2, op_span2: op_sp2,
reg1_name: reg_str(idx), 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_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{symbol::Ident, Span, Symbol}; use rustc_span::{symbol::Ident, Span, Symbol};
#[derive(Diagnostic, Clone, Copy)] #[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 { pub struct GenericTypeWithParentheses {
#[primary_span] #[primary_span]
#[label] #[label]
@ -22,7 +22,7 @@ pub struct UseAngleBrackets {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_lowering_invalid_abi, code = "E0703")] #[diag(ast_lowering_invalid_abi, code = E0703)]
#[note] #[note]
pub struct InvalidAbi { pub struct InvalidAbi {
#[primary_span] #[primary_span]
@ -89,7 +89,8 @@ pub enum AssocTyParenthesesSub {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_lowering_misplaced_impl_trait, code = "E0562")] #[diag(ast_lowering_misplaced_impl_trait, code = E0562)]
#[note]
pub struct MisplacedImplTrait<'a> { pub struct MisplacedImplTrait<'a> {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -113,15 +114,15 @@ pub struct UnderscoreExprLhsAssign {
} }
#[derive(Diagnostic, Clone, Copy)] #[derive(Diagnostic, Clone, Copy)]
#[diag(ast_lowering_base_expression_double_dot)] #[diag(ast_lowering_base_expression_double_dot, code = E0797)]
pub struct BaseExpressionDoubleDot { pub struct BaseExpressionDoubleDot {
#[primary_span] #[primary_span]
#[label] #[suggestion(code = "/* expr */", applicability = "has-placeholders", style = "verbose")]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic, Clone, Copy)] #[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 { pub struct AwaitOnlyInAsyncFnAndBlocks {
#[primary_span] #[primary_span]
#[label] #[label]
@ -131,27 +132,19 @@ pub struct AwaitOnlyInAsyncFnAndBlocks {
} }
#[derive(Diagnostic, Clone, Copy)] #[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 { pub struct CoroutineTooManyParameters {
#[primary_span] #[primary_span]
pub fn_decl_span: Span, pub fn_decl_span: Span,
} }
#[derive(Diagnostic, Clone, Copy)] #[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 { pub struct ClosureCannotBeStatic {
#[primary_span] #[primary_span]
pub fn_decl_span: 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)] #[derive(Diagnostic, Clone, Copy)]
#[diag(ast_lowering_functional_record_update_destructuring_assignment)] #[diag(ast_lowering_functional_record_update_destructuring_assignment)]
pub struct FunctionalRecordUpdateDestructuringAssignment { pub struct FunctionalRecordUpdateDestructuringAssignment {
@ -161,14 +154,14 @@ pub struct FunctionalRecordUpdateDestructuringAssignment {
} }
#[derive(Diagnostic, Clone, Copy)] #[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 { pub struct AsyncCoroutinesNotSupported {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic, Clone, Copy)] #[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 { pub struct InlineAsmUnsupportedTarget {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -395,3 +388,10 @@ pub enum BadReturnTypeNotation {
span: Span, 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::{ use super::errors::{
AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks, AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters, ClosureCannotBeStatic, CoroutineTooManyParameters,
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody, FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure, NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure,
UnderscoreExprLhsAssign, UnderscoreExprLhsAssign,
@ -13,7 +13,6 @@ use rustc_ast::*;
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_middle::span_bug;
use rustc_session::errors::report_lit_error; use rustc_session::errors::report_lit_error;
use rustc_span::source_map::{respan, Spanned}; use rustc_span::source_map::{respan, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::symbol::{kw, sym, Ident, Symbol};
@ -56,12 +55,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
return ex; return ex;
} }
// Desugar `ExprForLoop` // 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 // 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. // correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself.
ExprKind::ForLoop(pat, head, body, opt_label) => { ExprKind::ForLoop { pat, iter, body, label, kind } => {
return self.lower_expr_for(e, pat, head, body, *opt_label); 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) => { ExprKind::Let(pat, scrutinee, span, is_recovered) => {
hir::ExprKind::Let(self.arena.alloc(hir::Let { hir::ExprKind::Let(self.arena.alloc(hir::Let {
hir_id: self.next_id(),
span: self.lower_span(*span), span: self.lower_span(*span),
pat: self.lower_pat(pat), pat: self.lower_pat(pat),
ty: None, ty: None,
@ -183,14 +181,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))), self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
hir::MatchSource::Normal, 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::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
ExprKind::Closure(box Closure { ExprKind::Closure(box Closure {
binder, binder,
@ -226,6 +216,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
*fn_arg_span, *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) => { ExprKind::Block(blk, opt_label) => {
let opt_label = self.lower_label(*opt_label); let opt_label = self.lower_label(*opt_label);
hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), 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) self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims)
} }
ExprKind::Underscore => { 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) hir::ExprKind::Err(guar)
} }
ExprKind::Path(qself, path) => { ExprKind::Path(qself, path) => {
@ -294,8 +300,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let rest = match &se.rest { let rest = match &se.rest {
StructRest::Base(e) => Some(self.lower_expr(e)), StructRest::Base(e) => Some(self.lower_expr(e)),
StructRest::Rest(sp) => { StructRest::Rest(sp) => {
let guar = let guar = self.dcx().emit_err(BaseExpressionDoubleDot { span: *sp });
self.tcx.sess.emit_err(BaseExpressionDoubleDot { span: *sp });
Some(&*self.arena.alloc(self.expr_err(*sp, guar))) Some(&*self.arena.alloc(self.expr_err(*sp, guar)))
} }
StructRest::None => None, StructRest::None => None,
@ -314,30 +319,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
rest, 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::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
ExprKind::Err => hir::ExprKind::Err( ExprKind::Err => {
self.tcx.sess.span_delayed_bug(e.span, "lowered 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::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
ExprKind::Paren(_) | ExprKind::ForLoop(..) => { ExprKind::Paren(_) | ExprKind::ForLoop { .. } => {
unreachable!("already handled") unreachable!("already handled")
} }
@ -556,20 +544,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
let pat = self.lower_pat(&arm.pat); let pat = self.lower_pat(&arm.pat);
let mut guard = arm.guard.as_ref().map(|cond| { let guard = arm.guard.as_ref().map(|cond| self.lower_expr(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 hir_id = self.next_id(); let hir_id = self.next_id();
let span = self.lower_span(arm.span); let span = self.lower_span(arm.span);
self.lower_attrs(hir_id, &arm.attrs); self.lower_attrs(hir_id, &arm.attrs);
@ -584,14 +559,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
if self.tcx.features().never_patterns { if self.tcx.features().never_patterns {
// If the feature is off we already emitted the error after parsing. // If the feature is off we already emitted the error after parsing.
let suggestion = span.shrink_to_hi(); 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 { } else if let Some(body) = &arm.body {
self.tcx.sess.emit_err(NeverPatternWithBody { span: body.span }); self.dcx().emit_err(NeverPatternWithBody { span: body.span });
guard = None;
} else if let Some(g) = &arm.guard { } else if let Some(g) = &arm.guard {
self.tcx.sess.emit_err(NeverPatternWithGuard { span: g.span }); self.dcx().emit_err(NeverPatternWithGuard { span: g.span });
guard = None;
} }
// We add a fake `loop {}` arm body so that it typecks to `!`. // 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 } 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: /// This results in:
/// ///
/// ```text /// ```text
/// static move? |_task_context| -> <ret_ty> { /// static move? |<_task_context?>| -> <return_ty> {
/// <body> /// <body>
/// } /// }
/// ``` /// ```
pub(super) fn make_async_expr( pub(super) fn make_desugared_coroutine_expr(
&mut self, &mut self,
capture_clause: CaptureBy, capture_clause: CaptureBy,
closure_node_id: NodeId, closure_node_id: NodeId,
ret_ty: Option<hir::FnRetTy<'hir>>, return_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>>,
span: Span, span: Span,
desugaring_kind: hir::CoroutineDesugaring,
coroutine_source: hir::CoroutineSource, coroutine_source: hir::CoroutineSource,
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
) -> hir::ExprKind<'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 { let fn_decl = self.arena.alloc(hir::FnDecl {
inputs: &[], inputs,
output, output,
c_variadic: false, c_variadic: false,
implicit_self: hir::ImplicitSelfKind::None, implicit_self: hir::ImplicitSelfKind::None,
@ -724,94 +658,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
}); });
let body = self.lower_body(move |this| { let body = self.lower_body(move |this| {
this.coroutine_kind = Some(hir::CoroutineKind::Gen(coroutine_source)); this.coroutine_kind = Some(coroutine_kind);
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));
let old_ctx = this.task_context; 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); let res = body(this);
this.task_context = old_ctx; this.task_context = old_ctx;
(params, res) (params, res)
}); });
// `static |_task_context| -> <ret_ty> { body }`: // `static |<_task_context?>| -> <return_ty> { <body> }`:
hir::ExprKind::Closure(self.arena.alloc(hir::Closure { hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
def_id: self.local_def_id(closure_node_id), def_id: self.local_def_id(closure_node_id),
binder: hir::ClosureBinder::Default, binder: hir::ClosureBinder::Default,
@ -821,7 +680,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
body, body,
fn_decl_span: self.lower_span(span), fn_decl_span: self.lower_span(span),
fn_arg_span: None, fn_arg_span: None,
movability: Some(hir::Movability::Static), kind: hir::ClosureKind::Coroutine(coroutine_kind),
constness: hir::Constness::NotConst, 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> { 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 full_span = expr.span.to(await_kw_span);
let is_async_gen = match self.coroutine_kind { let is_async_gen = match self.coroutine_kind {
Some(hir::CoroutineKind::Async(_)) => false, Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => false,
Some(hir::CoroutineKind::AsyncGen(_)) => true, Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
Some(hir::CoroutineKind::Coroutine) | Some(hir::CoroutineKind::Gen(_)) | None => { Some(hir::CoroutineKind::Coroutine(_))
return hir::ExprKind::Err(self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks { | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _))
| None => {
return hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {
await_kw_span, await_kw_span,
item_span: self.current_item, 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( let gen_future_span = self.mark_span_with_reason(
DesugaringKind::Await, DesugaringKind::Await,
full_span, full_span,
Some(self.allow_gen_future.clone()), Some(self.allow_gen_future.clone()),
); );
let expr = self.lower_expr_mut(expr);
let expr_hir_id = expr.hir_id; let expr_hir_id = expr.hir_id;
// Note that the name of this binding must not be changed to something else because // 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, hir::LangItem::GetContext,
arena_vec![self; task_context], arena_vec![self; task_context],
); );
let call = self.expr_call_lang_item_fn( let call = match await_kind {
span, FutureKind::Future => self.expr_call_lang_item_fn(
hir::LangItem::FuturePoll, span,
arena_vec![self; new_unchecked, get_context], 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)) self.arena.alloc(self.expr_unsafe(call))
}; };
@ -1020,11 +902,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
let awaitee_arm = self.arm(awaitee_pat, loop_expr); let awaitee_arm = self.arm(awaitee_pat, loop_expr);
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }` // `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
let into_future_expr = self.expr_call_lang_item_fn( let into_future_expr = match await_kind {
span, FutureKind::Future => self.expr_call_lang_item_fn(
hir::LangItem::IntoFutureIntoFuture, span,
arena_vec![self; expr], 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> { // match <into_future_expr> {
// mut __awaitee => loop { .. } // mut __awaitee => loop { .. }
@ -1050,7 +937,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
) -> hir::ExprKind<'hir> { ) -> hir::ExprKind<'hir> {
let (binder_clause, generic_params) = self.lower_closure_binder(binder); 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 mut coroutine_kind = None;
let body_id = this.lower_fn_body(decl, |this| { let body_id = this.lower_fn_body(decl, |this| {
let e = this.lower_expr_mut(body); let e = this.lower_expr_mut(body);
@ -1058,7 +945,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
e e
}); });
let coroutine_option = 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) (body_id, coroutine_option)
}); });
@ -1075,39 +962,39 @@ impl<'hir> LoweringContext<'_, 'hir> {
body: body_id, body: body_id,
fn_decl_span: self.lower_span(fn_decl_span), fn_decl_span: self.lower_span(fn_decl_span),
fn_arg_span: Some(self.lower_span(fn_arg_span)), fn_arg_span: Some(self.lower_span(fn_arg_span)),
movability: coroutine_option, kind: closure_kind,
constness: self.lower_constness(constness), constness: self.lower_constness(constness),
}); });
hir::ExprKind::Closure(c) hir::ExprKind::Closure(c)
} }
fn coroutine_movability_for_fn( fn closure_movability_for_fn(
&mut self, &mut self,
decl: &FnDecl, decl: &FnDecl,
fn_decl_span: Span, fn_decl_span: Span,
coroutine_kind: Option<hir::CoroutineKind>, coroutine_kind: Option<hir::CoroutineKind>,
movability: Movability, movability: Movability,
) -> Option<hir::Movability> { ) -> hir::ClosureKind {
match coroutine_kind { match coroutine_kind {
Some(hir::CoroutineKind::Coroutine) => { Some(hir::CoroutineKind::Coroutine(_)) => {
if decl.inputs.len() > 1 { 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( Some(
hir::CoroutineKind::Gen(_) hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
| hir::CoroutineKind::Async(_) | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)
| hir::CoroutineKind::AsyncGen(_), | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _),
) => { ) => {
panic!("non-`async`/`gen` closure body turned `async`/`gen` during lowering"); panic!("non-`async`/`gen` closure body turned `async`/`gen` during lowering");
} }
None => { None => {
if movability == Movability::Static { 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_decl_span: Span,
fn_arg_span: Span, fn_arg_span: Span,
) -> hir::ExprKind<'hir> { ) -> 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 { 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 (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| { 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 // Transform `async |x: u8| -> X { ... }` into
// `|x: u8| || -> X { ... }`. // `|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 async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output {
let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock); let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock);
Some(hir::FnRetTy::Return(this.lower_ty(ty, &itctx))) Some(hir::FnRetTy::Return(this.lower_ty(ty, &itctx)))
@ -1168,21 +1043,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
None None
}; };
let async_body = this.make_async_expr( let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
capture_clause, decl,
inner_closure_id,
async_ret_ty,
body.span,
hir::CoroutineSource::Closure,
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), |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); 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 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); let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
// We need to lower the declaration outside the new scope, because we // 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 // have to conserve the state of being inside a loop condition for the
@ -1199,7 +1079,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
body, body,
fn_decl_span: self.lower_span(fn_decl_span), fn_decl_span: self.lower_span(fn_decl_span),
fn_arg_span: Some(self.lower_span(fn_arg_span)), fn_arg_span: Some(self.lower_span(fn_arg_span)),
movability: None, kind: hir::ClosureKind::Closure,
constness: hir::Constness::NotConst, constness: hir::Constness::NotConst,
}); });
hir::ExprKind::Closure(c) hir::ExprKind::Closure(c)
@ -1411,7 +1291,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
); );
let fields_omitted = match &se.rest { let fields_omitted = match &se.rest {
StructRest::Base(e) => { StructRest::Base(e) => {
self.tcx.sess.emit_err(FunctionalRecordUpdateDestructuringAssignment { self.dcx().emit_err(FunctionalRecordUpdateDestructuringAssignment {
span: e.span, span: e.span,
}); });
true true
@ -1507,7 +1387,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
(None, Some(..), Closed) => hir::LangItem::RangeToInclusive, (None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
(Some(..), Some(..), Closed) => unreachable!(), (Some(..), Some(..), Closed) => unreachable!(),
(start, None, Closed) => { (start, None, Closed) => {
self.tcx.sess.emit_err(InclusiveRangeWithNoEnd { span }); self.dcx().emit_err(InclusiveRangeWithNoEnd { span });
match start { match start {
Some(..) => hir::LangItem::RangeFrom, Some(..) => hir::LangItem::RangeFrom,
None => hir::LangItem::RangeFull, 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> { fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
let is_async_gen = match self.coroutine_kind { let is_async_gen = match self.coroutine_kind {
Some(hir::CoroutineKind::Gen(_)) => false, Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => false,
Some(hir::CoroutineKind::AsyncGen(_)) => true, Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
Some(hir::CoroutineKind::Async(_)) => { Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
return hir::ExprKind::Err( 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 { if !self.tcx.features().coroutines {
rustc_session::parse::feature_err( rustc_session::parse::feature_err(
&self.tcx.sess.parse_sess, &self.tcx.sess,
sym::coroutines, sym::coroutines,
span, span,
"yield syntax is experimental", "yield syntax is experimental",
) )
.emit(); .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 false
} }
}; };
@ -1685,6 +1577,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
head: &Expr, head: &Expr,
body: &Block, body: &Block,
opt_label: Option<Label>, opt_label: Option<Label>,
loop_kind: ForLoopKind,
) -> hir::Expr<'hir> { ) -> hir::Expr<'hir> {
let head = self.lower_expr_mut(head); let head = self.lower_expr_mut(head);
let pat = self.lower_pat(pat); let pat = self.lower_pat(pat);
@ -1713,17 +1606,41 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (iter_pat, iter_pat_nid) = let (iter_pat, iter_pat_nid) =
self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::MUT); self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::MUT);
// `match Iterator::next(&mut iter) { ... }`
let match_expr = { let match_expr = {
let iter = self.expr_ident(head_span, iter, iter_pat_nid); 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 = match loop_kind {
let next_expr = self.expr_call_lang_item_fn( ForLoopKind::For => {
head_span, // `Iterator::next(&mut iter)`
hir::LangItem::IteratorNext, let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
arena_vec![self; ref_mut_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]; let arms = arena_vec![self; none_arm, some_arm];
// `match $next_expr { ... }`
self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar) self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
}; };
let match_stmt = self.stmt_expr(for_span, match_expr); let match_stmt = self.stmt_expr(for_span, match_expr);
@ -1743,13 +1660,34 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `mut iter => { ... }` // `mut iter => { ... }`
let iter_arm = self.arm(iter_pat, loop_expr); let iter_arm = self.arm(iter_pat, loop_expr);
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }` let into_iter_expr = match loop_kind {
let into_iter_expr = { ForLoopKind::For => {
self.expr_call_lang_item_fn( // `::std::iter::IntoIterator::into_iter(<head>)`
head_span, self.expr_call_lang_item_fn(
hir::LangItem::IntoIterIntoIter, head_span,
arena_vec![self; head], 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( 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> { pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> {
let lit = self.arena.alloc(hir::Lit { let lit = self.arena.alloc(hir::Lit {
span: sp, 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)) 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> { pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> {
let lit = self.arena.alloc(hir::Lit { let lit = self.arena.alloc(hir::Lit {
span: sp, 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)) self.expr(sp, hir::ExprKind::Lit(lit))
} }
@ -2033,11 +1977,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
lang_item: hir::LangItem, lang_item: hir::LangItem,
name: Symbol, name: Symbol,
) -> hir::Expr<'hir> { ) -> hir::Expr<'hir> {
let qpath = self.make_lang_item_qpath(lang_item, self.lower_span(span));
let path = hir::ExprKind::Path(hir::QPath::TypeRelative( let path = hir::ExprKind::Path(hir::QPath::TypeRelative(
self.arena.alloc(self.ty( self.arena.alloc(self.ty(span, hir::TyKind::Path(qpath))),
span,
hir::TyKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span))),
)),
self.arena.alloc(hir::PathSegment::new( self.arena.alloc(hir::PathSegment::new(
Ident::new(name, span), Ident::new(name, span),
self.next_id(), 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( ctx.expr(
sp, sp,
hir::ExprKind::Err( 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( Err(_) => ctx.expr(
sp, 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 { 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::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::PredicateOrigin; use rustc_hir::PredicateOrigin;
use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_middle::span_bug;
use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, sym, Ident}; 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) self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs)
} }
ItemKind::Static(box ast::StaticItem { ty: t, mutability: m, expr: e }) => { 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) hir::ItemKind::Static(ty, *m, body_id)
} }
ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
@ -191,7 +193,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
Const::No, Const::No,
id, id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic), &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) hir::ItemKind::Const(ty, generics, body_id)
} }
@ -265,7 +269,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic), &ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| match ty { |this| match ty {
None => { None => {
let guar = this.tcx.sess.span_delayed_bug( let guar = this.dcx().span_delayed_bug(
span, span,
"expected to lower type alias type, but it was missing", "expected to lower type alias type, but it was missing",
); );
@ -339,9 +343,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
let itctx = ImplTraitContext::Universal; let itctx = ImplTraitContext::Universal;
let (generics, (trait_ref, lowered_ty)) = let (generics, (trait_ref, lowered_ty)) =
self.lower_generics(ast_generics, *constness, id, &itctx, |this| { 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| { let trait_ref = trait_ref.as_ref().map(|trait_ref| {
this.lower_trait_ref( this.lower_trait_ref(
*constness, constness,
trait_ref, trait_ref,
&ImplTraitContext::Disallowed(ImplTraitPosition::Trait), &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 }); let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules });
hir::ItemKind::Macro(macro_def, macro_kind) 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(..) => { ItemKind::MacCall(..) => {
panic!("`TyMac` should have been expanded by now") panic!("`TyMac` should have been expanded by now")
} }
@ -443,8 +460,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
ty: &Ty, ty: &Ty,
span: Span, span: Span,
body: Option<&Expr>, body: Option<&Expr>,
impl_trait_position: ImplTraitPosition,
) -> (&'hir hir::Ty<'hir>, hir::BodyId) { ) -> (&'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)) (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, // This is used to track which lifetimes have already been defined,
// and which need to be replicated when lowering an async fn. // 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_) => { hir::ItemKind::Impl(impl_) => {
self.is_in_trait_impl = impl_.of_trait.is_some(); self.is_in_trait_impl = impl_.of_trait.is_some();
&impl_.generics
} }
hir::ItemKind::Trait(_, _, generics, _, _) if self.tcx.features().effects => { hir::ItemKind::Trait(_, _, generics, _, _) => generics,
self.host_param_id = generics kind => {
.params span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr())
.iter()
.find(|param| {
matches!(
param.kind,
hir::GenericParamKind::Const { is_host_effect: true, .. }
)
})
.map(|param| param.def_id);
} }
_ => {} };
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 { match ctxt {
@ -793,6 +813,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
); );
(generics, kind, ty.is_some()) (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"), AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
}; };
@ -814,6 +842,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Fn(box Fn { sig, .. }) => { AssocItemKind::Fn(box Fn { sig, .. }) => {
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() } 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!(), AssocItemKind::MacCall(..) => unimplemented!(),
}; };
let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }; 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), &ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| match ty { |this| match ty {
None => { None => {
let guar = this.tcx.sess.span_delayed_bug( let guar = this.dcx().span_delayed_bug(
i.span, i.span,
"expected to lower associated type, but it was missing", "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"), 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 { 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 { hir::ImplItemRef {
id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }, id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
ident: self.lower_ident(i.ident), ident: self.lower_ident(i.ident),
@ -922,12 +967,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Fn(box Fn { sig, .. }) => { AssocItemKind::Fn(box Fn { sig, .. }) => {
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() } 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!(), AssocItemKind::MacCall(..) => unimplemented!(),
}, },
trait_item_def_id: self trait_item_def_id,
.resolver
.get_partial_res(i.id)
.map(|r| r.expect_full_res().def_id()),
} }
} }
@ -952,11 +997,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
params: &'hir [hir::Param<'hir>], params: &'hir [hir::Param<'hir>],
value: hir::Expr<'hir>, value: hir::Expr<'hir>,
) -> hir::BodyId { ) -> hir::BodyId {
let body = hir::Body { let body = hir::Body { params, value: self.arena.alloc(value) };
coroutine_kind: self.coroutine_kind,
params,
value: self.arena.alloc(value),
};
let id = body.id(); let id = body.id();
debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner); debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
self.bodies.push((id.hir_id.local_id, self.arena.alloc(body))); 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> { fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr<'hir> {
match block { match block {
Some(block) => self.lower_block_expr(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 { match expr {
Some(expr) => this.lower_expr_mut(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 { let (Some(coroutine_kind), Some(body)) = (coroutine_kind, body) else {
return self.lower_fn_body_block(span, decl, body); return self.lower_fn_body_block(span, decl, body);
}; };
let closure_id = coroutine_kind.closure_id();
self.lower_body(|this| { self.lower_body(|this| {
let mut parameters: Vec<hir::Param<'_>> = Vec::new(); let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
let mut statements: Vec<hir::Stmt<'_>> = Vec::new(); 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 // FIXME(async_fn_track_caller): Can this be moved above?
// captured and so that the drop order matches the equivalent non-async functions. 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: // If this is the simple case, this parameter will end up being the same as the
// // original parameter, but with a different pattern id.
// async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) { let stmt_attrs = self.attrs.get(&parameter.hir_id.local_id).copied();
// <body> let (new_parameter_pat, new_parameter_id) = self.pat_ident(desugared_span, ident);
// } let new_parameter = hir::Param {
// hir_id: parameter.hir_id,
// into: pat: new_parameter_pat,
// ty_span: self.lower_span(parameter.ty_span),
// fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) { span: self.lower_span(parameter.span),
// 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;
// Check if this is a binding pattern, if so, we can optimize and avoid adding a if is_simple_parameter {
// `let <pat> = __argN;` statement. In this case, we do not rename the parameter. // If this is the simple case, then we only insert one statement that is
let (ident, is_simple_parameter) = match parameter.pat.kind { // `let <pat> = <pat>;`. We re-use the original argument's pattern so that
hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => { // `HirId`s are densely assigned.
(ident, true) let expr = self.expr_ident(desugared_span, ident, new_parameter_id);
} let stmt = self.stmt_let_pat(
// For `ref mut` or wildcard arguments, we can't reuse the binding, but stmt_attrs,
// 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(
desugared_span, desugared_span,
this.arena.alloc_from_iter(statements), Some(expr),
Some(user_body), 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) // Construct the `let <pat> = __argN;` statement. We re-use the original
}; // parameter's pattern so that `HirId`s are densely assigned.
// FIXME(gen_blocks): Consider unifying the `make_*_expr` functions. let pattern_expr = self.expr_ident(desugared_span, ident, move_id);
let coroutine_expr = match coroutine_kind { let pattern_stmt = self.stmt_let_pat(
CoroutineKind::Async { .. } => this.make_async_expr( stmt_attrs,
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP }, desugared_span,
closure_id, Some(pattern_expr),
None, parameter.pat,
body.span, hir::LocalSource::AsyncFn,
hir::CoroutineSource::Fn, );
mkbody,
), statements.push(move_stmt);
CoroutineKind::Gen { .. } => this.make_gen_expr( statements.push(pattern_stmt);
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
closure_id,
None,
body.span,
hir::CoroutineSource::Fn,
mkbody,
),
CoroutineKind::AsyncGen { .. } => this.make_async_gen_expr(
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
closure_id,
None,
body.span,
hir::CoroutineSource::Fn,
mkbody,
),
}; };
let hir_id = this.lower_node_id(closure_id); parameters.push(new_parameter);
this.maybe_forward_track_caller(body.span, fn_id, hir_id); }
let expr = hir::Expr { hir_id, kind: coroutine_expr, span: this.lower_span(body.span) };
(this.arena.alloc_from_iter(parameters), expr) 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( fn lower_method_sig(
@ -1253,11 +1311,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
coroutine_kind: Option<CoroutineKind>, coroutine_kind: Option<CoroutineKind>,
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
let header = self.lower_fn_header(sig.header); 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 itctx = ImplTraitContext::Universal;
let (generics, decl) = let (generics, decl) = self.lower_generics(generics, constness, id, &itctx, |this| {
self.lower_generics(generics, sig.header.constness, id, &itctx, |this| { this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) });
});
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
} }
@ -1296,7 +1356,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
.map(|s| Symbol::intern(s)) .map(|s| Symbol::intern(s))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let suggested_name = find_best_match_for_name(&abi_names, abi.symbol_unescaped, None); 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, abi: abi.symbol_unescaped,
span: abi.span, span: abi.span,
explain: match err { explain: match err {
@ -1372,12 +1432,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
// need to compute this at all unless there is a Maybe bound. // need to compute this at all unless there is a Maybe bound.
let mut is_param: Option<bool> = None; let mut is_param: Option<bool> = None;
for bound in &bound_pred.bounds { for bound in &bound_pred.bounds {
if !matches!(*bound, GenericBound::Trait(_, TraitBoundModifier::Maybe)) { if !matches!(
*bound,
GenericBound::Trait(
_,
TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. }
)
) {
continue; continue;
} }
let is_param = *is_param.get_or_insert_with(compute_is_param); let is_param = *is_param.get_or_insert_with(compute_is_param);
if !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)] #![doc(rust_logo)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(let_chains)] #![feature(let_chains)]
#![recursion_limit = "256"]
#![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)] #![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::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc; 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 as hir;
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
@ -76,6 +75,7 @@ macro_rules! arena_vec {
mod asm; mod asm;
mod block; mod block;
mod delegation;
mod errors; mod errors;
mod expr; mod expr;
mod format; mod format;
@ -130,6 +130,7 @@ struct LoweringContext<'a, 'hir> {
allow_try_trait: Lrc<[Symbol]>, allow_try_trait: Lrc<[Symbol]>,
allow_gen_future: Lrc<[Symbol]>, allow_gen_future: Lrc<[Symbol]>,
allow_async_iterator: Lrc<[Symbol]>, allow_async_iterator: Lrc<[Symbol]>,
allow_for_await: Lrc<[Symbol]>,
/// Mapping from generics `def_id`s to TAIT generics `def_id`s. /// 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 /// 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 { } else {
[sym::gen_future].into() [sym::gen_future].into()
}, },
allow_for_await: [sym::async_iterator].into(),
// FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller` // FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller`
// interact with `gen`/`async gen` blocks // interact with `gen`/`async gen` blocks
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
@ -181,6 +183,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
host_param_id: None, host_param_id: None,
} }
} }
pub(crate) fn dcx(&self) -> &'hir DiagCtxt {
self.tcx.dcx()
}
} }
trait ResolverAstLoweringExt { trait ResolverAstLoweringExt {
@ -297,8 +303,6 @@ enum ImplTraitPosition {
ClosureParam, ClosureParam,
PointerParam, PointerParam,
FnTraitParam, FnTraitParam,
TraitParam,
ImplParam,
ExternFnReturn, ExternFnReturn,
ClosureReturn, ClosureReturn,
PointerReturn, PointerReturn,
@ -317,29 +321,27 @@ impl std::fmt::Display for ImplTraitPosition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self { let name = match self {
ImplTraitPosition::Path => "paths", ImplTraitPosition::Path => "paths",
ImplTraitPosition::Variable => "variable bindings", ImplTraitPosition::Variable => "the type of variable bindings",
ImplTraitPosition::Trait => "traits", ImplTraitPosition::Trait => "traits",
ImplTraitPosition::AsyncBlock => "async blocks", ImplTraitPosition::AsyncBlock => "async blocks",
ImplTraitPosition::Bound => "bounds", ImplTraitPosition::Bound => "bounds",
ImplTraitPosition::Generic => "generics", ImplTraitPosition::Generic => "generics",
ImplTraitPosition::ExternFnParam => "`extern fn` params", ImplTraitPosition::ExternFnParam => "`extern fn` parameters",
ImplTraitPosition::ClosureParam => "closure params", ImplTraitPosition::ClosureParam => "closure parameters",
ImplTraitPosition::PointerParam => "`fn` pointer params", ImplTraitPosition::PointerParam => "`fn` pointer parameters",
ImplTraitPosition::FnTraitParam => "`Fn` trait params", ImplTraitPosition::FnTraitParam => "the parameters of `Fn` trait bounds",
ImplTraitPosition::TraitParam => "trait method params",
ImplTraitPosition::ImplParam => "`impl` method params",
ImplTraitPosition::ExternFnReturn => "`extern fn` return types", ImplTraitPosition::ExternFnReturn => "`extern fn` return types",
ImplTraitPosition::ClosureReturn => "closure return types", ImplTraitPosition::ClosureReturn => "closure return types",
ImplTraitPosition::PointerReturn => "`fn` pointer 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::GenericDefault => "generic parameter defaults",
ImplTraitPosition::ConstTy => "const types", ImplTraitPosition::ConstTy => "const types",
ImplTraitPosition::StaticTy => "static types", ImplTraitPosition::StaticTy => "static types",
ImplTraitPosition::AssocTy => "associated types", ImplTraitPosition::AssocTy => "associated types",
ImplTraitPosition::FieldTy => "field types", ImplTraitPosition::FieldTy => "field types",
ImplTraitPosition::Cast => "cast types", ImplTraitPosition::Cast => "cast expression types",
ImplTraitPosition::ImplSelf => "impl headers", ImplTraitPosition::ImplSelf => "impl headers",
ImplTraitPosition::OffsetOf => "`offset_of!` params", ImplTraitPosition::OffsetOf => "`offset_of!` parameters",
}; };
write!(f, "{name}") write!(f, "{name}")
@ -357,19 +359,6 @@ enum FnDeclKind {
Impl, 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)] #[derive(Copy, Clone)]
enum AstOwner<'a> { enum AstOwner<'a> {
NonOwner, NonOwner,
@ -671,9 +660,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let (opt_hash_including_bodies, attrs_hash) = if self.tcx.needs_crate_hash() { let (opt_hash_including_bodies, attrs_hash) = if self.tcx.needs_crate_hash() {
self.tcx.with_stable_hashing_context(|mut hcx| { self.tcx.with_stable_hashing_context(|mut hcx| {
let mut stable_hasher = StableHasher::new(); let mut stable_hasher = StableHasher::new();
hcx.with_hir_bodies(node.def_id(), &bodies, |hcx| { node.hash_stable(&mut hcx, &mut stable_hasher);
node.hash_stable(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 h1 = stable_hasher.finish();
let mut stable_hasher = StableHasher::new(); let mut stable_hasher = StableHasher::new();
@ -764,6 +753,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.resolver.get_import_res(id).present_items() 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( fn make_lang_item_path(
&mut self, &mut self,
lang_item: hir::LangItem, lang_item: hir::LangItem,
@ -781,7 +774,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir_id: self.next_id(), hir_id: self.next_id(),
res, res,
args, args,
infer_args: false, infer_args: args.is_none(),
}]), }]),
}) })
} }
@ -1033,11 +1026,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&& first_char.is_ascii_lowercase() && first_char.is_ascii_lowercase()
{ {
let mut err = if !data.inputs.is_empty() { 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, span: data.inputs_span,
}) })
} else if let FnRetTy::Ty(ty) = &data.output { } 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), span: data.inputs_span.shrink_to_hi().to(ty.span),
}) })
} else { } else {
@ -1048,7 +1041,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
{ {
add_feature_diagnostics( add_feature_diagnostics(
&mut err, &mut err,
&self.tcx.sess.parse_sess, &self.tcx.sess,
sym::return_type_notation, sym::return_type_notation,
); );
} }
@ -1161,7 +1154,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::TypeBindingKind::Constraint { bounds } hir::TypeBindingKind::Constraint { bounds }
} }
DesugarKind::Error(position) => { DesugarKind::Error(position) => {
let guar = self.tcx.sess.emit_err(errors::MisplacedAssocTyBinding { let guar = self.dcx().emit_err(errors::MisplacedAssocTyBinding {
span: constraint.span, span: constraint.span,
position: DiagnosticArgFromDisplay(position), 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()); data.inputs.last().unwrap().span.shrink_to_hi().to(data.inputs_span.shrink_to_hi());
AssocTyParenthesesSub::NotEmpty { open_param, close_param } 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))] #[instrument(level = "debug", skip(self))]
@ -1318,7 +1311,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: t.span, span: t.span,
}, },
itctx, itctx,
ast::Const::No, ast::BoundConstness::Never,
); );
let bounds = this.arena.alloc_from_iter([bound]); let bounds = this.arena.alloc_from_iter([bound]);
let lifetime_bound = this.elided_dyn_bound(t.span); let lifetime_bound = this.elided_dyn_bound(t.span);
@ -1345,20 +1338,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let kind = match &t.kind { let kind = match &t.kind {
TyKind::Infer => hir::TyKind::Infer, TyKind::Infer => hir::TyKind::Infer,
TyKind::Err => { 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 // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
#[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::diagnostic_outside_of_impl)]
TyKind::AnonStruct(ref _fields) => hir::TyKind::Err( TyKind::AnonStruct(ref _fields) => {
self.tcx.sess.span_err(t.span, "anonymous structs are unimplemented"), hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous structs are unimplemented"))
), }
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
#[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::diagnostic_outside_of_impl)]
TyKind::AnonUnion(ref _fields) => hir::TyKind::Err( TyKind::AnonUnion(ref _fields) => {
self.tcx.sess.span_err(t.span, "anonymous unions are unimplemented"), 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::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
TyKind::Ref(region, mt) => { 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, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
let bounds = let bounds =
this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound { this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound {
GenericBound::Trait( // We can safely ignore constness here since AST validation
ty, // takes care of rejecting invalid modifier combinations and
modifier @ (TraitBoundModifier::None // const trait bounds in trait object types.
| TraitBoundModifier::MaybeConst(_) GenericBound::Trait(ty, modifiers) => match modifiers.polarity {
| TraitBoundModifier::Negative), BoundPolarity::Positive | BoundPolarity::Negative(_) => {
) => { Some(this.lower_poly_trait_ref(
Some(this.lower_poly_trait_ref(ty, itctx, modifier.to_constness())) ty,
} itctx,
// `~const ?Bound` will cause an error during AST validation // Still, don't pass along the constness here; we don't want to
// anyways, so treat it like `?Bound` as compilation proceeds. // synthesize any host effect args, it'd only cause problems.
GenericBound::Trait( ast::BoundConstness::Never,
_, ))
TraitBoundModifier::Maybe }
| TraitBoundModifier::MaybeConstMaybe BoundPolarity::Maybe(_) => None,
| TraitBoundModifier::MaybeConstNegative, },
) => None,
GenericBound::Outlives(lifetime) => { GenericBound::Outlives(lifetime) => {
if lifetime_bound.is_none() { if lifetime_bound.is_none() {
lifetime_bound = Some(this.lower_lifetime(lifetime)); lifetime_bound = Some(this.lower_lifetime(lifetime));
@ -1519,7 +1511,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::TyKind::Err(guar) hir::TyKind::Err(guar)
} }
ImplTraitContext::Disallowed(position) => { ImplTraitContext::Disallowed(position) => {
let guar = self.tcx.sess.emit_err(MisplacedImplTrait { let guar = self.dcx().emit_err(MisplacedImplTrait {
span: t.span, span: t.span,
position: DiagnosticArgFromDisplay(position), 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::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"),
TyKind::CVarArgs => { TyKind::CVarArgs => {
let guar = self.tcx.sess.span_delayed_bug( let guar = self.dcx().span_delayed_bug(
t.span, t.span,
"`TyKind::CVarArgs` should have been handled elsewhere", "`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) { if let Some(old_def_id) = self.orig_opt_local_def_id(param) {
old_def_id old_def_id
} else { } else {
self.tcx self.dcx()
.sess
.span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime"); .span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime");
continue; continue;
} }
@ -1833,19 +1824,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
inputs = &inputs[..inputs.len() - 1]; inputs = &inputs[..inputs.len() - 1];
} }
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| { let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
let itctx = if kind.param_impl_trait_allowed() { let itctx = match kind {
ImplTraitContext::Universal FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => {
} else { ImplTraitContext::Universal
ImplTraitContext::Disallowed(match kind { }
FnDeclKind::Fn | FnDeclKind::Inherent => { FnDeclKind::ExternFn => {
unreachable!("fn should allow APIT") ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnParam)
} }
FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam, FnDeclKind::Closure => {
FnDeclKind::Closure => ImplTraitPosition::ClosureParam, ImplTraitContext::Disallowed(ImplTraitPosition::ClosureParam)
FnDeclKind::Pointer => ImplTraitPosition::PointerParam, }
FnDeclKind::Trait => ImplTraitPosition::TraitParam, FnDeclKind::Pointer => {
FnDeclKind::Impl => ImplTraitPosition::ImplParam, ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam)
}) }
}; };
self.lower_ty_direct(&param.ty, &itctx) self.lower_ty_direct(&param.ty, &itctx)
})); }));
@ -1857,26 +1848,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
None => match &decl.output { None => match &decl.output {
FnRetTy::Ty(ty) => { FnRetTy::Ty(ty) => {
let context = if kind.return_impl_trait_allowed() { let itctx = match kind {
let fn_def_id = self.local_def_id(fn_node_id); FnDeclKind::Fn
ImplTraitContext::ReturnPositionOpaqueTy { | FnDeclKind::Inherent
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), | FnDeclKind::Trait
| FnDeclKind::Impl => ImplTraitContext::ReturnPositionOpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(self.local_def_id(fn_node_id)),
fn_kind: kind, 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)), FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)),
}, },
@ -2028,9 +2018,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
itctx: &ImplTraitContext, itctx: &ImplTraitContext,
) -> hir::GenericBound<'hir> { ) -> hir::GenericBound<'hir> {
match tpb { match tpb {
GenericBound::Trait(p, modifier) => hir::GenericBound::Trait( GenericBound::Trait(p, modifiers) => hir::GenericBound::Trait(
self.lower_poly_trait_ref(p, itctx, modifier.to_constness()), self.lower_poly_trait_ref(p, itctx, modifiers.constness.into()),
self.lower_trait_bound_modifier(*modifier), self.lower_trait_bound_modifiers(*modifiers),
), ),
GenericBound::Outlives(lifetime) => { GenericBound::Outlives(lifetime) => {
hir::GenericBound::Outlives(self.lower_lifetime(lifetime)) hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
@ -2109,7 +2099,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param: &GenericParam, param: &GenericParam,
source: hir::GenericParamSource, source: hir::GenericParamSource,
) -> hir::GenericParam<'hir> { ) -> 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); let hir_id = self.lower_node_id(param.id);
self.lower_attrs(hir_id, &param.attrs); self.lower_attrs(hir_id, &param.attrs);
@ -2128,6 +2118,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_generic_param_kind( fn lower_generic_param_kind(
&mut self, &mut self,
param: &GenericParam, param: &GenericParam,
source: hir::GenericParamSource,
) -> (hir::ParamName, hir::GenericParamKind<'hir>) { ) -> (hir::ParamName, hir::GenericParamKind<'hir>) {
match &param.kind { match &param.kind {
GenericParamKind::Lifetime => { GenericParamKind::Lifetime => {
@ -2146,22 +2137,51 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
(param_name, kind) (param_name, kind)
} }
GenericParamKind::Type { default, .. } => { GenericParamKind::Type { default, .. } => {
let kind = hir::GenericParamKind::Type { // Not only do we deny type param defaults in binders but we also map them to `None`
default: default.as_ref().map(|x| { // 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( self.lower_ty(
x, def,
&ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), &ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
) )
}), });
synthetic: false,
}; let kind = hir::GenericParamKind::Type { default, synthetic: false };
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind) (hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
} }
GenericParamKind::Const { ty, kw_span: _, default } => { GenericParamKind::Const { ty, kw_span: _, default } => {
let ty = self let ty = self
.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault)); .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::ParamName::Plain(self.lower_ident(param.ident)),
hir::GenericParamKind::Const { ty, default, is_host_effect: false }, hir::GenericParamKind::Const { ty, default, is_host_effect: false },
@ -2172,7 +2192,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_trait_ref( fn lower_trait_ref(
&mut self, &mut self,
constness: ast::Const, constness: ast::BoundConstness,
p: &TraitRef, p: &TraitRef,
itctx: &ImplTraitContext, itctx: &ImplTraitContext,
) -> hir::TraitRef<'hir> { ) -> hir::TraitRef<'hir> {
@ -2195,7 +2215,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self, &mut self,
p: &PolyTraitRef, p: &PolyTraitRef,
itctx: &ImplTraitContext, itctx: &ImplTraitContext,
constness: ast::Const, constness: ast::BoundConstness,
) -> hir::PolyTraitRef<'hir> { ) -> hir::PolyTraitRef<'hir> {
let bound_generic_params = let bound_generic_params =
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.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 { match c.value.kind {
ExprKind::Underscore => { ExprKind::Underscore => {
if self.tcx.features().generic_arg_infer { 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 { } else {
feature_err( feature_err(
&self.tcx.sess.parse_sess, &self.tcx.sess,
sym::generic_arg_infer, sym::generic_arg_infer,
c.value.span, c.value.span,
"using `_` for array lengths is unstable", "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 { fn lower_trait_bound_modifiers(
match f { &mut self,
TraitBoundModifier::None => hir::TraitBoundModifier::None, modifiers: TraitBoundModifiers,
TraitBoundModifier::MaybeConst(_) => hir::TraitBoundModifier::MaybeConst, ) -> hir::TraitBoundModifier {
// Invalid modifier combinations will cause an error during AST validation.
TraitBoundModifier::Negative => { // 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 { if self.tcx.features().negative_bounds {
hir::TraitBoundModifier::Negative hir::TraitBoundModifier::Negative
} else { } else {
hir::TraitBoundModifier::None hir::TraitBoundModifier::None
} }
} }
(BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const,
// `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a (BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst,
// placeholder for compilation to proceed.
TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => {
hir::TraitBoundModifier::Maybe
}
TraitBoundModifier::MaybeConstNegative => hir::TraitBoundModifier::MaybeConst,
} }
} }
@ -2552,45 +2574,62 @@ struct GenericArgsCtor<'hir> {
} }
impl<'hir> 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 { if !lcx.tcx.features().effects {
return; return;
} }
// if bound is non-const, don't add host effect param let (span, body) = match constness {
let ast::Const::Yes(span) = constness else { return }; 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(); (span, body)
let hir_id = lcx.next_id(); }
BoundConstness::Maybe(span) => {
let span = lcx.lower_span(span);
let Some(host_param_id) = lcx.host_param_id else { let Some(host_param_id) = lcx.host_param_id else {
lcx.tcx.sess.span_delayed_bug( lcx.dcx().span_delayed_bug(
span, span,
"no host param id for call in const yet no errors reported", "no host param id for call in const yet no errors reported",
); );
return; return;
}; };
let body = lcx.lower_body(|lcx| {
(&[], {
let hir_id = lcx.next_id(); let hir_id = lcx.next_id();
let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_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, None,
lcx.arena.alloc(hir::Path { lcx.arena.alloc(hir::Path {
span, span,
res, res,
segments: arena_vec![lcx; hir::PathSegment::new(Ident { segments: arena_vec![
name: sym::host, lcx;
span, hir::PathSegment::new(
}, hir_id, res)], 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( let def_id = lcx.create_def(
lcx.current_hir_id_owner.def_id, 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), 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) => { PatKind::Tuple(pats) => {
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple"); 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 // return inner to be processed in next loop
PatKind::Paren(inner) => pattern = inner, PatKind::Paren(inner) => pattern = inner,
PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span), 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 // This is not allowed as a sub-tuple pattern
PatKind::Ident(_, ident, Some(sub)) if sub.is_rest() => { PatKind::Ident(_, ident, Some(sub)) if sub.is_rest() => {
let sp = pat.span; let sp = pat.span;
self.tcx.sess.emit_err(SubTupleBinding { self.dcx().emit_err(SubTupleBinding {
span: sp, span: sp,
ident_name: ident.name, ident_name: ident.name,
ident: *ident, 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. /// 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) { 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. /// Used to ban the `..` pattern in places it shouldn't be semantically.
fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> { 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 // We're not in a list context so `..` can be reasonably treated
// as `_` because it should always be valid and roughly matches the // 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::Path(..) if allow_paths => {}
ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} 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)); 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, param_mode: ParamMode,
itctx: &ImplTraitContext, itctx: &ImplTraitContext,
// constness of the impl/bound if this is a trait path // constness of the impl/bound if this is a trait path
constness: Option<ast::Const>, constness: Option<ast::BoundConstness>,
) -> hir::QPath<'hir> { ) -> hir::QPath<'hir> {
let qself_position = qself.as_ref().map(|q| q.position); let qself_position = qself.as_ref().map(|q| q.position);
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx)); 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. // We should've returned in the for loop above.
self.tcx.sess.dcx().span_bug( self.dcx().span_bug(
p.span, p.span,
format!( format!(
"lower_qpath: no final extension segment in {}..{}", "lower_qpath: no final extension segment in {}..{}",
@ -179,7 +179,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_mode: ParamMode, param_mode: ParamMode,
parenthesized_generic_args: ParenthesizedGenericArgs, parenthesized_generic_args: ParenthesizedGenericArgs,
itctx: &ImplTraitContext, itctx: &ImplTraitContext,
constness: Option<ast::Const>, constness: Option<ast::BoundConstness>,
) -> hir::PathSegment<'hir> { ) -> hir::PathSegment<'hir> {
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment); 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() { 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 { } else {
None 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( self.lower_angle_bracketed_parameter_data(
&data.as_angle_bracketed_args(), &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 .const = `const` because of this
.variadic = C-variadic 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 = ast_passes_const_without_body =
free constant item without body free constant item without body
.suggestion = provide a definition for the constant .suggestion = provide a definition for the constant
@ -117,13 +119,13 @@ ast_passes_fn_without_body =
free function without a body free function without a body
.suggestion = provide a definition for the function .suggestion = provide a definition for the function
ast_passes_forbidden_bound =
bounds cannot be used in this context
ast_passes_forbidden_default = ast_passes_forbidden_default =
`default` is only allowed on items in trait impls `default` is only allowed on items in trait impls
.label = `default` because of this .label = `default` because of this
ast_passes_forbidden_lifetime_bound =
lifetime bounds cannot be used in this context
ast_passes_forbidden_non_lifetime_param = ast_passes_forbidden_non_lifetime_param =
only lifetime parameters can be used in this context 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 ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
.help = remove one of these features .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} ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
.because = {$annotation} because of this .because = {$annotation} because of this
.type = inherent impl for this type .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 = ast_passes_negative_bound_not_supported =
negative bounds are 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 ast_passes_nested_impl_trait = nested `impl Trait` is not allowed
.outer = outer `impl Trait` .outer = outer `impl Trait`
.inner = nested `impl Trait` here .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 ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
.help = use `auto trait Trait {"{}"}` instead .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_object = `?Trait` is not permitted in trait object types
ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits 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 = 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 .trait_impl = this impl is not `const`, so it cannot have `~const` trait bounds
.impl = inherent impls 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 .object = trait objects cannot have `~const` trait bounds
.item = this item cannot have `~const` trait bounds .item = this item cannot have `~const` trait bounds
ast_passes_trait_fn_const = ast_passes_trait_fn_const =
functions in traits cannot be declared const functions in {$in_impl ->
.label = functions in traits cannot be const [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 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`? /// 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> { enum DisallowTildeConstContext<'a> {
TraitObject, TraitObject,
Fn(FnKind<'a>), Fn(FnKind<'a>),
Trait(Span), Trait(Span),
TraitImpl(Span), TraitImpl(Span),
Impl(Span), Impl(Span),
TraitAssocTy(Span),
TraitImplAssocTy(Span),
InherentAssocTy(Span),
Item, 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> { struct AstValidator<'a> {
session: &'a Session, session: &'a Session,
features: &'a Features, features: &'a Features,
@ -53,11 +73,7 @@ struct AstValidator<'a> {
/// The span of the `extern` in an `extern { ... }` block, if any. /// The span of the `extern` in an `extern { ... }` block, if any.
extern_mod: Option<&'a Item>, extern_mod: Option<&'a Item>,
/// Are we inside a trait impl? outer_trait_or_trait_impl: Option<TraitOrTraitImpl<'a>>,
in_trait_impl: bool,
/// Are we inside a const trait defn or impl?
in_const_trait_or_impl: bool,
has_proc_macro_decls: bool, has_proc_macro_decls: bool,
@ -78,24 +94,28 @@ struct AstValidator<'a> {
impl<'a> AstValidator<'a> { impl<'a> AstValidator<'a> {
fn with_in_trait_impl( fn with_in_trait_impl(
&mut self, &mut self,
is_in: bool, trait_: Option<(Const, ImplPolarity, &'a TraitRef)>,
constness: Option<Const>,
f: impl FnOnce(&mut Self), f: impl FnOnce(&mut Self),
) { ) {
let old = mem::replace(&mut self.in_trait_impl, is_in); let old = mem::replace(
let old_const = mem::replace( &mut self.outer_trait_or_trait_impl,
&mut self.in_const_trait_or_impl, trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl {
matches!(constness, Some(Const::Yes(_))), constness,
polarity,
trait_ref,
}),
); );
f(self); f(self);
self.in_trait_impl = old; self.outer_trait_or_trait_impl = old;
self.in_const_trait_or_impl = old_const;
} }
fn with_in_trait(&mut self, is_const: bool, f: impl FnOnce(&mut Self)) { fn with_in_trait(&mut self, span: Span, constness: Option<Span>, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.in_const_trait_or_impl, is_const); let old = mem::replace(
&mut self.outer_trait_or_trait_impl,
Some(TraitOrTraitImpl::Trait { span, constness }),
);
f(self); 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)) { 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) { fn check_lifetime(&self, ident: Ident) {
let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty]; let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { 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) { fn check_label(&self, ident: Ident) {
if ident.without_first_quote().is_reserved() { 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; 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)) { 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) { fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl<'a>) {
if let Const::Yes(span) = constness { let Const::Yes(span) = constness else {
self.session.emit_err(errors::TraitFnConst { span }); 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) { 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(); let max_num_args: usize = u16::MAX.into();
if fn_decl.inputs.len() > max_num_args { if fn_decl.inputs.len() > max_num_args {
let Param { span, .. } = fn_decl.inputs[0]; 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 { match &*fn_decl.inputs {
[Param { ty, span, .. }] => { [Param { ty, span, .. }] => {
if let TyKind::CVarArgs = ty.kind { if let TyKind::CVarArgs = ty.kind {
self.session.emit_err(errors::FnParamCVarArgsOnly { span: *span }); self.dcx().emit_err(errors::FnParamCVarArgsOnly { span: *span });
} }
} }
[ps @ .., _] => { [ps @ .., _] => {
for Param { ty, span, .. } in ps { for Param { ty, span, .. } in ps {
if let TyKind::CVarArgs = ty.kind { 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| { .for_each(|attr| {
if attr.is_doc_comment() { if attr.is_doc_comment() {
self.session.emit_err(errors::FnParamDocComment { span: attr.span }); self.dcx().emit_err(errors::FnParamDocComment { span: attr.span });
} else { } 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) { fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) { if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
if param.is_self() { 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) { fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
if let Defaultness::Default(def_span) = defaultness { if let Defaultness::Default(def_span) = defaultness {
let span = self.session.source_map().guess_head_span(span); 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; return;
} }
let span = self.session.source_map().guess_head_span(item_span); 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) { fn check_mod_file_item_asciionly(&self, ident: Ident) {
if ident.name.as_str().is_ascii() { if ident.name.as_str().is_ascii() {
return; 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) { fn deny_generic_params(&self, generics: &Generics, ident: Span) {
if !generics.params.is_empty() { 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) { 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) { fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
@ -569,7 +628,7 @@ impl<'a> AstValidator<'a> {
if !trait_items.is_empty() { if !trait_items.is_empty() {
let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect(); 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); 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) => { TyKind::BareFn(bfty) => {
self.check_fn_decl(&bfty.decl, SelfSemantic::No); self.check_fn_decl(&bfty.decl, SelfSemantic::No);
Self::check_decl_no_pat(&bfty.decl, |span, _, _| { 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 { if let Extern::Implicit(_) = bfty.ext {
let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo()); 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 { for bound in bounds {
if let GenericBound::Outlives(lifetime) = bound { if let GenericBound::Outlives(lifetime) = bound {
if any_lifetime_bounds { if any_lifetime_bounds {
self.session self.dcx()
.emit_err(errors::TraitObjectBound { span: lifetime.ident.span }); .emit_err(errors::TraitObjectBound { span: lifetime.ident.span });
break; break;
} }
@ -655,11 +714,11 @@ impl<'a> AstValidator<'a> {
} }
TyKind::ImplTrait(_, bounds) => { TyKind::ImplTrait(_, bounds) => {
if self.is_impl_trait_banned { 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 { 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, span: ty.span,
outer: outer_impl_trait_sp, outer: outer_impl_trait_sp,
inner: ty.span, inner: ty.span,
@ -817,7 +876,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self_ty, self_ty,
items, items,
}) => { }) => {
self.with_in_trait_impl(true, Some(*constness), |this| { self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| {
this.visibility_not_permitted( this.visibility_not_permitted(
&item.vis, &item.vis,
errors::VisibilityNotPermittedNote::TraitImpl, errors::VisibilityNotPermittedNote::TraitImpl,
@ -827,7 +886,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
} }
if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity) 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), span: sp.to(t.path.span),
negative: sp, negative: sp,
r#unsafe: span, r#unsafe: span,
@ -866,35 +925,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
only_trait: only_trait.then_some(()), only_trait: only_trait.then_some(()),
}; };
self.visibility_not_permitted( self.with_in_trait_impl(None, |this| {
&item.vis, this.visibility_not_permitted(
errors::VisibilityNotPermittedNote::IndividualImplItems, &item.vis,
); errors::VisibilityNotPermittedNote::IndividualImplItems,
if let &Unsafe::Yes(span) = unsafety { );
self.dcx().emit_err(errors::InherentImplCannotUnsafe { if let &Unsafe::Yes(span) = unsafety {
span: self_ty.span, this.dcx().emit_err(errors::InherentImplCannotUnsafe {
annotation_span: span, span: self_ty.span,
annotation: "unsafe", annotation_span: span,
self_ty: self_ty.span, annotation: "unsafe",
}); self_ty: self_ty.span,
} });
if let &ImplPolarity::Negative(span) = polarity { }
self.dcx().emit_err(error(span, "negative", false)); if let &ImplPolarity::Negative(span) = polarity {
} this.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 &Defaultness::Default(def_span) = defaultness {
} this.dcx().emit_err(error(def_span, "`default`", true));
if let &Const::Yes(span) = constness { }
self.dcx().emit_err(error(span, "`const`", true)); if let &Const::Yes(span) = constness {
} this.dcx().emit_err(error(span, "`const`", true));
}
self.visit_vis(&item.vis); this.visit_vis(&item.vis);
self.visit_ident(item.ident); this.visit_ident(item.ident);
self.with_tilde_const(Some(DisallowTildeConstContext::Impl(item.span)), |this| { this.with_tilde_const(
this.visit_generics(generics) 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); walk_list!(self, visit_attribute, &item.attrs);
return; // Avoid visiting again. return; // Avoid visiting again.
} }
@ -902,7 +964,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_defaultness(item.span, *defaultness); self.check_defaultness(item.span, *defaultness);
if body.is_none() { if body.is_none() {
self.session.emit_err(errors::FnWithoutBody { self.dcx().emit_err(errors::FnWithoutBody {
span: item.span, span: item.span,
replace_span: self.ending_semi_or_hi(item.span), replace_span: self.ending_semi_or_hi(item.span),
extern_block_suggestion: match sig.header.ext { 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, .. }) => { ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => {
let is_const_trait = attr::contains_name(&item.attrs, sym::const_trait); let is_const_trait =
self.with_in_trait(is_const_trait, |this| { 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 { if *is_auto == IsAuto::Yes {
// Auto traits cannot have generics, super traits nor contain items. // Auto traits cannot have generics, super traits nor contain items.
this.deny_generic_params(generics, item.ident.span); this.deny_generic_params(generics, item.ident.span);
@ -977,8 +1040,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
// context for the supertraits. // context for the supertraits.
this.visit_vis(&item.vis); this.visit_vis(&item.vis);
this.visit_ident(item.ident); this.visit_ident(item.ident);
let disallowed = let disallowed = is_const_trait
(!is_const_trait).then(|| DisallowTildeConstContext::Trait(item.span)); .is_none()
.then(|| DisallowTildeConstContext::Trait(item.span));
this.with_tilde_const(disallowed, |this| { this.with_tilde_const(disallowed, |this| {
this.visit_generics(generics); this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) 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, .. }) => { ItemKind::Const(box ConstItem { defaultness, expr, .. }) => {
self.check_defaultness(item.span, *defaultness); self.check_defaultness(item.span, *defaultness);
if expr.is_none() { if expr.is_none() {
self.session.emit_err(errors::ConstWithoutBody { self.dcx().emit_err(errors::ConstWithoutBody {
span: item.span, span: item.span,
replace_span: self.ending_semi_or_hi(item.span), replace_span: self.ending_semi_or_hi(item.span),
}); });
} }
} }
ItemKind::Static(box StaticItem { expr: None, .. }) => { ItemKind::Static(box StaticItem { expr: None, .. }) => {
self.session.emit_err(errors::StaticWithoutBody { self.dcx().emit_err(errors::StaticWithoutBody {
span: item.span, span: item.span,
replace_span: self.ending_semi_or_hi(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); self.check_defaultness(item.span, *defaultness);
if ty.is_none() { if ty.is_none() {
self.session.emit_err(errors::TyAliasWithoutBody { self.dcx().emit_err(errors::TyAliasWithoutBody {
span: item.span, span: item.span,
replace_span: self.ending_semi_or_hi(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) { fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
if let GenericBound::Trait(poly, modify) = bound { if let GenericBound::Trait(poly, modifiers) = bound {
match (ctxt, modify) { match (ctxt, modifiers.constness, modifiers.polarity) {
(BoundKind::SuperTraits, TraitBoundModifier::Maybe) => { (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
self.dcx().emit_err(errors::OptionalTraitSupertrait { self.dcx().emit_err(errors::OptionalTraitSupertrait {
span: poly.span, span: poly.span,
path_str: pprust::path_to_string(&poly.trait_ref.path), 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 }); 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 => if let Some(reason) = &self.disallow_tilde_const =>
{ {
let reason = match reason { 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. // suggestion for moving such bounds to the assoc const fns if available.
errors::TildeConstReason::Impl { span } 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 => { DisallowTildeConstContext::TraitObject => {
errors::TildeConstReason::TraitObject errors::TildeConstReason::TraitObject
} }
@ -1235,16 +1311,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}; };
self.dcx().emit_err(errors::TildeConstDisallowed { span, reason }); 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(), span: bound.span(),
modifier: "?", left: modifiers.constness.as_str(),
}); right: modifiers.polarity.as_str(),
}
(_, TraitBoundModifier::MaybeConstNegative) => {
self.dcx().emit_err(errors::OptionalConstExclusive {
span: bound.span(),
modifier: "!",
}); });
} }
_ => {} _ => {}
@ -1252,15 +1327,27 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
} }
// Negative trait bounds are not allowed to have associated constraints // 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(segment) = trait_ref.trait_ref.path.segments.last()
&& let Some(ast::GenericArgs::AngleBracketed(args)) = segment.args.as_deref()
{ {
for arg in &args.args { match segment.args.as_deref() {
if let ast::AngleBracketedArg::Constraint(constraint) = arg { Some(ast::GenericArgs::AngleBracketed(args)) => {
self.dcx() for arg in &args.args {
.emit_err(errors::ConstraintOnNegativeBound { span: constraint.span }); 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 = let tilde_const_allowed =
matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. })) 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)); let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
self.with_tilde_const(disallowed, |this| visit::walk_fn(this, 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); 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()); self.check_defaultness(item.span, item.kind.defaultness());
} }
if ctxt == AssocCtxt::Impl { if ctxt == AssocCtxt::Impl {
match &item.kind { match &item.kind {
AssocItemKind::Const(box ConstItem { expr: None, .. }) => { AssocItemKind::Const(box ConstItem { expr: None, .. }) => {
self.session.emit_err(errors::AssocConstWithoutBody { self.dcx().emit_err(errors::AssocConstWithoutBody {
span: item.span, span: item.span,
replace_span: self.ending_semi_or_hi(item.span), replace_span: self.ending_semi_or_hi(item.span),
}); });
} }
AssocItemKind::Fn(box Fn { body, .. }) => { AssocItemKind::Fn(box Fn { body, .. }) => {
if body.is_none() { if body.is_none() {
self.session.emit_err(errors::AssocFnWithoutBody { self.dcx().emit_err(errors::AssocFnWithoutBody {
span: item.span, span: item.span,
replace_span: self.ending_semi_or_hi(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, .. }) => { AssocItemKind::Type(box TyAlias { bounds, ty, .. }) => {
if ty.is_none() { if ty.is_none() {
self.session.emit_err(errors::AssocTypeWithoutBody { self.dcx().emit_err(errors::AssocTypeWithoutBody {
span: item.span, span: item.span,
replace_span: self.ending_semi_or_hi(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); self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { 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"); 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 { match &item.kind {
AssocItemKind::Fn(box Fn { sig, generics, body, .. }) AssocItemKind::Fn(box Fn { sig, generics, body, .. })
if self.in_const_trait_or_impl if parent_is_const
|| ctxt == AssocCtxt::Trait || ctxt == AssocCtxt::Trait
|| matches!(sig.header.constness, Const::Yes(_)) => || 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.visit_fn(kind, item.span, item.id);
} }
_ => self AssocItemKind::Type(_) => {
.with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)), 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 { for param in &generics.params {
if param.ident == potential_param.ident { if param.ident == potential_param.ident {
for bound in &param.bounds { 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[..] { if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
let assoc = pprust::path_to_string(&ast::Path::from_ident( let assoc = pprust::path_to_string(&ast::Path::from_ident(
@ -1543,8 +1652,7 @@ pub fn check_crate(
session, session,
features, features,
extern_mod: None, extern_mod: None,
in_trait_impl: false, outer_trait_or_trait_impl: None,
in_const_trait_or_impl: false,
has_proc_macro_decls: false, has_proc_macro_decls: false,
outer_impl_trait: None, outer_impl_trait: None,
disallow_tilde_const: Some(DisallowTildeConstContext::Item), disallow_tilde_const: Some(DisallowTildeConstContext::Item),

View File

@ -1,7 +1,7 @@
//! Errors emitted by ast_passes. //! Errors emitted by ast_passes.
use rustc_ast::ParamKindOrd; use rustc_ast::ParamKindOrd;
use rustc_errors::AddToDiagnostic; use rustc_errors::{codes::*, AddToDiagnostic, Applicability};
use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{symbol::Ident, Span, Symbol}; use rustc_span::{symbol::Ident, Span, Symbol};
@ -23,7 +23,7 @@ pub struct InvalidLabel {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_visibility_not_permitted, code = "E0449")] #[diag(ast_passes_visibility_not_permitted, code = E0449)]
pub struct VisibilityNotPermitted { pub struct VisibilityNotPermitted {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -44,16 +44,34 @@ pub enum VisibilityNotPermittedNote {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_trait_fn_const, code = "E0379")] #[diag(ast_passes_trait_fn_const, code = E0379)]
pub struct TraitFnConst { pub struct TraitFnConst {
#[primary_span] #[primary_span]
#[label] #[label]
pub span: Span, 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)] #[derive(Diagnostic)]
#[diag(ast_passes_forbidden_lifetime_bound)] #[diag(ast_passes_forbidden_bound)]
pub struct ForbiddenLifetimeBound { pub struct ForbiddenBound {
#[primary_span] #[primary_span]
pub spans: Vec<Span>, pub spans: Vec<Span>,
} }
@ -284,14 +302,14 @@ pub struct ItemUnderscore<'a> {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_nomangle_ascii, code = "E0754")] #[diag(ast_passes_nomangle_ascii, code = E0754)]
pub struct NoMangleAscii { pub struct NoMangleAscii {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_module_nonascii, code = "E0754")] #[diag(ast_passes_module_nonascii, code = E0754)]
#[help] #[help]
pub struct ModuleNonAscii { pub struct ModuleNonAscii {
#[primary_span] #[primary_span]
@ -300,7 +318,7 @@ pub struct ModuleNonAscii {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_auto_generic, code = "E0567")] #[diag(ast_passes_auto_generic, code = E0567)]
pub struct AutoTraitGeneric { pub struct AutoTraitGeneric {
#[primary_span] #[primary_span]
#[suggestion(code = "", applicability = "machine-applicable")] #[suggestion(code = "", applicability = "machine-applicable")]
@ -310,7 +328,7 @@ pub struct AutoTraitGeneric {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_auto_super_lifetime, code = "E0568")] #[diag(ast_passes_auto_super_lifetime, code = E0568)]
pub struct AutoTraitBounds { pub struct AutoTraitBounds {
#[primary_span] #[primary_span]
#[suggestion(code = "", applicability = "machine-applicable")] #[suggestion(code = "", applicability = "machine-applicable")]
@ -320,7 +338,7 @@ pub struct AutoTraitBounds {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_auto_items, code = "E0380")] #[diag(ast_passes_auto_items, code = E0380)]
pub struct AutoTraitItems { pub struct AutoTraitItems {
#[primary_span] #[primary_span]
pub spans: Vec<Span>, pub spans: Vec<Span>,
@ -366,28 +384,28 @@ impl AddToDiagnostic for EmptyLabelManySpans {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_pattern_in_fn_pointer, code = "E0561")] #[diag(ast_passes_pattern_in_fn_pointer, code = E0561)]
pub struct PatternFnPointer { pub struct PatternFnPointer {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_trait_object_single_bound, code = "E0226")] #[diag(ast_passes_trait_object_single_bound, code = E0226)]
pub struct TraitObjectBound { pub struct TraitObjectBound {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_impl_trait_path, code = "E0667")] #[diag(ast_passes_impl_trait_path, code = E0667)]
pub struct ImplTraitPath { pub struct ImplTraitPath {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_nested_impl_trait, code = "E0666")] #[diag(ast_passes_nested_impl_trait, code = E0666)]
pub struct NestedImplTrait { pub struct NestedImplTrait {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -425,7 +443,7 @@ pub struct ObsoleteAuto {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_unsafe_negative_impl, code = "E0198")] #[diag(ast_passes_unsafe_negative_impl, code = E0198)]
pub struct UnsafeNegativeImpl { pub struct UnsafeNegativeImpl {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -450,7 +468,7 @@ pub struct InherentImplCannot<'a> {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_inherent_cannot_be, code = "E0197")] #[diag(ast_passes_inherent_cannot_be, code = E0197)]
pub struct InherentImplCannotUnsafe<'a> { pub struct InherentImplCannotUnsafe<'a> {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -518,7 +536,7 @@ pub struct GenericDefaultTrailing {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_nested_lifetimes, code = "E0316")] #[diag(ast_passes_nested_lifetimes, code = E0316)]
pub struct NestedLifetimes { pub struct NestedLifetimes {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -540,6 +558,15 @@ pub struct OptionalTraitObject {
pub span: Span, 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)] #[derive(Diagnostic)]
#[diag(ast_passes_tilde_const_disallowed)] #[diag(ast_passes_tilde_const_disallowed)]
pub struct TildeConstDisallowed { pub struct TildeConstDisallowed {
@ -573,6 +600,21 @@ pub enum TildeConstReason {
#[primary_span] #[primary_span]
span: 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)] #[note(ast_passes_object)]
TraitObject, TraitObject,
#[note(ast_passes_item)] #[note(ast_passes_item)]
@ -580,11 +622,12 @@ pub enum TildeConstReason {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_optional_const_exclusive)] #[diag(ast_passes_incompatible_trait_bound_modifiers)]
pub struct OptionalConstExclusive { pub struct IncompatibleTraitBoundModifiers {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
pub modifier: &'static str, pub left: &'static str,
pub right: &'static str,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
@ -612,7 +655,7 @@ pub struct ConstAndCVariadic {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_pattern_in_foreign, code = "E0130")] #[diag(ast_passes_pattern_in_foreign, code = E0130)]
pub struct PatternInForeign { pub struct PatternInForeign {
#[primary_span] #[primary_span]
#[label] #[label]
@ -620,7 +663,7 @@ pub struct PatternInForeign {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_pattern_in_bodiless, code = "E0642")] #[diag(ast_passes_pattern_in_bodiless, code = E0642)]
pub struct PatternInBodiless { pub struct PatternInBodiless {
#[primary_span] #[primary_span]
#[label] #[label]
@ -668,14 +711,14 @@ pub struct AssociatedSuggestion2 {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_stability_outside_std, code = "E0734")] #[diag(ast_passes_stability_outside_std, code = E0734)]
pub struct StabilityOutsideStd { pub struct StabilityOutsideStd {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_feature_on_non_nightly, code = "E0554")] #[diag(ast_passes_feature_on_non_nightly, code = E0554)]
pub struct FeatureOnNonNightly { pub struct FeatureOnNonNightly {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -699,8 +742,8 @@ impl AddToDiagnostic for StableFeature {
rustc_errors::SubdiagnosticMessage, rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage, ) -> rustc_errors::SubdiagnosticMessage,
{ {
diag.set_arg("name", self.name); diag.arg("name", self.name);
diag.set_arg("since", self.since); diag.arg("since", self.since);
diag.help(fluent::ast_passes_stable_since); diag.help(fluent::ast_passes_stable_since);
} }
} }
@ -737,6 +780,13 @@ pub struct ConstraintOnNegativeBound {
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)]
#[diag(ast_passes_negative_bound_with_parenthetical_notation)]
pub struct NegativeBoundWithParentheticalNotation {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_invalid_unnamed_field_ty)] #[diag(ast_passes_invalid_unnamed_field_ty)]
pub struct InvalidUnnamedFieldTy { pub struct InvalidUnnamedFieldTy {

View File

@ -17,14 +17,12 @@ use crate::errors;
macro_rules! gate { macro_rules! gate {
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { 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) => {{ ($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
feature_err(&$visitor.sess.parse_sess, sym::$feature, $span, $explain) feature_err(&$visitor.sess, sym::$feature, $span, $explain).with_help($help).emit();
.help($help)
.emit();
} }
}}; }};
} }
@ -33,7 +31,7 @@ macro_rules! gate {
macro_rules! gate_alt { macro_rules! gate_alt {
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{ ($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{
if !$has_feature && !$span.allows_unstable($name) { 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<_> = let spans: Vec<_> =
$spans.filter(|span| !span.allows_unstable(sym::$feature)).collect(); $spans.filter(|span| !span.allows_unstable(sym::$feature)).collect();
if !spans.is_empty() { 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 { macro_rules! gate_legacy {
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { 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()) { match abi::is_enabled(self.features, span, symbol_unescaped.as_str()) {
Ok(()) => (), Ok(()) => (),
Err(abi::AbiDisabled::Unstable { feature, explain }) => { Err(abi::AbiDisabled::Unstable { feature, explain }) => {
feature_err_issue( feature_err_issue(&self.sess, feature, span, GateIssue::Language, explain).emit();
&self.sess.parse_sess,
feature,
span,
GateIssue::Language,
explain,
)
.emit();
} }
Err(abi::AbiDisabled::Unrecognized) => { Err(abi::AbiDisabled::Unrecognized) => {
if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) { 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]) { fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) {
// Check only lifetime parameters are present and that the lifetime // Check only lifetime parameters are present and that the
// parameters that are present have no bounds. // generic parameters that are present have no bounds.
let non_lt_param_spans = params.iter().filter_map(|param| match param.kind { let non_lt_param_spans = params.iter().filter_map(|param| match param.kind {
ast::GenericParamKind::Lifetime { .. } => None, ast::GenericParamKind::Lifetime { .. } => None,
_ => Some(param.ident.span), _ => Some(param.ident.span),
@ -164,10 +155,11 @@ impl<'a> PostExpansionVisitor<'a> {
non_lt_param_spans, non_lt_param_spans,
crate::fluent_generated::ast_passes_forbidden_non_lifetime_param crate::fluent_generated::ast_passes_forbidden_non_lifetime_param
); );
for param in params { for param in params {
if !param.bounds.is_empty() { if !param.bounds.is_empty() {
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); 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_const_stable)
|| attr.has_name(sym::rustc_default_body_unstable) || 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) { fn visit_expr(&mut self, e: &'a ast::Expr) {
match e.kind { match e.kind {
ast::ExprKind::TryBlock(_) => { ast::ExprKind::TryBlock(_) => {
@ -406,7 +411,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
&self, &self,
exclusive_range_pattern, exclusive_range_pattern,
pattern.span, 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!( gate_all!(
if_let_guard, if_let_guard,
"`if let` guards are experimental", "`if let` guards are experimental",
@ -527,6 +532,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
"async closures are unstable", "async closures are unstable",
"to use an async block, remove the `||`: `async {`" "to use an async block, remove the `||`: `async {`"
); );
gate_all!(async_for_loop, "`for await` loops are experimental");
gate_all!( gate_all!(
closure_lifetime_binder, closure_lifetime_binder,
"`for<...>` binders for closures are experimental", "`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!(explicit_tail_calls, "`become` expression is experimental");
gate_all!(generic_const_items, "generic const items are experimental"); gate_all!(generic_const_items, "generic const items are experimental");
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented"); 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 !visitor.features.never_patterns {
if let Some(spans) = spans.get(&sym::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) if let Ok(snippet) = sm.span_to_snippet(span)
&& snippet == "!" && snippet == "!"
{ {
feature_err( feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
&sess.parse_sess, .emit();
sym::never_patterns,
span,
"`!` patterns are experimental",
)
.emit();
} else { } else {
let suggestion = span.shrink_to_hi(); 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 { if !visitor.features.negative_bounds {
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { 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) if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2)
{ {
let spans = vec![f1_span, f2_span]; 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(if_let_guard)]
#![feature(iter_is_partitioned)] #![feature(iter_is_partitioned)]
#![feature(let_chains)] #![feature(let_chains)]
#![recursion_limit = "256"]
#![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)] #![deny(rustc::diagnostic_outside_of_impl)]

View File

@ -38,21 +38,21 @@ struct ShowSpanVisitor<'a> {
impl<'a> Visitor<'a> for ShowSpanVisitor<'a> { impl<'a> Visitor<'a> for ShowSpanVisitor<'a> {
fn visit_expr(&mut self, e: &'a ast::Expr) { fn visit_expr(&mut self, e: &'a ast::Expr) {
if let Mode::Expression = self.mode { 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); visit::walk_expr(self, e);
} }
fn visit_pat(&mut self, p: &'a ast::Pat) { fn visit_pat(&mut self, p: &'a ast::Pat) {
if let Mode::Pattern = self.mode { 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); visit::walk_pat(self, p);
} }
fn visit_ty(&mut self, t: &'a ast::Ty) { fn visit_ty(&mut self, t: &'a ast::Ty) {
if let Mode::Type = self.mode { 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); visit::walk_ty(self, t);
} }

View File

@ -4,7 +4,6 @@
#![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)] #![deny(rustc::diagnostic_outside_of_impl)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![recursion_limit = "256"]
mod helpers; mod helpers;
pub mod pp; 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::util::parser;
use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind}; use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind};
use rustc_ast::{attr, BindingAnnotation, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term}; 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::{InlineAsmOperand, InlineAsmRegOrRegClass};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
@ -160,6 +160,10 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
use TokenTree::Delimited as Del; use TokenTree::Delimited as Del;
use TokenTree::Token as Tok; 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 // 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 // insert space between adjacent tokens, except for the cases listed in
// this match. // this match.
@ -167,24 +171,35 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
// No space after line doc comments. // No space after line doc comments.
(Tok(Token { kind: DocComment(CommentKind::Line, ..), .. }, _), _) => false, (Tok(Token { kind: DocComment(CommentKind::Line, ..), .. }, _), _) => false,
// `.` + ANYTHING: `x.y`, `tup.0` // `.` + NON-PUNCT: `x.y`, `tup.0`
// `$` + ANYTHING: `$e` (Tok(Token { kind: Dot, .. }, _), tt2) if !is_punct(tt2) => false,
(Tok(Token { kind: Dot | Dollar, .. }, _), _) => false,
// ANYTHING + `,`: `foo,` // `$` + IDENT: `$e`
// ANYTHING + `.`: `x.y`, `tup.0` (Tok(Token { kind: Dollar, .. }, _), Tok(Token { kind: Ident(..), .. }, _)) => false,
// ANYTHING + `!`: `foo! { ... }`
//
// FIXME: Incorrect cases:
// - Logical not: `x =! y`, `if! x { f(); }`
// - Never type: `Fn() ->!`
(_, Tok(Token { kind: Comma | Dot | Not, .. }, _)) => false,
// IDENT + `(`: `f(3)` // NON-PUNCT + `,`: `foo,`
// // NON-PUNCT + `;`: `x = 3;`, `[T; 3]`
// FIXME: Incorrect cases: // NON-PUNCT + `.`: `x.y`, `tup.0`
// - Let: `let(a, b) = (1, 2)` (tt1, Tok(Token { kind: Comma | Semi | Dot, .. }, _)) if !is_punct(tt1) => false,
(Tok(Token { kind: Ident(..), .. }, _), Del(_, _, Parenthesis, _)) => 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]` // `#` + `[`: `#[attr]`
(Tok(Token { kind: Pound, .. }, _), Del(_, _, Bracket, _)) => false, (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::Item(item) => self.print_item(item),
ast::StmtKind::Expr(expr) => { ast::StmtKind::Expr(expr) => {
self.space_if_not_bol(); 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) { if classify::expr_requires_semi_to_be_stmt(expr) {
self.word(";"); self.word(";");
} }
} }
ast::StmtKind::Semi(expr) => { ast::StmtKind::Semi(expr) => {
self.space_if_not_bol(); 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(";"); self.word(";");
} }
ast::StmtKind::Empty => { ast::StmtKind::Empty => {
@ -1155,7 +1178,11 @@ impl<'a> State<'a> {
ast::StmtKind::Expr(expr) if i == blk.stmts.len() - 1 => { ast::StmtKind::Expr(expr) if i == blk.stmts.len() - 1 => {
self.maybe_print_comment(st.span.lo()); self.maybe_print_comment(st.span.lo());
self.space_if_not_bol(); 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.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
} }
_ => self.print_stmt(st), _ => self.print_stmt(st),
@ -1427,7 +1454,7 @@ impl<'a> State<'a> {
} }
self.nbsp(); self.nbsp();
self.word("{"); self.word("{");
let empty = fields.is_empty() && !etc; let empty = fields.is_empty() && *etc == ast::PatFieldsRest::None;
if !empty { if !empty {
self.space(); self.space();
} }
@ -1445,7 +1472,7 @@ impl<'a> State<'a> {
}, },
|f| f.pat.span, |f| f.pat.span,
); );
if *etc { if *etc == ast::PatFieldsRest::Rest {
if !fields.is_empty() { if !fields.is_empty() {
self.word_space(","); self.word_space(",");
} }
@ -1507,6 +1534,11 @@ impl<'a> State<'a> {
self.pclose(); self.pclose();
} }
PatKind::MacCall(m) => self.print_mac(m), PatKind::MacCall(m) => self.print_mac(m),
PatKind::Err(_) => {
self.popen();
self.word("/*ERROR*/");
self.pclose();
}
} }
self.ann.post(self, AnnNode::Pat(pat)) self.ann.post(self, AnnNode::Pat(pat))
} }
@ -1559,26 +1591,20 @@ impl<'a> State<'a> {
match bound { match bound {
GenericBound::Trait(tref, modifier) => { GenericBound::Trait(tref, modifier) => {
match modifier { match modifier.constness {
TraitBoundModifier::None => {} ast::BoundConstness::Never => {}
TraitBoundModifier::Negative => { ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_) => {
self.word("!"); self.word_space(modifier.constness.as_str());
}
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.polarity {
ast::BoundPolarity::Positive => {}
ast::BoundPolarity::Negative(_) | ast::BoundPolarity::Maybe(_) => {
self.word(modifier.polarity.as_str());
}
}
self.print_poly_trait_ref(tref); self.print_poly_trait_ref(tref);
} }
GenericBound::Outlives(lt) => self.print_lifetime(*lt), GenericBound::Outlives(lt) => self.print_lifetime(*lt),

View File

@ -1,8 +1,10 @@
use crate::pp::Breaks::Inconsistent; use crate::pp::Breaks::Inconsistent;
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT}; use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
use ast::ForLoopKind;
use itertools::{Itertools, Position}; use itertools::{Itertools, Position};
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token; use rustc_ast::token;
use rustc_ast::util::classify;
use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast::util::literal::escape_byte_str_symbol;
use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast::util::parser::{self, AssocOp, Fixity};
use rustc_ast::{self as ast, BlockCheckMode}; use rustc_ast::{self as ast, BlockCheckMode};
@ -14,6 +16,61 @@ use std::fmt::Write;
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub(crate) struct FixupContext { 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, pub parenthesize_exterior_struct_lit: bool,
} }
@ -21,7 +78,11 @@ pub(crate) struct FixupContext {
/// in a targetted fashion where needed. /// in a targetted fashion where needed.
impl Default for FixupContext { impl Default for FixupContext {
fn default() -> Self { 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 /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
/// `if cond { ... }`. /// `if cond { ... }`.
fn print_expr_as_cond(&mut self, expr: &ast::Expr) { 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) self.print_expr_cond_paren(expr, Self::cond_needs_par(expr), fixup)
} }
@ -98,26 +160,25 @@ impl<'a> State<'a> {
&mut self, &mut self,
expr: &ast::Expr, expr: &ast::Expr,
needs_par: bool, needs_par: bool,
fixup: FixupContext, mut fixup: FixupContext,
) { ) {
if needs_par { if needs_par {
self.popen(); 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); self.print_expr(expr, fixup);
if needs_par { if needs_par {
@ -233,7 +294,32 @@ impl<'a> State<'a> {
_ => parser::PREC_POSTFIX, _ => 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) self.print_call_post(args)
} }
@ -244,7 +330,17 @@ impl<'a> State<'a> {
base_args: &[P<ast::Expr>], base_args: &[P<ast::Expr>],
fixup: FixupContext, 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.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX, fixup);
self.word("."); self.word(".");
self.print_ident(segment.ident); self.print_ident(segment.ident);
if let Some(args) = &segment.args { 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) => { (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
parser::PREC_FORCE_PAREN 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, _ => 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.space();
self.word_space(op.node.as_str()); 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) { fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) {
self.word(op.as_str()); 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( fn print_expr_addr_of(
@ -321,7 +431,11 @@ impl<'a> State<'a> {
self.print_mutability(mutability, true); 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) { pub(super) fn print_expr(&mut self, expr: &ast::Expr, fixup: FixupContext) {
@ -332,7 +446,7 @@ impl<'a> State<'a> {
&mut self, &mut self,
expr: &ast::Expr, expr: &ast::Expr,
is_inline: bool, is_inline: bool,
fixup: FixupContext, mut fixup: FixupContext,
) { ) {
self.maybe_print_comment(expr.span.lo()); self.maybe_print_comment(expr.span.lo());
@ -344,7 +458,27 @@ impl<'a> State<'a> {
} }
self.ibox(INDENT_UNIT); 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)); self.ann.pre(self, AnnNode::Expr(expr));
match &expr.kind { match &expr.kind {
ast::ExprKind::Array(exprs) => { ast::ExprKind::Array(exprs) => {
self.print_expr_vec(exprs); self.print_expr_vec(exprs);
@ -385,7 +519,16 @@ impl<'a> State<'a> {
} }
ast::ExprKind::Cast(expr, ty) => { ast::ExprKind::Cast(expr, ty) => {
let prec = AssocOp::As.precedence() as i8; 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.space();
self.word_space("as"); self.word_space("as");
self.print_type(ty); self.print_type(ty);
@ -418,20 +561,23 @@ impl<'a> State<'a> {
self.space(); self.space();
self.print_block_with_attrs(blk, attrs); self.print_block_with_attrs(blk, attrs);
} }
ast::ExprKind::ForLoop(pat, iter, blk, opt_label) => { ast::ExprKind::ForLoop { pat, iter, body, label, kind } => {
if let Some(label) = opt_label { if let Some(label) = label {
self.print_ident(label.ident); self.print_ident(label.ident);
self.word_space(":"); self.word_space(":");
} }
self.cbox(0); self.cbox(0);
self.ibox(0); self.ibox(0);
self.word_nbsp("for"); self.word_nbsp("for");
if kind == &ForLoopKind::ForAwait {
self.word_nbsp("await");
}
self.print_pat(pat); self.print_pat(pat);
self.space(); self.space();
self.word_space("in"); self.word_space("in");
self.print_expr_as_cond(iter); self.print_expr_as_cond(iter);
self.space(); self.space();
self.print_block_with_attrs(blk, attrs); self.print_block_with_attrs(body, attrs);
} }
ast::ExprKind::Loop(blk, opt_label, _) => { ast::ExprKind::Loop(blk, opt_label, _) => {
if let Some(label) = opt_label { if let Some(label) = opt_label {
@ -504,31 +650,71 @@ impl<'a> State<'a> {
self.print_block_with_attrs(blk, attrs); self.print_block_with_attrs(blk, attrs);
} }
ast::ExprKind::Await(expr, _) => { ast::ExprKind::Await(expr, _) => {
// Same fixups as ExprKind::MethodCall.
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup); self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
self.word(".await"); self.word(".await");
} }
ast::ExprKind::Assign(lhs, rhs, _) => { ast::ExprKind::Assign(lhs, rhs, _) => {
// Same fixups as ExprKind::Binary.
let prec = AssocOp::Assign.precedence() as i8; 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.space();
self.word_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) => { ast::ExprKind::AssignOp(op, lhs, rhs) => {
// Same fixups as ExprKind::Binary.
let prec = AssocOp::Assign.precedence() as i8; 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.space();
self.word(op.node.as_str()); self.word(op.node.as_str());
self.word_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::Field(expr, ident) => { ast::ExprKind::Field(expr, ident) => {
// Same fixups as ExprKind::MethodCall.
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup); self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
self.word("."); self.word(".");
self.print_ident(*ident); self.print_ident(*ident);
} }
ast::ExprKind::Index(expr, index, _) => { 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.word("[");
self.print_expr(index, FixupContext::default()); self.print_expr(index, FixupContext::default());
self.word("]"); self.word("]");
@ -540,14 +726,31 @@ impl<'a> State<'a> {
// a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.) // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
let fake_prec = AssocOp::LOr.precedence() as i8; let fake_prec = AssocOp::LOr.precedence() as i8;
if let Some(e) = start { 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 { match limits {
ast::RangeLimits::HalfOpen => self.word(".."), ast::RangeLimits::HalfOpen => self.word(".."),
ast::RangeLimits::Closed => self.word("..="), ast::RangeLimits::Closed => self.word("..="),
} }
if let Some(e) = end { 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("_"), ast::ExprKind::Underscore => self.word("_"),
@ -561,7 +764,15 @@ impl<'a> State<'a> {
} }
if let Some(expr) = opt_expr { if let Some(expr) = opt_expr {
self.space(); 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) => { ast::ExprKind::Continue(opt_label) => {
@ -575,7 +786,15 @@ impl<'a> State<'a> {
self.word("return"); self.word("return");
if let Some(expr) = result { if let Some(expr) = result {
self.word(" "); 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) => { ast::ExprKind::Yeet(result) => {
@ -584,13 +803,25 @@ impl<'a> State<'a> {
self.word("yeet"); self.word("yeet");
if let Some(expr) = result { if let Some(expr) = result {
self.word(" "); 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) => { ast::ExprKind::Become(result) => {
self.word("become"); self.word("become");
self.word(" "); 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) => { ast::ExprKind::InlineAsm(a) => {
// FIXME: This should have its own syntax, distinct from a macro invocation. // 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 { if let Some(expr) = e {
self.space(); 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) => { ast::ExprKind::Try(e) => {
// Same fixups as ExprKind::MethodCall.
self.print_expr_maybe_paren(e, parser::PREC_POSTFIX, fixup); self.print_expr_maybe_paren(e, parser::PREC_POSTFIX, fixup);
self.word("?") self.word("?")
} }
@ -659,7 +899,13 @@ impl<'a> State<'a> {
self.pclose() self.pclose()
} }
} }
self.ann.post(self, AnnNode::Expr(expr)); self.ann.post(self, AnnNode::Expr(expr));
if needs_par {
self.pclose();
}
self.end(); self.end();
} }
@ -700,7 +946,7 @@ impl<'a> State<'a> {
} }
_ => { _ => {
self.end(); // Close the ibox for the pattern. 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(","); self.word(",");
} }
} }

View File

@ -5,7 +5,6 @@ use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
use ast::StaticItem; use ast::StaticItem;
use itertools::{Itertools, Position}; use itertools::{Itertools, Position};
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::GenericBound;
use rustc_ast::ModKind; use rustc_ast::ModKind;
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
@ -338,19 +337,9 @@ impl<'a> State<'a> {
self.word_nbsp("trait"); self.word_nbsp("trait");
self.print_ident(item.ident); self.print_ident(item.ident);
self.print_generic_params(&generics.params); self.print_generic_params(&generics.params);
let mut real_bounds = Vec::with_capacity(bounds.len()); if !bounds.is_empty() {
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() {
self.word_nbsp(":"); self.word_nbsp(":");
self.print_type_bounds(&real_bounds); self.print_type_bounds(bounds);
} }
self.print_where_clause(&generics.where_clause); self.print_where_clause(&generics.where_clause);
self.word(" "); self.word(" ");
@ -387,6 +376,9 @@ impl<'a> State<'a> {
state.print_visibility(&item.vis) 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)) self.ann.post(self, AnnNode::Item(item))
} }
@ -565,10 +557,38 @@ impl<'a> State<'a> {
self.word(";"); self.word(";");
} }
} }
ast::AssocItemKind::Delegation(box delegation) => {
self.print_delegation(delegation, vis, &item.attrs)
}
} }
self.ann.post(self, AnnNode::SubItem(id)) 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( fn print_fn_full(
&mut self, &mut self,
sig: &ast::FnSig, sig: &ast::FnSig,

View File

@ -9,7 +9,7 @@ use rustc_macros::HashStable_Generic;
use rustc_session::config::ExpectedValues; use rustc_session::config::ExpectedValues;
use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::lint::builtin::UNEXPECTED_CFGS;
use rustc_session::lint::BuiltinLintDiagnostics; 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_session::{RustcVersion, Session};
use rustc_span::hygiene::Transparency; use rustc_span::hygiene::Transparency;
use rustc_span::{symbol::sym, symbol::Symbol, Span}; 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::rustc_allowed_through_unstable_modules => allowed_through_unstable_modules = true,
sym::unstable => { sym::unstable => {
if stab.is_some() { if stab.is_some() {
sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }); sess.dcx()
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
break; break;
} }
@ -217,7 +218,8 @@ pub fn find_stability(
} }
sym::stable => { sym::stable => {
if stab.is_some() { if stab.is_some() {
sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }); sess.dcx()
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
break; break;
} }
if let Some((feature, level)) = parse_stability(sess, attr) { if let Some((feature, level)) = parse_stability(sess, attr) {
@ -238,7 +240,8 @@ pub fn find_stability(
_, _,
)) => *allowed_through_unstable_modules = true, )) => *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_promotable => promotable = true,
sym::rustc_const_unstable => { sym::rustc_const_unstable => {
if const_stab.is_some() { 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; break;
} }
@ -272,7 +276,8 @@ pub fn find_const_stability(
} }
sym::rustc_const_stable => { sym::rustc_const_stable => {
if const_stab.is_some() { 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; break;
} }
if let Some((feature, level)) = parse_stability(sess, attr) { if let Some((feature, level)) = parse_stability(sess, attr) {
@ -288,7 +293,11 @@ pub fn find_const_stability(
if promotable { if promotable {
match &mut const_stab { match &mut const_stab {
Some((stab, _)) => stab.promotable = promotable, 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 { for attr in attrs {
if attr.has_name(sym::rustc_default_body_unstable) { if attr.has_name(sym::rustc_default_body_unstable) {
if body_stab.is_some() { 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; break;
} }
@ -321,7 +331,7 @@ pub fn find_body_stability(
fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option<Symbol>) -> Option<()> { fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option<Symbol>) -> Option<()> {
if item.is_some() { if item.is_some() {
sess.emit_err(session_diagnostics::MultipleItem { sess.dcx().emit_err(session_diagnostics::MultipleItem {
span: meta.span, span: meta.span,
item: pprust::path_to_string(&meta.path), 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); *item = Some(v);
Some(()) Some(())
} else { } else {
sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span }); sess.dcx().emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
None None
} }
} }
@ -345,7 +355,7 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
let mut since = None; let mut since = None;
for meta in metas { for meta in metas {
let Some(mi) = meta.meta_item() else { let Some(mi) = meta.meta_item() else {
sess.emit_err(session_diagnostics::UnsupportedLiteral { sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
span: meta.span(), span: meta.span(),
reason: UnsupportedLiteralReason::Generic, reason: UnsupportedLiteralReason::Generic,
is_bytestr: false, 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::feature => insert_or_error(sess, mi, &mut feature)?,
sym::since => insert_or_error(sess, mi, &mut since)?, 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(), span: meta.span(),
item: pprust::path_to_string(&mi.path), item: pprust::path_to_string(&mi.path),
expected: &["feature", "since"], expected: &["feature", "since"],
@ -371,9 +381,9 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
let feature = match feature { let feature = match feature {
Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature), Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
Some(_bad_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 { 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) { } else if let Some(version) = parse_version(since) {
StableSince::Version(version) StableSince::Version(version)
} else { } else {
sess.emit_err(session_diagnostics::InvalidSince { span: attr.span }); sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span });
StableSince::Err StableSince::Err
} }
} else { } else {
sess.emit_err(session_diagnostics::MissingSince { span: attr.span }); sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span });
StableSince::Err StableSince::Err
}; };
@ -413,7 +423,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
let mut implied_by = None; let mut implied_by = None;
for meta in metas { for meta in metas {
let Some(mi) = meta.meta_item() else { let Some(mi) = meta.meta_item() else {
sess.emit_err(session_diagnostics::UnsupportedLiteral { sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
span: meta.span(), span: meta.span(),
reason: UnsupportedLiteralReason::Generic, reason: UnsupportedLiteralReason::Generic,
is_bytestr: false, is_bytestr: false,
@ -435,7 +445,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
issue => match issue.parse::<NonZeroU32>() { issue => match issue.parse::<NonZeroU32>() {
Ok(num) => Some(num), Ok(num) => Some(num),
Err(err) => { Err(err) => {
sess.emit_err( sess.dcx().emit_err(
session_diagnostics::InvalidIssueString { session_diagnostics::InvalidIssueString {
span: mi.span, span: mi.span,
cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind( cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind(
@ -451,13 +461,13 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
} }
sym::soft => { sym::soft => {
if !mi.is_word() { 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; is_soft = true;
} }
sym::implied_by => insert_or_error(sess, mi, &mut implied_by)?, 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(), span: meta.span(),
item: pprust::path_to_string(&mi.path), item: pprust::path_to_string(&mi.path),
expected: &["feature", "reason", "issue", "soft", "implied_by"], 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 { let feature = match feature {
Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature), Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
Some(_bad_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 = let issue = issue
issue.ok_or_else(|| sess.emit_err(session_diagnostics::MissingIssue { span: attr.span })); .ok_or_else(|| sess.dcx().emit_err(session_diagnostics::MissingIssue { span: attr.span }));
match (feature, issue) { match (feature, issue) {
(Ok(feature), Ok(_)) => { (Ok(feature), Ok(_)) => {
@ -508,15 +518,15 @@ pub struct Condition {
/// Tests if a cfg-pattern matches the cfg set /// Tests if a cfg-pattern matches the cfg set
pub fn cfg_matches( pub fn cfg_matches(
cfg: &ast::MetaItem, cfg: &ast::MetaItem,
sess: &ParseSess, sess: &Session,
lint_node_id: NodeId, lint_node_id: NodeId,
features: Option<&Features>, features: Option<&Features>,
) -> bool { ) -> bool {
eval_condition(cfg, sess, features, &mut |cfg| { eval_condition(cfg, sess, features, &mut |cfg| {
try_gate_cfg(cfg.name, cfg.span, sess, features); 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) => { Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
sess.buffer_lint_with_diagnostic( sess.parse_sess.buffer_lint_with_diagnostic(
UNEXPECTED_CFGS, UNEXPECTED_CFGS,
cfg.span, cfg.span,
lint_node_id, lint_node_id,
@ -531,8 +541,8 @@ pub fn cfg_matches(
), ),
); );
} }
None if sess.check_config.exhaustive_names => { None if sess.parse_sess.check_config.exhaustive_names => {
sess.buffer_lint_with_diagnostic( sess.parse_sess.buffer_lint_with_diagnostic(
UNEXPECTED_CFGS, UNEXPECTED_CFGS,
cfg.span, cfg.span,
lint_node_id, lint_node_id,
@ -545,18 +555,18 @@ pub fn cfg_matches(
} }
_ => { /* not unexpected */ } _ => { /* 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); let gate = find_gated_cfg(|sym| sym == name);
if let (Some(feats), Some(gated_cfg)) = (features, gate) { if let (Some(feats), Some(gated_cfg)) = (features, gate) {
gate_cfg(gated_cfg, span, sess, feats); 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; let (cfg, feature, has_feature) = gated_cfg;
if !has_feature(features) && !cfg_span.allows_unstable(*feature) { if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
let explain = format!("`cfg({cfg})` is experimental and subject to change"); 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. /// evaluate individual items.
pub fn eval_condition( pub fn eval_condition(
cfg: &ast::MetaItem, cfg: &ast::MetaItem,
sess: &ParseSess, sess: &Session,
features: Option<&Features>, features: Option<&Features>,
eval: &mut impl FnMut(Condition) -> bool, eval: &mut impl FnMut(Condition) -> bool,
) -> bool { ) -> bool {
let dcx = &sess.parse_sess.dcx;
match &cfg.kind { match &cfg.kind {
ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => { ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
try_gate_cfg(sym::version, cfg.span, sess, features); try_gate_cfg(sym::version, cfg.span, sess, features);
@ -599,23 +610,23 @@ pub fn eval_condition(
NestedMetaItem::Lit(MetaItemLit { span, .. }) NestedMetaItem::Lit(MetaItemLit { span, .. })
| NestedMetaItem::MetaItem(MetaItem { span, .. }), | NestedMetaItem::MetaItem(MetaItem { span, .. }),
] => { ] => {
sess.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span }); dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span });
return false; return false;
} }
[..] => { [..] => {
sess.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { dcx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral {
span: cfg.span, span: cfg.span,
}); });
return false; return false;
} }
}; };
let Some(min_version) = parse_version(*min_version) else { 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; return false;
}; };
// See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details // 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 RustcVersion::CURRENT > min_version
} else { } else {
RustcVersion::CURRENT >= min_version RustcVersion::CURRENT >= min_version
@ -624,7 +635,7 @@ pub fn eval_condition(
ast::MetaItemKind::List(mis) => { ast::MetaItemKind::List(mis) => {
for mi in mis.iter() { for mi in mis.iter() {
if !mi.is_meta_item() { if !mi.is_meta_item() {
sess.emit_err(session_diagnostics::UnsupportedLiteral { dcx.emit_err(session_diagnostics::UnsupportedLiteral {
span: mi.span(), span: mi.span(),
reason: UnsupportedLiteralReason::Generic, reason: UnsupportedLiteralReason::Generic,
is_bytestr: false, is_bytestr: false,
@ -653,9 +664,7 @@ pub fn eval_condition(
}), }),
sym::not => { sym::not => {
if mis.len() != 1 { if mis.len() != 1 {
sess.emit_err(session_diagnostics::ExpectedOneCfgPattern { dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
span: cfg.span,
});
return false; 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, span: cfg.span,
predicate: pprust::path_to_string(&cfg.path), 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 => { 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 true
} }
MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
sess.emit_err(session_diagnostics::UnsupportedLiteral { dcx.emit_err(session_diagnostics::UnsupportedLiteral {
span: lit.span, span: lit.span,
reason: UnsupportedLiteralReason::CfgString, reason: UnsupportedLiteralReason::CfgString,
is_bytestr: lit.kind.is_bytestr(), is_bytestr: lit.kind.is_bytestr(),
@ -791,7 +800,7 @@ pub fn find_deprecation(
MetaItemKind::List(list) => { MetaItemKind::List(list) => {
let get = |meta: &MetaItem, item: &mut Option<Symbol>| { let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
if item.is_some() { if item.is_some() {
sess.emit_err(session_diagnostics::MultipleItem { sess.dcx().emit_err(session_diagnostics::MultipleItem {
span: meta.span, span: meta.span,
item: pprust::path_to_string(&meta.path), item: pprust::path_to_string(&meta.path),
}); });
@ -802,14 +811,14 @@ pub fn find_deprecation(
true true
} else { } else {
if let Some(lit) = meta.name_value_literal() { if let Some(lit) = meta.name_value_literal() {
sess.emit_err(session_diagnostics::UnsupportedLiteral { sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
span: lit.span, span: lit.span,
reason: UnsupportedLiteralReason::DeprecatedString, reason: UnsupportedLiteralReason::DeprecatedString,
is_bytestr: lit.kind.is_bytestr(), is_bytestr: lit.kind.is_bytestr(),
start_point_span: sess.source_map().start_point(lit.span), start_point_span: sess.source_map().start_point(lit.span),
}); });
} else { } else {
sess.emit_err(session_diagnostics::IncorrectMetaItem { sess.dcx().emit_err(session_diagnostics::IncorrectMetaItem {
span: meta.span, span: meta.span,
}); });
} }
@ -833,11 +842,13 @@ pub fn find_deprecation(
} }
sym::suggestion => { sym::suggestion => {
if !features.deprecated_suggestion { if !features.deprecated_suggestion {
sess.emit_err(session_diagnostics::DeprecatedItemSuggestion { sess.dcx().emit_err(
span: mi.span, session_diagnostics::DeprecatedItemSuggestion {
is_nightly: sess.is_nightly_build().then_some(()), span: mi.span,
details: (), is_nightly: sess.is_nightly_build().then_some(()),
}); details: (),
},
);
} }
if !get(mi, &mut suggestion) { 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(), span: meta.span(),
item: pprust::path_to_string(&mi.path), item: pprust::path_to_string(&mi.path),
expected: if features.deprecated_suggestion { expected: if features.deprecated_suggestion {
@ -858,7 +869,7 @@ pub fn find_deprecation(
} }
}, },
NestedMetaItem::Lit(lit) => { NestedMetaItem::Lit(lit) => {
sess.emit_err(session_diagnostics::UnsupportedLiteral { sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
span: lit.span, span: lit.span,
reason: UnsupportedLiteralReason::DeprecatedKvPair, reason: UnsupportedLiteralReason::DeprecatedKvPair,
is_bytestr: false, is_bytestr: false,
@ -879,18 +890,18 @@ pub fn find_deprecation(
} else if let Some(version) = parse_version(since) { } else if let Some(version) = parse_version(since) {
DeprecatedSince::RustcVersion(version) DeprecatedSince::RustcVersion(version)
} else { } else {
sess.emit_err(session_diagnostics::InvalidSince { span: attr.span }); sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span });
DeprecatedSince::Err DeprecatedSince::Err
} }
} else if is_rustc { } 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 DeprecatedSince::Err
} else { } else {
DeprecatedSince::Unspecified DeprecatedSince::Unspecified
}; };
if is_rustc && note.is_none() { 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; 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:?}"); assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {attr:?}");
use ReprAttr::*; use ReprAttr::*;
let mut acc = Vec::new(); let mut acc = Vec::new();
let diagnostic = sess.dcx(); let dcx = sess.dcx();
if let Some(items) = attr.meta_item_list() { if let Some(items) = attr.meta_item_list() {
for item in items { for item in items {
@ -958,7 +969,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
sym::simd => Some(ReprSimd), sym::simd => Some(ReprSimd),
sym::transparent => Some(ReprTransparent), sym::transparent => Some(ReprTransparent),
sym::align => { sym::align => {
sess.emit_err(session_diagnostics::InvalidReprAlignNeedArg { sess.dcx().emit_err(session_diagnostics::InvalidReprAlignNeedArg {
span: item.span(), span: item.span(),
}); });
recognised = true; recognised = true;
@ -989,13 +1000,13 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|| int_type_of_word(name).is_some() || int_type_of_word(name).is_some()
{ {
recognised = true; recognised = true;
sess.emit_err(session_diagnostics::InvalidReprHintNoParen { sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
span: item.span(), span: item.span(),
name: name.to_ident_string(), name: name.to_ident_string(),
}); });
} }
if let Some(literal_error) = literal_error { if let Some(literal_error) = literal_error {
sess.emit_err(session_diagnostics::InvalidReprGeneric { sess.dcx().emit_err(session_diagnostics::InvalidReprGeneric {
span: item.span(), span: item.span(),
repr_arg: name.to_ident_string(), repr_arg: name.to_ident_string(),
error_part: literal_error, 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) { if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
let name = meta_item.name_or_empty().to_ident_string(); let name = meta_item.name_or_empty().to_ident_string();
recognised = true; recognised = true;
sess.emit_err(session_diagnostics::IncorrectReprFormatGeneric { sess.dcx().emit_err(session_diagnostics::IncorrectReprFormatGeneric {
span: item.span(), span: item.span(),
repr_arg: &name, repr_arg: &name,
cause: IncorrectReprFormatGenericCause::from_lit_kind( 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() ) || int_type_of_word(meta_item.name_or_empty()).is_some()
{ {
recognised = true; recognised = true;
sess.emit_err(session_diagnostics::InvalidReprHintNoValue { sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoValue {
span: meta_item.span, span: meta_item.span,
name: meta_item.name_or_empty().to_ident_string(), 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(_) => { MetaItemKind::List(_) => {
if meta_item.has_name(sym::align) { if meta_item.has_name(sym::align) {
recognised = true; recognised = true;
sess.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg { sess.dcx().emit_err(
span: meta_item.span, session_diagnostics::IncorrectReprFormatAlignOneArg {
}); span: meta_item.span,
},
);
} else if meta_item.has_name(sym::packed) { } else if meta_item.has_name(sym::packed) {
recognised = true; recognised = true;
sess.emit_err( sess.dcx().emit_err(
session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg { session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
span: meta_item.span, 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() ) || int_type_of_word(meta_item.name_or_empty()).is_some()
{ {
recognised = true; recognised = true;
sess.emit_err(session_diagnostics::InvalidReprHintNoParen { sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
span: meta_item.span, span: meta_item.span,
name: meta_item.name_or_empty().to_ident_string(), 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 // (e.g. if we only pretty-print the source), so we have to gate
// the `span_delayed_bug` call as follows: // the `span_delayed_bug` call as follows:
if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) { 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 let list = attrs
.filter_map(move |attr| { .filter_map(move |attr| {
attr.meta_item_list().or_else(|| { attr.meta_item_list().or_else(|| {
sess.emit_err(session_diagnostics::ExpectsFeatureList { sess.dcx().emit_err(session_diagnostics::ExpectsFeatureList {
span: attr.span, span: attr.span,
name: symbol.to_ident_string(), name: symbol.to_ident_string(),
}); });
@ -1161,7 +1174,7 @@ fn allow_unstable<'a>(
list.into_iter().filter_map(move |it| { list.into_iter().filter_map(move |it| {
let name = it.ident().map(|ident| ident.name); let name = it.ident().map(|ident| ident.name);
if name.is_none() { if name.is_none() {
sess.emit_err(session_diagnostics::ExpectsFeatures { sess.dcx().emit_err(session_diagnostics::ExpectsFeatures {
span: it.span(), span: it.span(),
name: symbol.to_ident_string(), name: symbol.to_ident_string(),
}); });
@ -1172,9 +1185,9 @@ fn allow_unstable<'a>(
pub fn parse_alignment(node: &ast::LitKind) -> Result<u32, &'static str> { pub fn parse_alignment(node: &ast::LitKind) -> Result<u32, &'static str> {
if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { 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 // 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 { } else {
Err("not a power of two") Err("not a power of two")
} }

View File

@ -2,7 +2,7 @@ use std::num::IntErrorKind;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_errors::{ use rustc_errors::{
error_code, Applicability, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, codes::*, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level,
}; };
use rustc_macros::Diagnostic; use rustc_macros::Diagnostic;
use rustc_span::{Span, Symbol}; use rustc_span::{Span, Symbol};
@ -11,14 +11,14 @@ use crate::fluent_generated as fluent;
use crate::UnsupportedLiteralReason; use crate::UnsupportedLiteralReason;
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_expected_one_cfg_pattern, code = "E0536")] #[diag(attr_expected_one_cfg_pattern, code = E0536)]
pub(crate) struct ExpectedOneCfgPattern { pub(crate) struct ExpectedOneCfgPattern {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_invalid_predicate, code = "E0537")] #[diag(attr_invalid_predicate, code = E0537)]
pub(crate) struct InvalidPredicate { pub(crate) struct InvalidPredicate {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -27,7 +27,7 @@ pub(crate) struct InvalidPredicate {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_multiple_item, code = "E0538")] #[diag(attr_multiple_item, code = E0538)]
pub(crate) struct MultipleItem { pub(crate) struct MultipleItem {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -36,7 +36,7 @@ pub(crate) struct MultipleItem {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_incorrect_meta_item, code = "E0539")] #[diag(attr_incorrect_meta_item, code = E0539)]
pub(crate) struct IncorrectMetaItem { pub(crate) struct IncorrectMetaItem {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -50,44 +50,41 @@ pub(crate) struct UnknownMetaItem<'a> {
} }
// Manual implementation to be able to format `expected` items correctly. // Manual implementation to be able to format `expected` items correctly.
impl<'a> IntoDiagnostic<'a> for UnknownMetaItem<'_> { impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnknownMetaItem<'_> {
fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>(); let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
let mut diag = dcx.struct_span_err_with_code( DiagnosticBuilder::new(dcx, level, fluent::attr_unknown_meta_item)
self.span, .with_span(self.span)
fluent::attr_unknown_meta_item, .with_code(E0541)
error_code!(E0541), .with_arg("item", self.item)
); .with_arg("expected", expected.join(", "))
diag.set_arg("item", self.item); .with_span_label(self.span, fluent::attr_label)
diag.set_arg("expected", expected.join(", "));
diag.span_label(self.span, fluent::attr_label);
diag
} }
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_missing_since, code = "E0542")] #[diag(attr_missing_since, code = E0542)]
pub(crate) struct MissingSince { pub(crate) struct MissingSince {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_missing_note, code = "E0543")] #[diag(attr_missing_note, code = E0543)]
pub(crate) struct MissingNote { pub(crate) struct MissingNote {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_multiple_stability_levels, code = "E0544")] #[diag(attr_multiple_stability_levels, code = E0544)]
pub(crate) struct MultipleStabilityLevels { pub(crate) struct MultipleStabilityLevels {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_invalid_issue_string, code = "E0545")] #[diag(attr_invalid_issue_string, code = E0545)]
pub(crate) struct InvalidIssueString { pub(crate) struct InvalidIssueString {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -145,21 +142,21 @@ impl InvalidIssueStringCause {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_missing_feature, code = "E0546")] #[diag(attr_missing_feature, code = E0546)]
pub(crate) struct MissingFeature { pub(crate) struct MissingFeature {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_non_ident_feature, code = "E0546")] #[diag(attr_non_ident_feature, code = E0546)]
pub(crate) struct NonIdentFeature { pub(crate) struct NonIdentFeature {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_missing_issue, code = "E0547")] #[diag(attr_missing_issue, code = E0547)]
pub(crate) struct MissingIssue { pub(crate) struct MissingIssue {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -168,14 +165,14 @@ pub(crate) struct MissingIssue {
// FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`? // FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`?
// It is more similar to `IncorrectReprFormatGeneric`. // It is more similar to `IncorrectReprFormatGeneric`.
#[derive(Diagnostic)] #[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 { pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_invalid_repr_hint_no_paren, code = "E0552")] #[diag(attr_invalid_repr_hint_no_paren, code = E0552)]
pub(crate) struct InvalidReprHintNoParen { pub(crate) struct InvalidReprHintNoParen {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -184,7 +181,7 @@ pub(crate) struct InvalidReprHintNoParen {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_invalid_repr_hint_no_value, code = "E0552")] #[diag(attr_invalid_repr_hint_no_value, code = E0552)]
pub(crate) struct InvalidReprHintNoValue { pub(crate) struct InvalidReprHintNoValue {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -200,10 +197,11 @@ pub(crate) struct UnsupportedLiteral {
pub start_point_span: Span, pub start_point_span: Span,
} }
impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral { impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnsupportedLiteral {
fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
let mut diag = dcx.struct_span_err_with_code( let mut diag = DiagnosticBuilder::new(
self.span, dcx,
level,
match self.reason { match self.reason {
UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic, UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string, 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 fluent::attr_unsupported_literal_deprecated_kv_pair
} }
}, },
error_code!(E0565),
); );
diag.span(self.span);
diag.code(E0565);
if self.is_bytestr { if self.is_bytestr {
diag.span_suggestion( diag.span_suggestion(
self.start_point_span, self.start_point_span,
@ -229,7 +228,7 @@ impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_invalid_repr_align_need_arg, code = "E0589")] #[diag(attr_invalid_repr_align_need_arg, code = E0589)]
pub(crate) struct InvalidReprAlignNeedArg { pub(crate) struct InvalidReprAlignNeedArg {
#[primary_span] #[primary_span]
#[suggestion(code = "align(...)", applicability = "has-placeholders")] #[suggestion(code = "align(...)", applicability = "has-placeholders")]
@ -237,7 +236,7 @@ pub(crate) struct InvalidReprAlignNeedArg {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_invalid_repr_generic, code = "E0589")] #[diag(attr_invalid_repr_generic, code = E0589)]
pub(crate) struct InvalidReprGeneric<'a> { pub(crate) struct InvalidReprGeneric<'a> {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -247,14 +246,14 @@ pub(crate) struct InvalidReprGeneric<'a> {
} }
#[derive(Diagnostic)] #[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 { pub(crate) struct IncorrectReprFormatAlignOneArg {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_incorrect_repr_format_generic, code = "E0693")] #[diag(attr_incorrect_repr_format_generic, code = E0693)]
pub(crate) struct IncorrectReprFormatGeneric<'a> { pub(crate) struct IncorrectReprFormatGeneric<'a> {
#[primary_span] #[primary_span]
pub span: 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> { pub fn from_lit_kind(span: Span, kind: &ast::LitKind, name: &'a str) -> Option<Self> {
match kind { match kind {
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { 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 }), ast::LitKind::Str(symbol, _) => Some(Self::Symbol { span, name, symbol: *symbol }),
_ => None, _ => None,
@ -305,14 +304,14 @@ impl<'a> IncorrectReprFormatGenericCause<'a> {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_rustc_promotable_pairing, code = "E0717")] #[diag(attr_rustc_promotable_pairing, code = E0717)]
pub(crate) struct RustcPromotablePairing { pub(crate) struct RustcPromotablePairing {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_rustc_allowed_unstable_pairing, code = "E0789")] #[diag(attr_rustc_allowed_unstable_pairing, code = E0789)]
pub(crate) struct RustcAllowedUnstablePairing { pub(crate) struct RustcAllowedUnstablePairing {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,

View File

@ -1,10 +1,12 @@
use rustc_errors::{ use rustc_errors::{codes::*, struct_span_code_err, DiagCtxt, DiagnosticBuilder};
struct_span_err, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
};
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span; use rustc_span::Span;
impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
pub fn dcx(&self) -> &'tcx DiagCtxt {
self.infcx.dcx()
}
pub(crate) fn cannot_move_when_borrowed( pub(crate) fn cannot_move_when_borrowed(
&self, &self,
span: Span, span: Span,
@ -12,8 +14,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
place: &str, place: &str,
borrow_place: &str, borrow_place: &str,
value_place: &str, value_place: &str,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
self.infcx.tcx.sess.create_err(crate::session_diagnostics::MoveBorrow { self.dcx().create_err(crate::session_diagnostics::MoveBorrow {
place, place,
span, span,
borrow_place, borrow_place,
@ -28,18 +30,16 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
desc: &str, desc: &str,
borrow_span: Span, borrow_span: Span,
borrow_desc: &str, borrow_desc: &str,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!( struct_span_code_err!(
self, self.dcx(),
span, span,
E0503, E0503,
"cannot use {} because it was mutably borrowed", "cannot use {} because it was mutably borrowed",
desc, desc,
); )
.with_span_label(borrow_span, format!("{borrow_desc} is borrowed here"))
err.span_label(borrow_span, format!("{borrow_desc} is borrowed here")); .with_span_label(span, format!("use of borrowed {borrow_desc}"))
err.span_label(span, format!("use of borrowed {borrow_desc}"));
err
} }
pub(crate) fn cannot_mutably_borrow_multiply( pub(crate) fn cannot_mutably_borrow_multiply(
@ -50,10 +50,10 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
old_loan_span: Span, old_loan_span: Span,
old_opt_via: &str, old_opt_via: &str,
old_load_end_span: Option<Span>, 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 via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
let mut err = struct_span_err!( let mut err = struct_span_code_err!(
self, self.dcx(),
new_loan_span, new_loan_span,
E0499, E0499,
"cannot borrow {}{} as mutable more than once at a time", "cannot borrow {}{} as mutable more than once at a time",
@ -97,9 +97,9 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
desc: &str, desc: &str,
old_loan_span: Span, old_loan_span: Span,
old_load_end_span: Option<Span>, old_load_end_span: Option<Span>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!( let mut err = struct_span_code_err!(
self, self.dcx(),
new_loan_span, new_loan_span,
E0524, E0524,
"two closures require unique access to {} at the same time", "two closures require unique access to {} at the same time",
@ -130,9 +130,9 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
noun_old: &str, noun_old: &str,
old_opt_via: &str, old_opt_via: &str,
previous_end_span: Option<Span>, previous_end_span: Option<Span>,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!( let mut err = struct_span_code_err!(
self, self.dcx(),
new_loan_span, new_loan_span,
E0500, E0500,
"closure requires unique access to {} but {} is already borrowed{}", "closure requires unique access to {} but {} is already borrowed{}",
@ -162,9 +162,9 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
old_opt_via: &str, old_opt_via: &str,
previous_end_span: Option<Span>, previous_end_span: Option<Span>,
second_borrow_desc: &str, second_borrow_desc: &str,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!( let mut err = struct_span_code_err!(
self, self.dcx(),
new_loan_span, new_loan_span,
E0501, E0501,
"cannot borrow {}{} as {} because previous closure requires unique access", "cannot borrow {}{} as {} because previous closure requires unique access",
@ -194,10 +194,10 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
kind_old: &str, kind_old: &str,
msg_old: &str, msg_old: &str,
old_load_end_span: Option<Span>, 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 via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
let mut err = struct_span_err!( let mut err = struct_span_code_err!(
self, self.dcx(),
span, span,
E0502, E0502,
"cannot borrow {}{} as {} because {} is also borrowed as {}{}", "cannot borrow {}{} as {} because {} is also borrowed as {}{}",
@ -235,18 +235,16 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
span: Span, span: Span,
borrow_span: Span, borrow_span: Span,
desc: &str, desc: &str,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!( struct_span_code_err!(
self, self.dcx(),
span, span,
E0506, E0506,
"cannot assign to {} because it is borrowed", "cannot assign to {} because it is borrowed",
desc, desc,
); )
.with_span_label(borrow_span, format!("{desc} is borrowed here"))
err.span_label(borrow_span, format!("{desc} is borrowed here")); .with_span_label(span, format!("{desc} is assigned to here but it was already borrowed"))
err.span_label(span, format!("{desc} is assigned to here but it was already borrowed"));
err
} }
pub(crate) fn cannot_reassign_immutable( pub(crate) fn cannot_reassign_immutable(
@ -254,25 +252,27 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
span: Span, span: Span,
desc: &str, desc: &str,
is_arg: bool, is_arg: bool,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" }; 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( pub(crate) fn cannot_assign(&self, span: Span, desc: &str) -> DiagnosticBuilder<'tcx> {
&self, struct_span_code_err!(self.dcx(), span, E0594, "cannot assign to {}", desc)
span: Span,
desc: &str,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0594, "cannot assign to {}", desc)
} }
pub(crate) fn cannot_move_out_of( pub(crate) fn cannot_move_out_of(
&self, &self,
move_from_span: Span, move_from_span: Span,
move_from_desc: &str, move_from_desc: &str,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc) 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 /// 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, move_from_span: Span,
ty: Ty<'_>, ty: Ty<'_>,
is_index: Option<bool>, is_index: Option<bool>,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
let type_name = match (&ty.kind(), is_index) { let type_name = match (&ty.kind(), is_index) {
(&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array", (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
(&ty::Slice(_), _) => "slice", (&ty::Slice(_), _) => "slice",
_ => span_bug!(move_from_span, "this path should not cause illegal move"), _ => span_bug!(move_from_span, "this path should not cause illegal move"),
}; };
let mut err = struct_span_err!( struct_span_code_err!(
self, self.dcx(),
move_from_span, move_from_span,
E0508, E0508,
"cannot move out of type `{}`, a non-copy {}", "cannot move out of type `{}`, a non-copy {}",
ty, ty,
type_name, type_name,
); )
err.span_label(move_from_span, "cannot move out of here"); .with_span_label(move_from_span, "cannot move out of here")
err
} }
pub(crate) fn cannot_move_out_of_interior_of_drop( pub(crate) fn cannot_move_out_of_interior_of_drop(
&self, &self,
move_from_span: Span, move_from_span: Span,
container_ty: Ty<'_>, container_ty: Ty<'_>,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!( struct_span_code_err!(
self, self.dcx(),
move_from_span, move_from_span,
E0509, E0509,
"cannot move out of type `{}`, which implements the `Drop` trait", "cannot move out of type `{}`, which implements the `Drop` trait",
container_ty, container_ty,
); )
err.span_label(move_from_span, "cannot move out of here"); .with_span_label(move_from_span, "cannot move out of here")
err
} }
pub(crate) fn cannot_act_on_moved_value( pub(crate) fn cannot_act_on_moved_value(
@ -323,11 +321,11 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
verb: &str, verb: &str,
optional_adverb_for_moved: &str, optional_adverb_for_moved: &str,
moved_path: Option<String>, moved_path: Option<String>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default(); let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default();
struct_span_err!( struct_span_code_err!(
self, self.dcx(),
use_span, use_span,
E0382, E0382,
"{} of {}moved value{}", "{} of {}moved value{}",
@ -342,8 +340,15 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
span: Span, span: Span,
path: &str, path: &str,
reason: &str, reason: &str,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,) struct_span_code_err!(
self.dcx(),
span,
E0596,
"cannot borrow {} as mutable{}",
path,
reason
)
} }
pub(crate) fn cannot_mutate_in_immutable_section( pub(crate) fn cannot_mutate_in_immutable_section(
@ -353,43 +358,41 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
immutable_place: &str, immutable_place: &str,
immutable_section: &str, immutable_section: &str,
action: &str, action: &str,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!( struct_span_code_err!(
self, self.dcx(),
mutate_span, mutate_span,
E0510, E0510,
"cannot {} {} in {}", "cannot {} {} in {}",
action, action,
immutable_place, immutable_place,
immutable_section, immutable_section,
); )
err.span_label(mutate_span, format!("cannot {action}")); .with_span_label(mutate_span, format!("cannot {action}"))
err.span_label(immutable_span, format!("value is immutable in {immutable_section}")); .with_span_label(immutable_span, format!("value is immutable in {immutable_section}"))
err
} }
pub(crate) fn cannot_borrow_across_coroutine_yield( pub(crate) fn cannot_borrow_across_coroutine_yield(
&self, &self,
span: Span, span: Span,
yield_span: Span, yield_span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind; let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind;
let mut err = struct_span_err!( struct_span_code_err!(
self, self.dcx(),
span, span,
E0626, E0626,
"borrow may still be in use when {coroutine_kind:#} yields", "borrow may still be in use when {coroutine_kind:#} yields",
); )
err.span_label(yield_span, "possible yield occurs here"); .with_span_label(yield_span, "possible yield occurs here")
err
} }
pub(crate) fn cannot_borrow_across_destructor( pub(crate) fn cannot_borrow_across_destructor(
&self, &self,
borrow_span: Span, borrow_span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
struct_span_err!( struct_span_code_err!(
self, self.dcx(),
borrow_span, borrow_span,
E0713, E0713,
"borrow may still be in use when destructor runs", "borrow may still be in use when destructor runs",
@ -400,8 +403,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
&self, &self,
span: Span, span: Span,
path: &str, path: &str,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
struct_span_err!(self, span, E0597, "{} does not live long enough", path,) struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path,)
} }
pub(crate) fn cannot_return_reference_to_local( pub(crate) fn cannot_return_reference_to_local(
@ -410,23 +413,20 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
return_kind: &str, return_kind: &str,
reference_desc: &str, reference_desc: &str,
path_desc: &str, path_desc: &str,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!( struct_span_code_err!(
self, self.dcx(),
span, span,
E0515, E0515,
"cannot {RETURN} {REFERENCE} {LOCAL}", "cannot {RETURN} {REFERENCE} {LOCAL}",
RETURN = return_kind, RETURN = return_kind,
REFERENCE = reference_desc, REFERENCE = reference_desc,
LOCAL = path_desc, LOCAL = path_desc,
); )
.with_span_label(
err.span_label(
span, span,
format!("{return_kind}s a {reference_desc} data owned by the current function"), format!("{return_kind}s a {reference_desc} data owned by the current function"),
); )
err
} }
pub(crate) fn cannot_capture_in_long_lived_closure( pub(crate) fn cannot_capture_in_long_lived_closure(
@ -436,42 +436,35 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
borrowed_path: &str, borrowed_path: &str,
capture_span: Span, capture_span: Span,
scope: &str, scope: &str,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!( struct_span_code_err!(
self, self.dcx(),
closure_span, closure_span,
E0373, E0373,
"{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \ "{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \
which is owned by the current {scope}", which is owned by the current {scope}",
); )
err.span_label(capture_span, format!("{borrowed_path} is borrowed here")) .with_span_label(capture_span, format!("{borrowed_path} is borrowed here"))
.span_label(closure_span, format!("may outlive borrowed value {borrowed_path}")); .with_span_label(closure_span, format!("may outlive borrowed value {borrowed_path}"))
err
} }
pub(crate) fn thread_local_value_does_not_live_long_enough( pub(crate) fn thread_local_value_does_not_live_long_enough(
&self, &self,
span: Span, span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",) 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( pub(crate) fn temporary_value_borrowed_for_too_long(
&self, &self,
span: Span, span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",) struct_span_code_err!(self.dcx(), 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)
} }
} }
@ -479,9 +472,9 @@ pub(crate) fn borrowed_data_escapes_closure<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
escape_span: Span, escape_span: Span,
escapes_from: &str, escapes_from: &str,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
struct_span_err!( struct_span_code_err!(
tcx.sess, tcx.dcx(),
escape_span, escape_span,
E0521, E0521,
"borrowed data escapes outside of {}", "borrowed data escapes outside of {}",

View File

@ -1,7 +1,7 @@
#![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)] #![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::canonical::Canonical;
use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError; use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc_infer::infer::region_constraints::Constraint; use rustc_infer::infer::region_constraints::Constraint;
@ -77,7 +77,7 @@ impl<'tcx> UniverseInfo<'tcx> {
// up in the existing UI tests. Consider investigating this // up in the existing UI tests. Consider investigating this
// some more. // some more.
mbcx.buffer_error( 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> { trait TypeOpInfo<'tcx> {
/// Returns an error to be reported if rerunning the type op fails to /// Returns an error to be reported if rerunning the type op fails to
/// recover the error's cause. /// recover the error's cause.
fn fallback_error( fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
&self,
tcx: TyCtxt<'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
fn base_universe(&self) -> ty::UniverseIndex; fn base_universe(&self) -> ty::UniverseIndex;
@ -161,7 +157,7 @@ trait TypeOpInfo<'tcx> {
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>, placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>, error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>; ) -> Option<DiagnosticBuilder<'tcx>>;
#[instrument(level = "debug", skip(self, mbcx))] #[instrument(level = "debug", skip(self, mbcx))]
fn report_error( fn report_error(
@ -224,12 +220,8 @@ struct PredicateQuery<'tcx> {
} }
impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
fn fallback_error( fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
&self, tcx.dcx().create_err(HigherRankedLifetimeError {
tcx: TyCtxt<'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
tcx.sess.create_err(HigherRankedLifetimeError {
cause: Some(HigherRankedErrorCause::CouldNotProve { cause: Some(HigherRankedErrorCause::CouldNotProve {
predicate: self.canonical_query.value.value.predicate.to_string(), predicate: self.canonical_query.value.value.predicate.to_string(),
}), }),
@ -247,7 +239,7 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>, placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>, error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { ) -> Option<DiagnosticBuilder<'tcx>> {
let (infcx, key, _) = let (infcx, key, _) =
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
let ocx = ObligationCtxt::new(&infcx); let ocx = ObligationCtxt::new(&infcx);
@ -265,12 +257,8 @@ impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
where where
T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx, T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx,
{ {
fn fallback_error( fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
&self, tcx.dcx().create_err(HigherRankedLifetimeError {
tcx: TyCtxt<'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
tcx.sess.create_err(HigherRankedLifetimeError {
cause: Some(HigherRankedErrorCause::CouldNotNormalize { cause: Some(HigherRankedErrorCause::CouldNotNormalize {
value: self.canonical_query.value.value.value.to_string(), value: self.canonical_query.value.value.value.to_string(),
}), }),
@ -288,7 +276,7 @@ where
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>, placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>, error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { ) -> Option<DiagnosticBuilder<'tcx>> {
let (infcx, key, _) = let (infcx, key, _) =
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
let ocx = ObligationCtxt::new(&infcx); let ocx = ObligationCtxt::new(&infcx);
@ -312,14 +300,10 @@ struct AscribeUserTypeQuery<'tcx> {
} }
impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
fn fallback_error( fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
&self,
tcx: TyCtxt<'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
// FIXME: This error message isn't great, but it doesn't show up in the existing UI tests, // 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. // 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 { fn base_universe(&self) -> ty::UniverseIndex {
@ -332,7 +316,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>, placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>, error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { ) -> Option<DiagnosticBuilder<'tcx>> {
let (infcx, key, _) = let (infcx, key, _) =
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
let ocx = ObligationCtxt::new(&infcx); 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> { impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
fn fallback_error( fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
&self,
tcx: TyCtxt<'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
// FIXME: This error message isn't great, but it doesn't show up in the existing UI tests, // 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. // 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 { fn base_universe(&self) -> ty::UniverseIndex {
@ -362,7 +342,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
_cause: ObligationCause<'tcx>, _cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>, placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>, error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { ) -> Option<DiagnosticBuilder<'tcx>> {
try_extract_error_from_region_constraints( try_extract_error_from_region_constraints(
mbcx.infcx, mbcx.infcx,
placeholder_region, placeholder_region,
@ -383,7 +363,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
ocx: &ObligationCtxt<'_, 'tcx>, ocx: &ObligationCtxt<'_, 'tcx>,
placeholder_region: ty::Region<'tcx>, placeholder_region: ty::Region<'tcx>,
error_region: Option<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 // We generally shouldn't have errors here because the query was
// already run, but there's no point using `span_delayed_bug` // already run, but there's no point using `span_delayed_bug`
// when we're going to emit an error here anyway. // 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>, region_constraints: &RegionConstraintData<'tcx>,
mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin, mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex, 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 = let matches =
|a_region: Region<'tcx>, b_region: Region<'tcx>| match (a_region.kind(), b_region.kind()) { |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, (RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound,
_ => a_region == b_region, _ => a_region == b_region,
}; };
let check = |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| { let mut check =
match *constraint { |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match *constraint {
Constraint::RegSubReg(sub, sup) Constraint::RegSubReg(sub, sup)
if ((exact && sup == placeholder_region) if ((exact && sup == placeholder_region)
|| (!exact && matches(sup, placeholder_region))) || (!exact && matches(sup, placeholder_region)))
@ -422,16 +407,16 @@ fn try_extract_error_from_region_constraints<'tcx>(
{ {
Some((sub, cause.clone())) Some((sub, cause.clone()))
} }
// FIXME: Should this check the universe of the var?
Constraint::VarSubReg(vid, sup) Constraint::VarSubReg(vid, sup)
if ((exact && sup == placeholder_region) if (exact
|| (!exact && matches(sup, placeholder_region))) => && 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())) Some((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
} }
_ => None, _ => None,
} };
};
let mut info = region_constraints let mut info = region_constraints
.constraints .constraints
.iter() .iter()

View File

@ -1,13 +1,15 @@
// ignore-tidy-filelength
use either::Either; use either::Either;
use hir::PatField;
use rustc_data_structures::captures::Captures; use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{ 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 as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
use rustc_hir::{CoroutineDesugaring, PatField};
use rustc_hir::{CoroutineKind, CoroutineSource, LangItem}; use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
use rustc_infer::traits::ObligationCause; use rustc_infer::traits::ObligationCause;
use rustc_middle::hir::nested_filter::OnlyBodies; 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::symbol::{kw, sym, Ident};
use rustc_span::{BytePos, Span, Symbol}; use rustc_span::{BytePos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::ObligationCtxt;
use std::iter; use std::iter;
@ -324,7 +327,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&mut self, &mut self,
mpi: MovePathIndex, mpi: MovePathIndex,
move_span: Span, move_span: Span,
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, err: &mut DiagnosticBuilder<'_>,
in_pattern: &mut bool, in_pattern: &mut bool,
move_spans: UseSpans<'_>, move_spans: UseSpans<'_>,
) { ) {
@ -483,8 +486,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
desired_action: InitializationRequiringAction, desired_action: InitializationRequiringAction,
span: Span, span: Span,
use_spans: UseSpans<'tcx>, use_spans: UseSpans<'tcx>,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
// We need all statements in the body where the binding was assigned to to later find all // 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. // the branching code paths where the binding *wasn't* assigned to.
let inits = &self.move_data.init_path_map[mpi]; let inits = &self.move_data.init_path_map[mpi];
let move_path = &self.move_data.move_paths[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 used = desired_action.as_general_verb_in_past_tense();
let mut err = let mut err = struct_span_code_err!(
struct_span_err!(self, span, E0381, "{used} binding {desc}{isnt_initialized}"); self.dcx(),
span,
E0381,
"{used} binding {desc}{isnt_initialized}"
);
use_spans.var_path_only_subdiag(&mut err, desired_action); use_spans.var_path_only_subdiag(&mut err, desired_action);
if let InitializationRequiringAction::PartialAssignment 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| { move_spans.var_subdiag(None, &mut err, None, |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*; use crate::session_diagnostics::CaptureVarCause::*;
match kind { match kind {
Some(_) => MoveUseInCoroutine { var_span }, hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span },
None => MoveUseInClosure { var_span }, hir::ClosureKind::Closure => MoveUseInClosure { var_span },
} }
}); });
@ -873,7 +880,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
location: Location, location: Location,
(place, _span): (Place<'tcx>, Span), (place, _span): (Place<'tcx>, Span),
borrow: &BorrowData<'tcx>, borrow: &BorrowData<'tcx>,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
let borrow_spans = self.retrieve_borrow_spans(borrow); let borrow_spans = self.retrieve_borrow_spans(borrow);
let borrow_span = borrow_spans.args_or_use(); let borrow_span = borrow_spans.args_or_use();
@ -895,10 +902,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let place = &borrow.borrowed_place; let place = &borrow.borrowed_place;
let desc_place = self.describe_any_place(place.as_ref()); let desc_place = self.describe_any_place(place.as_ref());
match kind { match kind {
Some(_) => { hir::ClosureKind::Coroutine(_) => {
BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true } 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), (place, span): (Place<'tcx>, Span),
gen_borrow_kind: BorrowKind, gen_borrow_kind: BorrowKind,
issued_borrow: &BorrowData<'tcx>, issued_borrow: &BorrowData<'tcx>,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
let issued_spans = self.retrieve_borrow_spans(issued_borrow); let issued_spans = self.retrieve_borrow_spans(issued_borrow);
let issued_span = issued_spans.args_or_use(); let issued_span = issued_spans.args_or_use();
@ -1042,12 +1051,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|kind, var_span| { |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*; use crate::session_diagnostics::CaptureVarCause::*;
match kind { match kind {
Some(_) => BorrowUsePlaceCoroutine { hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
place: desc_place, place: desc_place,
var_span, var_span,
is_single_var: true, is_single_var: true,
}, },
None => BorrowUsePlaceClosure { hir::ClosureKind::Closure => BorrowUsePlaceClosure {
place: desc_place, place: desc_place,
var_span, var_span,
is_single_var: true, 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| { borrow_spans.var_subdiag(None, &mut err, Some(gen_borrow_kind), |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*; use crate::session_diagnostics::CaptureVarCause::*;
match kind { match kind {
Some(_) => BorrowUsePlaceCoroutine { hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
place: desc_place, place: desc_place,
var_span, var_span,
is_single_var: false, is_single_var: false,
}, },
None => { hir::ClosureKind::Closure => {
BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false } BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false }
} }
} }
}); });
} else { } else {
issued_spans.var_subdiag( issued_spans.var_subdiag(
Some(self.infcx.tcx.sess.dcx()), Some(self.dcx()),
&mut err, &mut err,
Some(issued_borrow.kind), Some(issued_borrow.kind),
|kind, var_span| { |kind, var_span| {
@ -1146,23 +1155,29 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let borrow_place = &issued_borrow.borrowed_place; let borrow_place = &issued_borrow.borrowed_place;
let borrow_place_desc = self.describe_any_place(borrow_place.as_ref()); let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
match kind { match kind {
Some(_) => { hir::ClosureKind::Coroutine(_) => {
FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span } 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( borrow_spans.var_subdiag(
Some(self.infcx.tcx.sess.dcx()), Some(self.dcx()),
&mut err, &mut err,
Some(gen_borrow_kind), Some(gen_borrow_kind),
|kind, var_span| { |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*; use crate::session_diagnostics::CaptureVarCause::*;
match kind { match kind {
Some(_) => SecondBorrowUsePlaceCoroutine { place: desc_place, var_span }, hir::ClosureKind::Coroutine(_) => {
None => SecondBorrowUsePlaceClosure { place: desc_place, var_span }, 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; return None;
}; };
debug!("checking call args for uses of inner_param: {:?}", args); 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 { else {
debug!("no uses of inner_param found as a by-move call arg"); 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>, place: Place<'tcx>,
borrowed_place: Place<'tcx>, borrowed_place: Place<'tcx>,
) { ) {
if let ([ProjectionElem::Index(_)], [ProjectionElem::Index(_)]) = let tcx = self.infcx.tcx;
(&place.projection[..], &borrowed_place.projection[..]) 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( let mut note_default_suggestion = || {
"consider using `.split_at_mut(position)` or similar method to obtain \ err.help(
two mutable non-overlapping sub-slices", "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"); )
.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>) { fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
if e.span.contains(self.capture_span) { if e.span.contains(self.capture_span) {
if let hir::ExprKind::Closure(&hir::Closure { if let hir::ExprKind::Closure(&hir::Closure {
movability: None, kind: hir::ClosureKind::Closure,
body, body,
fn_arg_span, fn_arg_span,
fn_decl: hir::FnDecl { inputs, .. }, fn_decl: hir::FnDecl { inputs, .. },
@ -1688,7 +1788,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&& let Some(init) = local.init && let Some(init) = local.init
{ {
if let hir::Expr { if let hir::Expr {
kind: hir::ExprKind::Closure(&hir::Closure { movability: None, .. }), kind:
hir::ExprKind::Closure(&hir::Closure {
kind: hir::ClosureKind::Closure,
..
}),
.. ..
} = init } = init
&& init.span.contains(self.capture_span) && init.span.contains(self.capture_span)
@ -2025,7 +2129,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
drop_span: Span, drop_span: Span,
borrow_spans: UseSpans<'tcx>, borrow_spans: UseSpans<'tcx>,
explanation: BorrowExplanation<'tcx>, explanation: BorrowExplanation<'tcx>,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
debug!( debug!(
"report_local_value_does_not_live_long_enough(\ "report_local_value_does_not_live_long_enough(\
{:?}, {:?}, {:?}, {:?}, {:?}\ {:?}, {:?}, {:?}, {:?}, {:?}\
@ -2200,7 +2304,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&mut self, &mut self,
drop_span: Span, drop_span: Span,
borrow_span: Span, borrow_span: Span,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
debug!( debug!(
"report_thread_local_value_does_not_live_long_enough(\ "report_thread_local_value_does_not_live_long_enough(\
{:?}, {:?}\ {:?}, {:?}\
@ -2208,15 +2312,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
drop_span, borrow_span drop_span, borrow_span
); );
let mut err = self.thread_local_value_does_not_live_long_enough(borrow_span); self.thread_local_value_does_not_live_long_enough(borrow_span)
.with_span_label(
err.span_label( borrow_span,
borrow_span, "thread-local variables cannot be borrowed beyond the end of the function",
"thread-local variables cannot be borrowed beyond the end of the function", )
); .with_span_label(drop_span, "end of enclosing function is here")
err.span_label(drop_span, "end of enclosing function is here");
err
} }
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
@ -2228,7 +2329,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
borrow_spans: UseSpans<'tcx>, borrow_spans: UseSpans<'tcx>,
proper_span: Span, proper_span: Span,
explanation: BorrowExplanation<'tcx>, explanation: BorrowExplanation<'tcx>,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
explanation explanation
{ {
@ -2395,7 +2496,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return_span: Span, return_span: Span,
category: ConstraintCategory<'tcx>, category: ConstraintCategory<'tcx>,
opt_place_desc: Option<&String>, opt_place_desc: Option<&String>,
) -> Option<DiagnosticBuilder<'cx, ErrorGuaranteed>> { ) -> Option<DiagnosticBuilder<'cx>> {
let return_kind = match category { let return_kind = match category {
ConstraintCategory::Return(_) => "return", ConstraintCategory::Return(_) => "return",
ConstraintCategory::Yield => "yield", ConstraintCategory::Yield => "yield",
@ -2490,7 +2591,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
constraint_span: Span, constraint_span: Span,
captured_var: &str, captured_var: &str,
scope: &str, scope: &str,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
let tcx = self.infcx.tcx; let tcx = self.infcx.tcx;
let args_span = use_span.args_or_use(); 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() { let kind = match use_span.coroutine_kind() {
Some(coroutine_kind) => match 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::Block => "gen block",
CoroutineSource::Closure => "gen closure", CoroutineSource::Closure => "gen closure",
CoroutineSource::Fn => { CoroutineSource::Fn => {
bug!("gen block/closure expected, but gen function found.") 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::Block => "async gen block",
CoroutineSource::Closure => "async gen closure", CoroutineSource::Closure => "async gen closure",
CoroutineSource::Fn => { CoroutineSource::Fn => {
bug!("gen block/closure expected, but gen function found.") bug!("gen block/closure expected, but gen function found.")
} }
}, },
CoroutineKind::Async(async_kind) => match async_kind { CoroutineKind::Desugared(CoroutineDesugaring::Async, async_kind) => {
CoroutineSource::Block => "async block", match async_kind {
CoroutineSource::Closure => "async closure", CoroutineSource::Block => "async block",
CoroutineSource::Fn => { CoroutineSource::Closure => "async closure",
bug!("async block/closure expected, but async function found.") CoroutineSource::Fn => {
bug!("async block/closure expected, but async function found.")
}
} }
}, }
CoroutineKind::Coroutine => "coroutine", CoroutineKind::Coroutine(_) => "coroutine",
}, },
None => "closure", None => "closure",
}; };
@ -2566,7 +2669,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} }
ConstraintCategory::CallArgument(_) => { ConstraintCategory::CallArgument(_) => {
fr_name.highlight_region_name(&mut err); 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( err.note(
"async blocks are not executed immediately and must either take a \ "async blocks are not executed immediately and must either take a \
reference or ownership of outside variables they use", reference or ownership of outside variables they use",
@ -2593,7 +2699,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
upvar_span: Span, upvar_span: Span,
upvar_name: Symbol, upvar_name: Symbol,
escape_span: Span, escape_span: Span,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx> {
let tcx = self.infcx.tcx; let tcx = self.infcx.tcx;
let escapes_from = tcx.def_descr(self.mir_def_id().to_def_id()); 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| { loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*; use crate::session_diagnostics::CaptureVarCause::*;
match kind { match kind {
Some(_) => BorrowUseInCoroutine { var_span }, hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
None => BorrowUseInClosure { 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| { loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*; use crate::session_diagnostics::CaptureVarCause::*;
match kind { match kind {
Some(_) => BorrowUseInCoroutine { var_span }, hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
None => BorrowUseInClosure { var_span }, hir::ClosureKind::Closure => BorrowUseInClosure { var_span },
} }
}); });
@ -3052,7 +3158,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
) -> Option<AnnotatedBorrowFnSignature<'tcx>> { ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
// Define a fallback for when we can't match a closure. // Define a fallback for when we can't match a closure.
let fallback = || { 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 { if is_closure {
None None
} else { } else {
@ -3224,7 +3330,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
assigned_to, args assigned_to, args
); );
for operand in 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 { else {
continue; continue;
}; };
@ -3262,7 +3369,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
sig: ty::PolyFnSig<'tcx>, sig: ty::PolyFnSig<'tcx>,
) -> Option<AnnotatedBorrowFnSignature<'tcx>> { ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig); 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_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)?; 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 { } else if let Some(guard) = &arm.guard {
self.errors.push(( self.errors.push((
arm.pat.span.to(guard.body().span), arm.pat.span.to(guard.span),
format!( format!(
"if this pattern and condition are matched, {} is not \ "if this pattern and condition are matched, {} is not \
initialized", initialized",

View File

@ -315,7 +315,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
let mut failed = false; let mut failed = false;
let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| { 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 default = tcx.object_lifetime_default(param.def_id);
let re_static = tcx.lifetimes.re_static; let re_static = tcx.lifetimes.re_static;
@ -339,7 +339,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
has_dyn = true; 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 { } else {
arg arg
} }
@ -691,7 +691,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
); );
// Check if one of the arguments to this function is the target place. // Check if one of the arguments to this function is the target place.
let found_target = args.iter().any(|arg| { 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() { if let Some(potential) = place.as_local() {
potential == target potential == target
} else { } else {

View File

@ -23,6 +23,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_middle::util::{call_kind, CallDesugaringKind}; use rustc_middle::util::{call_kind, CallDesugaringKind};
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult}; use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::Spanned;
use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::abi::{FieldIdx, VariantIdx};
use rustc_trait_selection::infer::InferCtxtExt; 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); debug!("add_moved_or_invoked_closure_note: id={:?}", id);
if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() { if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() {
let closure = match args.first() { let closure = match args.first() {
Some(Operand::Copy(place) | Operand::Move(place)) Some(Spanned {
if target == place.local_or_deref_local() => node: Operand::Copy(place) | Operand::Move(place), ..
{ }) if target == place.local_or_deref_local() => {
place.local_or_deref_local().unwrap() place.local_or_deref_local().unwrap()
} }
_ => return false, _ => return false,
@ -124,7 +125,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let did = did.expect_local(); let did = did.expect_local();
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
diag.eager_subdiagnostic( diag.eager_subdiagnostic(
self.infcx.tcx.sess.dcx(), self.dcx(),
OnClosureNote::InvokedTwice { OnClosureNote::InvokedTwice {
place_name: &ty::place_to_string_for_capture( place_name: &ty::place_to_string_for_capture(
self.infcx.tcx, self.infcx.tcx,
@ -146,7 +147,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let did = did.expect_local(); let did = did.expect_local();
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
diag.eager_subdiagnostic( diag.eager_subdiagnostic(
self.infcx.tcx.sess.dcx(), self.dcx(),
OnClosureNote::MovedTwice { OnClosureNote::MovedTwice {
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place), place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
span: *span, span: *span,
@ -370,7 +371,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
ty::Array(ty, _) | ty::Slice(ty) => { ty::Array(ty, _) | ty::Slice(ty) => {
self.describe_field_from_ty(ty, field, variant_index, including_tuple_field) 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, // We won't be borrowck'ing here if the closure came from another crate,
// so it's safe to call `expect_local`. // 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. /// The access is caused by capturing a variable for a closure.
ClosureUse { ClosureUse {
/// This is true if the captured variable was from a coroutine. /// 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 /// The span of the args of the closure, including the `move` keyword if
/// it's present. /// it's present.
args_span: Span, 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> { pub(super) fn coroutine_kind(self) -> Option<CoroutineKind> {
match self { match self {
UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind, UseSpans::ClosureUse {
closure_kind: hir::ClosureKind::Coroutine(coroutine_kind),
..
} => Some(coroutine_kind),
_ => None, _ => None,
} }
} }
@ -599,9 +604,9 @@ impl UseSpans<'_> {
) { ) {
use crate::InitializationRequiringAction::*; use crate::InitializationRequiringAction::*;
use CaptureVarPathUseCause::*; use CaptureVarPathUseCause::*;
if let UseSpans::ClosureUse { coroutine_kind, path_span, .. } = self { if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self {
match coroutine_kind { match closure_kind {
Some(_) => { hir::ClosureKind::Coroutine(_) => {
err.subdiagnostic(match action { err.subdiagnostic(match action {
Borrow => BorrowInCoroutine { path_span }, Borrow => BorrowInCoroutine { path_span },
MatchOn | Use => UseInCoroutine { path_span }, MatchOn | Use => UseInCoroutine { path_span },
@ -609,7 +614,7 @@ impl UseSpans<'_> {
PartialAssignment => AssignPartInCoroutine { path_span }, PartialAssignment => AssignPartInCoroutine { path_span },
}); });
} }
None => { hir::ClosureKind::Closure => {
err.subdiagnostic(match action { err.subdiagnostic(match action {
Borrow => BorrowInClosure { path_span }, Borrow => BorrowInClosure { path_span },
MatchOn | Use => UseInClosure { path_span }, MatchOn | Use => UseInClosure { path_span },
@ -627,9 +632,9 @@ impl UseSpans<'_> {
dcx: Option<&rustc_errors::DiagCtxt>, dcx: Option<&rustc_errors::DiagCtxt>,
err: &mut Diagnostic, err: &mut Diagnostic,
kind: Option<rustc_middle::mir::BorrowKind>, 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 { if capture_kind_span != path_span {
err.subdiagnostic(match kind { err.subdiagnostic(match kind {
Some(kd) => match kd { Some(kd) => match kd {
@ -645,7 +650,7 @@ impl UseSpans<'_> {
None => CaptureVarKind::Move { kind_span: capture_kind_span }, None => CaptureVarKind::Move { kind_span: capture_kind_span },
}); });
}; };
let diag = f(coroutine_kind, path_span); let diag = f(closure_kind, path_span);
match dcx { match dcx {
Some(hd) => err.eager_subdiagnostic(hd, diag), Some(hd) => err.eager_subdiagnostic(hd, diag),
None => err.subdiagnostic(diag), None => err.subdiagnostic(diag),
@ -656,7 +661,9 @@ impl UseSpans<'_> {
/// Returns `false` if this place is not used in a closure. /// Returns `false` if this place is not used in a closure.
pub(super) fn for_closure(&self) -> bool { pub(super) fn for_closure(&self) -> bool {
match *self { match *self {
UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind.is_none(), UseSpans::ClosureUse { closure_kind, .. } => {
matches!(closure_kind, hir::ClosureKind::Closure)
}
_ => false, _ => false,
} }
} }
@ -664,7 +671,10 @@ impl UseSpans<'_> {
/// Returns `false` if this place is not used in a coroutine. /// Returns `false` if this place is not used in a coroutine.
pub(super) fn for_coroutine(&self) -> bool { pub(super) fn for_coroutine(&self) -> bool {
match *self { 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, _ => false,
} }
} }
@ -783,15 +793,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt); debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind
&& let AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _, _) = && let AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) = **kind
**kind
{ {
debug!("move_spans: def_id={:?} places={:?}", def_id, places); debug!("move_spans: def_id={:?} places={:?}", def_id, places);
let def_id = def_id.expect_local(); 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) 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)) => { | FakeReadCause::ForLet(Some(closure_def_id)) => {
debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place); debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
let places = &[Operand::Move(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)) self.closure_span(closure_def_id, moved_place, IndexSlice::from_raw(places))
{ {
return ClosureUse { return ClosureUse {
coroutine_kind, closure_kind,
args_span, args_span,
capture_kind_span, capture_kind_span,
path_span, path_span,
@ -919,7 +928,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind { if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind {
let (&def_id, is_coroutine) = match kind { let (&def_id, is_coroutine) = match kind {
box AggregateKind::Closure(def_id, _) => (def_id, false), 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, _ => continue,
}; };
let def_id = def_id.expect_local(); let def_id = def_id.expect_local();
@ -928,10 +937,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
"borrow_spans: def_id={:?} is_coroutine={:?} places={:?}", "borrow_spans: def_id={:?} is_coroutine={:?} places={:?}",
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) 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 { } else {
return OtherUse(use_span); return OtherUse(use_span);
} }
@ -953,7 +962,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
def_id: LocalDefId, def_id: LocalDefId,
target_place: PlaceRef<'tcx>, target_place: PlaceRef<'tcx>,
places: &IndexSlice<FieldIdx, Operand<'tcx>>, places: &IndexSlice<FieldIdx, Operand<'tcx>>,
) -> Option<(Span, Option<CoroutineKind>, Span, Span)> { ) -> Option<(Span, hir::ClosureKind, Span, Span)> {
debug!( debug!(
"closure_span: def_id={:?} target_place={:?} places={:?}", "closure_span: def_id={:?} target_place={:?} places={:?}",
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 hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id);
let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); 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 for (captured_place, place) in
self.infcx.tcx.closure_captures(def_id).iter().zip(places) 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() => if target_place == place.as_ref() =>
{ {
debug!("closure_span: found captured local {:?}", place); debug!("closure_span: found captured local {:?}", place);
let body = self.infcx.tcx.hir().body(body);
let coroutine_kind = body.coroutine_kind();
return Some(( return Some((
fn_decl_span, fn_decl_span,
coroutine_kind, kind,
captured_place.get_capture_kind_span(self.infcx.tcx), captured_place.get_capture_kind_span(self.infcx.tcx),
captured_place.get_path_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) && self.infcx.can_eq(self.param_env, ty, self_ty)
{ {
err.eager_subdiagnostic( err.eager_subdiagnostic(
self.infcx.tcx.sess.dcx(), self.dcx(),
CaptureReasonSuggest::FreshReborrow { CaptureReasonSuggest::FreshReborrow {
span: move_span.shrink_to_hi(), span: move_span.shrink_to_hi(),
}, },
@ -1173,9 +1179,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} else { } else {
vec![(move_span.shrink_to_hi(), ".clone()".to_string())] vec![(move_span.shrink_to_hi(), ".clone()".to_string())]
}; };
if let Some(errors) = if let Some(errors) = self.infcx.type_implements_trait_shallow(
self.infcx.could_impl_trait(clone_trait, ty, self.param_env) clone_trait,
&& !has_sugg ty,
self.param_env,
) && !has_sugg
{ {
let msg = match &errors[..] { let msg = match &errors[..] {
[] => "you can `clone` the value and consume it, but this \ [] => "you can `clone` the value and consume it, but this \
@ -1208,7 +1216,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
for error in errors { for error in errors {
if let FulfillmentErrorCode::CodeSelectionError( if let FulfillmentErrorCode::SelectionError(
SelectionError::Unimplemented, SelectionError::Unimplemented,
) = error.code ) = error.code
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait( && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
@ -1242,8 +1250,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// another message for the same span // another message for the same span
if !is_loop_message { if !is_loop_message {
move_spans.var_subdiag(None, err, None, |kind, var_span| match kind { move_spans.var_subdiag(None, err, None, |kind, var_span| match kind {
Some(_) => CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial }, hir::ClosureKind::Coroutine(_) => {
None => CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial }, 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::mir::*;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex}; use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
@ -288,7 +288,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
&mut self, &mut self,
place: Place<'tcx>, place: Place<'tcx>,
span: Span, span: Span,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> { ) -> DiagnosticBuilder<'a> {
let description = if place.projection.len() == 1 { let description = if place.projection.len() == 1 {
format!("static item {}", self.describe_any_place(place.as_ref())) format!("static item {}", self.describe_any_place(place.as_ref()))
} else { } else {
@ -310,7 +310,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
deref_target_place: Place<'tcx>, deref_target_place: Place<'tcx>,
span: Span, span: Span,
use_spans: Option<UseSpans<'tcx>>, use_spans: Option<UseSpans<'tcx>>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> { ) -> DiagnosticBuilder<'a> {
// Inspect the type of the content behind the // Inspect the type of the content behind the
// borrow to provide feedback about why this // borrow to provide feedback about why this
// was a move rather than a copy. // was a move rather than a copy.
@ -329,15 +329,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let PlaceRef { local, projection: [] } = deref_base { if let PlaceRef { local, projection: [] } = deref_base {
let decl = &self.body.local_decls[local]; let decl = &self.body.local_decls[local];
if decl.is_ref_for_guard() { if decl.is_ref_for_guard() {
let mut err = self.cannot_move_out_of( return self
span, .cannot_move_out_of(
&format!("`{}` in pattern guard", self.local_names[local].unwrap()), span,
); &format!("`{}` in pattern guard", self.local_names[local].unwrap()),
err.note( )
"variables bound in patterns cannot be moved from \ .with_note(
until after the end of the pattern guard", "variables bound in patterns cannot be moved from \
); until after the end of the pattern guard",
return err; );
} else if decl.is_ref_to_static() { } else if decl.is_ref_to_static() {
return self.report_cannot_move_from_static(move_place, span); 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, closure_kind_ty, closure_kind, place_description,
); );
let mut diag = self.cannot_move_out_of(span, &place_description); self.cannot_move_out_of(span, &place_description)
.with_span_label(upvar_span, "captured outer variable")
diag.span_label(upvar_span, "captured outer variable"); .with_span_label(
diag.span_label( self.infcx.tcx.def_span(def_id),
self.infcx.tcx.def_span(def_id), format!("captured by this `{closure_kind}` closure"),
format!("captured by this `{closure_kind}` closure"), )
);
diag
} }
_ => { _ => {
let source = self.borrowed_content_source(deref_base); let source = self.borrowed_content_source(deref_base);

View File

@ -1,5 +1,5 @@
use hir::ExprKind; use hir::ExprKind;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::intravisit::Visitor; use rustc_hir::intravisit::Visitor;
use rustc_hir::Node; use rustc_hir::Node;
@ -711,7 +711,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
fn construct_mut_suggestion_for_local_binding_patterns( fn construct_mut_suggestion_for_local_binding_patterns(
&self, &self,
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, err: &mut DiagnosticBuilder<'_>,
local: Local, local: Local,
) { ) {
let local_decl = &self.body.local_decls[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 source = self.body.source;
let hir = self.infcx.tcx.hir(); let hir = self.infcx.tcx.hir();
if let InstanceDef::Item(def_id) = source.instance if let InstanceDef::Item(def_id) = source.instance
&& let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id) && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id)
&& let ExprKind::Closure(closure) = kind && let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind
&& closure.movability == None
&& let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id)
{ {
let mut cur_expr = expr; let mut cur_expr = expr;
@ -1067,12 +1066,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} }
} }
fn suggest_make_local_mut( fn suggest_make_local_mut(&self, err: &mut DiagnosticBuilder<'_>, local: Local, name: Symbol) {
&self,
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
local: Local,
name: Symbol,
) {
let local_decl = &self.body.local_decls[local]; let local_decl = &self.body.local_decls[local];
let (pointer_sigil, pointer_desc) = let (pointer_sigil, pointer_desc) =
@ -1223,19 +1217,22 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
{ {
match self match self
.infcx .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() .as_deref()
{ {
Some([]) => { Some([]) => {
// The type implements Clone. // FIXME: This error message isn't useful, since we're just
err.span_help( // vaguely suggesting to clone a value that already
expr.span, // implements `Clone`.
format!( //
"you can `clone` the `{}` value and consume it, but this \ // A correct suggestion here would take into account the fact
might not be your desired behavior", // that inference may be affected by missing types on bindings,
ty.peel_refs(), // etc., to improve "tests/ui/borrowck/issue-91206.stderr", for
), // example.
);
} }
None => { None => {
if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) = 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. // The type doesn't implement Clone because of unmet obligations.
for error in errors { for error in errors {
if let traits::FulfillmentErrorCode::CodeSelectionError( if let traits::FulfillmentErrorCode::SelectionError(
traits::SelectionError::Unimplemented, traits::SelectionError::Unimplemented,
) = error.code ) = error.code
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait( && 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 // If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a
// list of diagnostics. // list of diagnostics.
let mut diag = if suggested.len() == 1 { 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) => { SuggestedConstraint::Outlives(a, bs) => {
let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect(); let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
format!("add bound `{a}: {}`", bs.join(" + ")) format!("add bound `{a}: {}`", bs.join(" + "))
@ -222,7 +222,6 @@ impl OutlivesSuggestionBuilder {
let mut diag = mbcx let mut diag = mbcx
.infcx .infcx
.tcx .tcx
.sess
.dcx() .dcx()
.struct_help("the following changes may resolve your lifetime errors"); .struct_help("the following changes may resolve your lifetime errors");

View File

@ -3,7 +3,7 @@
//! Error reporting machinery for lifetime errors. //! Error reporting machinery for lifetime errors.
use rustc_data_structures::fx::FxIndexSet; 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 as hir;
use rustc_hir::def::Res::Def; use rustc_hir::def::Res::Def;
use rustc_hir::def_id::DefId; 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::{self, RegionVid, Ty};
use rustc_middle::ty::{Region, TyCtxt}; use rustc_middle::ty::{Region, TyCtxt};
use rustc_span::symbol::{kw, Ident}; use rustc_span::symbol::{kw, Ident};
use rustc_span::{Span, DUMMY_SP}; use rustc_span::Span;
use crate::borrowck_errors; use crate::borrowck_errors;
use crate::session_diagnostics::{ use crate::session_diagnostics::{
@ -84,7 +84,7 @@ impl<'tcx> RegionErrors<'tcx> {
#[track_caller] #[track_caller]
pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) { pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) {
let val = val.into(); 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); self.0.push(val);
} }
pub fn is_empty(&self) -> bool { 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 // and the span which bounded to the trait for adding 'static lifetime suggestion
fn suggest_static_lifetime_for_gat_from_hrtb( fn suggest_static_lifetime_for_gat_from_hrtb(
&self, &self,
diag: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, diag: &mut DiagnosticBuilder<'_>,
lower_bound: RegionVid, lower_bound: RegionVid,
) { ) {
let mut suggestions = vec![]; let mut suggestions = vec![];
@ -327,11 +327,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// to report it; we could probably handle it by // to report it; we could probably handle it by
// iterating over the universal regions and reporting // iterating over the universal regions and reporting
// an error that multiple bounds are required. // an error that multiple bounds are required.
let mut diag = let mut diag = self.dcx().create_err(GenericDoesNotLiveLongEnough {
self.infcx.tcx.sess.create_err(GenericDoesNotLiveLongEnough { kind: type_test.generic_kind.to_string(),
kind: type_test.generic_kind.to_string(), span: type_test_span,
span: type_test_span, });
});
// Add notes and suggestions for the case of 'static lifetime // Add notes and suggestions for the case of 'static lifetime
// implied but not specified when a generic associated types // 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_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
let named_key = self.regioncx.name_regions(self.infcx.tcx, key); let named_key = self.regioncx.name_regions(self.infcx.tcx, key);
let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region); 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, self.infcx.tcx,
span, span,
named_ty, named_ty,
@ -573,7 +572,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
&self, &self,
errci: &ErrorConstraintInfo<'tcx>, errci: &ErrorConstraintInfo<'tcx>,
kind: ReturnConstraint, kind: ReturnConstraint,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
let ErrorConstraintInfo { outlived_fr, span, .. } = errci; let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty; 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 { if let ReturnConstraint::ClosureUpvar(upvar_field) = kind {
let def_id = match self.regioncx.universal_regions().defining_ty { 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( fn report_escaping_data_error(
&self, &self,
errci: &ErrorConstraintInfo<'tcx>, errci: &ErrorConstraintInfo<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx> {
let ErrorConstraintInfo { span, category, .. } = errci; let ErrorConstraintInfo { span, category, .. } = errci;
let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region( 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 /// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
/// | is returning data with lifetime `'b` /// | is returning data with lifetime `'b`
/// ``` /// ```
fn report_general_error( fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> DiagnosticBuilder<'tcx> {
&self,
errci: &ErrorConstraintInfo<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let ErrorConstraintInfo { let ErrorConstraintInfo {
fr, fr,
fr_is_local, 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 mir_def_name = self.infcx.tcx.def_descr(self.mir_def_id().to_def_id());
let err = LifetimeOutliveErr { span: *span }; 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, // In certain scenarios, such as the one described in issue #118021,
// we might encounter a lifetime that cannot be named. // we might encounter a lifetime that cannot be named.
@ -1045,11 +1041,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} }
hir::ExprKind::Closure(hir::Closure { hir::ExprKind::Closure(hir::Closure {
capture_clause: hir::CaptureBy::Ref, capture_clause: hir::CaptureBy::Ref,
body, kind,
.. ..
}) => { }) => {
let body = map.body(*body); if !matches!(
if !matches!(body.coroutine_kind, Some(hir::CoroutineKind::Async(..))) { kind,
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::Async,
_
),)
) {
closure_span = Some(expr.span.shrink_to_lo()); closure_span = Some(expr.span.shrink_to_lo());
} }
} }

View File

@ -188,7 +188,7 @@ impl Display for RegionName {
} }
impl rustc_errors::IntoDiagnosticArg 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() self.to_string().into_diagnostic_arg()
} }
} }
@ -620,7 +620,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
) => { ) => {
// HIR lowering sometimes doesn't catch this in erroneous // HIR lowering sometimes doesn't catch this in erroneous
// programs, so we need to use span_delayed_bug here. See #82126. // 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(), hir_arg.span(),
format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"), 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) { let (return_span, mir_description, hir_ty) = match tcx.hir_node(mir_hir_id) {
hir::Node::Expr(hir::Expr { 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 { 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)), hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)),
}; };
let mir_description = match hir.body(body).coroutine_kind { let mir_description = match kind {
Some(hir::CoroutineKind::Async(src)) => match src { hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineSource::Block => " of async block", hir::CoroutineDesugaring::Async,
hir::CoroutineSource::Closure => " of async closure", hir::CoroutineSource::Block,
hir::CoroutineSource::Fn => { )) => " of async block",
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"
}
},
Some(hir::CoroutineKind::AsyncGen(src)) => match src { hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineSource::Block => " of async gen block", hir::CoroutineDesugaring::Async,
hir::CoroutineSource::Closure => " of async gen closure", hir::CoroutineSource::Closure,
hir::CoroutineSource::Fn => { )) => " of async closure",
let parent_item =
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id); hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
let output = &parent_item hir::CoroutineDesugaring::Async,
.fn_decl() hir::CoroutineSource::Fn,
.expect("coroutine lowered from async gen fn should be in fn") )) => {
.output; let parent_item =
span = output.span(); tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
" of async gen function" 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::Coroutine) => " of coroutine", }
None => " of closure",
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) (span, mir_description, hir_ty)
} }

View File

@ -8,12 +8,9 @@
#![feature(let_chains)] #![feature(let_chains)]
#![feature(min_specialization)] #![feature(min_specialization)]
#![feature(never_type)] #![feature(never_type)]
#![feature(lazy_cell)]
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)] #![feature(stmt_expr_attributes)]
#![feature(trusted_step)]
#![feature(try_blocks)] #![feature(try_blocks)]
#![recursion_limit = "256"]
#[macro_use] #[macro_use]
extern crate rustc_middle; extern crate rustc_middle;
@ -274,11 +271,12 @@ fn do_mir_borrowck<'tcx>(
// The first argument is the coroutine type passed by value // The first argument is the coroutine type passed by value
if let Some(local) = body.local_decls.raw.get(1) if let Some(local) = body.local_decls.raw.get(1)
// Get the interior types and args which typeck computed // 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 true
} else {
false
}; };
for (idx, move_data) in promoted_move_data { 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); 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(); 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); self.consume_operand(loc, (func, span), flow_state);
for arg in args { 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); 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, // moved into the closure and subsequently used by the closure,
// in order to populate our used_mut set. // in order to populate our used_mut set.
match **aggregate_kind { 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 def_id = def_id.expect_local();
let BorrowCheckResult { used_mut_upvars, .. } = let BorrowCheckResult { used_mut_upvars, .. } =
self.infcx.tcx.mir_borrowck(def_id); self.infcx.tcx.mir_borrowck(def_id);
@ -1612,7 +1610,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| ty::FnPtr(_) | ty::FnPtr(_)
| ty::Dynamic(_, _, _) | ty::Dynamic(_, _, _)
| ty::Closure(_, _) | ty::Closure(_, _)
| ty::Coroutine(_, _, _) | ty::Coroutine(_, _)
| ty::CoroutineWitness(..) | ty::CoroutineWitness(..)
| ty::Never | ty::Never
| ty::Tuple(_) | ty::Tuple(_)
@ -1636,7 +1634,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return; return;
} }
} }
ty::Closure(_, _) | ty::Coroutine(_, _, _) | ty::Tuple(_) => (), ty::Closure(_, _) | ty::Coroutine(_, _) | ty::Tuple(_) => (),
ty::Bool ty::Bool
| ty::Char | ty::Char
| ty::Int(_) | ty::Int(_)
@ -2134,7 +2132,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug` // 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 // enabled. We don't want to ICE for that case, as other errors will have
// been emitted (#52262). // been emitted (#52262).
self.infcx.tcx.sess.span_delayed_bug( self.dcx().span_delayed_bug(
span, span,
format!( format!(
"Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible", "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. /// and we want only the best of those errors.
/// ///
/// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the /// 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 /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of
/// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once /// the `Place` of the previous most diagnostic. This happens instead of buffering the
/// all move errors have been reported, any diagnostics in this map are added to the buffer /// error. Once all move errors have been reported, any diagnostics in this map are added
/// to be emitted. /// to the buffer to be emitted.
/// ///
/// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary /// `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 /// 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. /// same primary span come out in a consistent order.
buffered_move_errors: buffered_move_errors:
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>)>, BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>,
buffered_mut_errors: FxIndexMap<Span, (DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)>, buffered_mut_errors: FxIndexMap<Span, (DiagnosticBuilder<'tcx>, usize)>,
/// Diagnostics to be reported buffer. /// 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>, buffered: Vec<Diagnostic>,
/// Set to Some if we emit an error during borrowck /// Set to Some if we emit an error during borrowck
tainted_by_errors: Option<ErrorGuaranteed>, 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 { 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(), t.span.clone_ignoring_labels(),
"diagnostic buffered but not emitted", "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<'_, ()>) { 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) { pub fn set_tainted_by_errors(&mut self, e: ErrorGuaranteed) {
@ -2446,7 +2445,7 @@ mod error {
} }
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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); self.errors.buffer_error(t);
} }
@ -2457,7 +2456,7 @@ mod error {
pub fn buffer_move_error( pub fn buffer_move_error(
&mut self, &mut self,
move_out_indices: Vec<MoveOutIndex>, move_out_indices: Vec<MoveOutIndex>,
place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>), place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>),
) -> bool { ) -> bool {
if let Some((_, diag)) = if let Some((_, diag)) =
self.errors.buffered_move_errors.insert(move_out_indices, place_and_err) self.errors.buffered_move_errors.insert(move_out_indices, place_and_err)
@ -2473,16 +2472,11 @@ mod error {
pub fn get_buffered_mut_error( pub fn get_buffered_mut_error(
&mut self, &mut self,
span: Span, span: Span,
) -> Option<(DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)> { ) -> Option<(DiagnosticBuilder<'tcx>, usize)> {
self.errors.buffered_mut_errors.remove(&span) self.errors.buffered_mut_errors.remove(&span)
} }
pub fn buffer_mut_error( pub fn buffer_mut_error(&mut self, span: Span, t: DiagnosticBuilder<'tcx>, count: usize) {
&mut self,
span: Span,
t: DiagnosticBuilder<'tcx, ErrorGuaranteed>,
count: usize,
) {
self.errors.buffered_mut_errors.insert(span, (t, count)); 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. // Buffer any move errors that we collected and de-duplicated.
for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) { for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
// We have already set tainted for this error, so just buffer it. // 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) { for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
if count > 10 { if count > 10 {
diag.note(format!("...and {} other attempted mutable borrows", 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() { if !self.errors.buffered.is_empty() {
self.errors.buffered.sort_by_key(|diag| diag.sort_span); self.errors.buffered.sort_by_key(|diag| diag.sort_span);
let dcx = self.dcx();
for diag in self.errors.buffered.drain(..) { 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( pub fn has_move_error(
&self, &self,
move_out_indices: &[MoveOutIndex], move_out_indices: &[MoveOutIndex],
) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx, ErrorGuaranteed>)> { ) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx>)> {
self.errors.buffered_move_errors.get(move_out_indices) 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_middle::ty::{self, OpaqueHiddenType, TyCtxt};
use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::move_paths::MoveData;
use rustc_mir_dataflow::points::DenseLocationMap;
use rustc_mir_dataflow::ResultsCursor; use rustc_mir_dataflow::ResultsCursor;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use std::env; use std::env;
@ -27,7 +28,7 @@ use crate::{
facts::{AllFacts, AllFactsExt, RustcFacts}, facts::{AllFacts, AllFactsExt, RustcFacts},
location::LocationTable, location::LocationTable,
polonius, polonius,
region_infer::{values::RegionValueElements, RegionInferenceContext}, region_infer::RegionInferenceContext,
renumber, renumber,
type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}, type_check::{self, MirTypeckRegionConstraints, MirTypeckResults},
universal_regions::UniversalRegions, universal_regions::UniversalRegions,
@ -98,7 +99,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
let universal_regions = Rc::new(universal_regions); 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. // Run the MIR type-checker.
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = 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() { if !nll_errors.is_empty() {
// Suppress unhelpful extra errors in `infer_opaque_types`. // 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, body.span,
"`compute_regions` tainted `infcx` with errors but did not emit any errors", "`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 def_span = tcx.def_span(body.source.def_id());
let mut err = if let Some(closure_region_requirements) = closure_region_requirements { 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); regioncx.annotate(tcx, &mut err);
@ -299,7 +300,7 @@ pub(super) fn dump_annotation<'tcx>(
err err
} else { } 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); regioncx.annotate(tcx, &mut err);
err err

View File

@ -120,7 +120,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> {
} => { } => {
self.consume_operand(location, func); self.consume_operand(location, func);
for arg in args { for arg in args {
self.consume_operand(location, arg); self.consume_operand(location, &arg.node);
} }
self.mutate_place(location, *destination, Deep); 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::ObligationCause;
use rustc_middle::traits::ObligationCauseCode; 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 rustc_span::Span;
use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph}; use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph};
@ -30,8 +31,7 @@ use crate::{
nll::PoloniusOutput, nll::PoloniusOutput,
region_infer::reverse_sccs::ReverseSccGraph, region_infer::reverse_sccs::ReverseSccGraph,
region_infer::values::{ region_infer::values::{
LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues, LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex,
ToElementIndex,
}, },
type_check::{free_region_relations::UniversalRegionRelations, Locations}, type_check::{free_region_relations::UniversalRegionRelations, Locations},
universal_regions::UniversalRegions, universal_regions::UniversalRegions,
@ -330,7 +330,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>, universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
type_tests: Vec<TypeTest<'tcx>>, type_tests: Vec<TypeTest<'tcx>>,
liveness_constraints: LivenessValues, liveness_constraints: LivenessValues,
elements: &Rc<RegionValueElements>, elements: &Rc<DenseLocationMap>,
) -> Self { ) -> Self {
debug!("universal_regions: {:#?}", universal_regions); debug!("universal_regions: {:#?}", universal_regions);
debug!("outlives constraints: {:#?}", outlives_constraints); debug!("outlives constraints: {:#?}", outlives_constraints);
@ -1145,6 +1145,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
} }
let ty = ty.fold_with(&mut OpaqueFolder { tcx }); let ty = ty.fold_with(&mut OpaqueFolder { tcx });
let mut failed = false;
let ty = tcx.fold_regions(ty, |r, _depth| { let ty = tcx.fold_regions(ty, |r, _depth| {
let r_vid = self.to_region_vid(r); 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)) .filter(|&u_r| !self.universal_regions.is_local_free_region(u_r))
.find(|&u_r| self.eval_equal(u_r, r_vid)) .find(|&u_r| self.eval_equal(u_r, r_vid))
.map(|u_r| ty::Region::new_var(tcx, u_r)) .map(|u_r| ty::Region::new_var(tcx, u_r))
// In the case of a failure, use `ReErased`. We will eventually // In case we could not find a named region to map to,
// return `None` in this case. // we will return `None` below.
.unwrap_or(tcx.lifetimes.re_erased) .unwrap_or_else(|| {
failed = true;
r
})
}); });
debug!("try_promote_type_test_subject: folded ty = {:?}", ty); debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
// This will be true if we failed to promote some region. // This will be true if we failed to promote some region.
if ty.has_erased_regions() { if failed {
return None; return None;
} }

View File

@ -402,7 +402,7 @@ fn check_opaque_type_parameter_valid(
let opaque_param = opaque_generics.param_at(i, tcx); let opaque_param = opaque_generics.param_at(i, tcx);
let kind = opaque_param.kind.descr(); let kind = opaque_param.kind.descr();
return Err(tcx.sess.emit_err(NonGenericOpaqueTypeParam { return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam {
ty: arg, ty: arg,
kind, kind,
span, span,
@ -419,9 +419,9 @@ fn check_opaque_type_parameter_valid(
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
.collect(); .collect();
return Err(tcx return Err(tcx
.sess .dcx()
.struct_span_err(span, "non-defining opaque type use in defining scope") .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()); .emit());
} }
} }

View File

@ -1,101 +1,18 @@
#![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)] #![deny(rustc::diagnostic_outside_of_impl)]
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_index::bit_set::SparseBitMatrix; use rustc_index::bit_set::SparseBitMatrix;
use rustc_index::interval::IntervalSet; use rustc_index::interval::IntervalSet;
use rustc_index::interval::SparseIntervalMatrix; use rustc_index::interval::SparseIntervalMatrix;
use rustc_index::Idx; use rustc_index::Idx;
use rustc_index::IndexVec; use rustc_middle::mir::{BasicBlock, Location};
use rustc_middle::mir::{BasicBlock, Body, Location};
use rustc_middle::ty::{self, RegionVid}; use rustc_middle::ty::{self, RegionVid};
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
use std::fmt::Debug; use std::fmt::Debug;
use std::rc::Rc; use std::rc::Rc;
use crate::dataflow::BorrowIndex; use crate::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 {}
}
rustc_index::newtype_index! { rustc_index::newtype_index! {
/// A single integer representing a `ty::Placeholder`. /// 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. /// an interval matrix storing liveness ranges for each region-vid.
pub(crate) struct LivenessValues { pub(crate) struct LivenessValues {
/// The map from locations to points. /// 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. /// 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 /// When using `-Zpolonius=next`, for each point: the loans flowing into the live regions at
/// that point. /// that point.
@ -155,24 +79,52 @@ impl LiveLoans {
impl LivenessValues { impl LivenessValues {
/// Create an empty map of regions to locations where they're live. /// 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 { 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, elements,
loans: None, loans: None,
} }
} }
/// Iterate through each region that has a value in this set. /// Iterate through each region that has a value in this set.
pub(crate) fn regions(&self) -> impl Iterator<Item = RegionVid> { pub(crate) fn regions(&self) -> impl Iterator<Item = RegionVid> + '_ {
self.points.rows() 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`. /// Records `region` as being live at the given `location`.
pub(crate) fn add_location(&mut self, region: RegionVid, location: 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); 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. // When available, record the loans flowing into this region as live at the given point.
if let Some(loans) = self.loans.as_mut() { if let Some(loans) = self.loans.as_mut() {
@ -185,7 +137,13 @@ impl LivenessValues {
/// Records `region` as being live at all the given `points`. /// Records `region` as being live at all the given `points`.
pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet<PointIndex>) { pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet<PointIndex>) {
debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points); 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. // When available, record the loans flowing into this region as live at the given points.
if let Some(loans) = self.loans.as_mut() { 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. /// Records `region` as being live at all the control-flow points.
pub(crate) fn add_all_points(&mut self, region: RegionVid) { 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`. /// Returns whether `region` is marked live at the given `location`.
pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool { pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
let point = self.elements.point_from_location(location); let point = self.elements.point_from_location(location);
self.points.row(region).is_some_and(|r| r.contains(point)) if let Some(points) = &self.points {
} points.row(region).is_some_and(|r| r.contains(point))
} else {
/// Returns whether `region` is marked live at any location. unreachable!(
pub(crate) fn is_live_anywhere(&self, region: RegionVid) -> bool { "Should be using LivenessValues::with_specific_points to ask whether live at a location"
self.live_points(region).next().is_some() )
}
} }
/// Returns an iterator of all the points where `region` is live. /// Returns an iterator of all the points where `region` is live.
fn live_points(&self, region: RegionVid) -> impl Iterator<Item = PointIndex> + '_ { 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) .row(region)
.into_iter() .into_iter()
.flat_map(|set| set.iter()) .flat_map(|set| set.iter())
@ -298,7 +266,7 @@ impl PlaceholderIndices {
/// it would also contain various points from within the function. /// it would also contain various points from within the function.
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct RegionValues<N: Idx> { pub(crate) struct RegionValues<N: Idx> {
elements: Rc<RegionValueElements>, elements: Rc<DenseLocationMap>,
placeholder_indices: Rc<PlaceholderIndices>, placeholder_indices: Rc<PlaceholderIndices>,
points: SparseIntervalMatrix<N, PointIndex>, points: SparseIntervalMatrix<N, PointIndex>,
free_regions: SparseBitMatrix<N, RegionVid>, 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 /// Each of the regions in num_region_variables will be initialized with an
/// empty set of points and no causal information. /// empty set of points and no causal information.
pub(crate) fn new( pub(crate) fn new(
elements: &Rc<RegionValueElements>, elements: &Rc<DenseLocationMap>,
num_universal_regions: usize, num_universal_regions: usize,
placeholder_indices: &Rc<PlaceholderIndices>, placeholder_indices: &Rc<PlaceholderIndices>,
) -> Self { ) -> Self {
let num_placeholders = placeholder_indices.len(); let num_placeholders = placeholder_indices.len();
Self { Self {
elements: elements.clone(), elements: elements.clone(),
points: SparseIntervalMatrix::new(elements.num_points), points: SparseIntervalMatrix::new(elements.num_points()),
placeholder_indices: placeholder_indices.clone(), placeholder_indices: placeholder_indices.clone(),
free_regions: SparseBitMatrix::new(num_universal_regions), free_regions: SparseBitMatrix::new(num_universal_regions),
placeholders: SparseBitMatrix::new(num_placeholders), 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 /// elements for the region `from` from `values` and add them to
/// the region `to` in `self`. /// the region `to` in `self`.
pub(crate) fn merge_liveness(&mut self, to: N, from: RegionVid, values: &LivenessValues) { 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); 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. /// For debugging purposes, returns a pretty-printed string of the given points.
pub(crate) fn pretty_print_points( pub(crate) fn pretty_print_points(
elements: &RegionValueElements, elements: &DenseLocationMap,
points: impl IntoIterator<Item = PointIndex>, points: impl IntoIterator<Item = PointIndex>,
) -> String { ) -> String {
pretty_print_region_elements( 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_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{GenericArg, Ty}; use rustc_middle::ty::{GenericArg, Ty};
use rustc_span::Span; use rustc_span::Span;
@ -6,7 +6,7 @@ use rustc_span::Span;
use crate::diagnostics::RegionName; use crate::diagnostics::RegionName;
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(borrowck_move_unsized, code = "E0161")] #[diag(borrowck_move_unsized, code = E0161)]
pub(crate) struct MoveUnsized<'tcx> { pub(crate) struct MoveUnsized<'tcx> {
pub ty: Ty<'tcx>, pub ty: Ty<'tcx>,
#[primary_span] #[primary_span]
@ -281,7 +281,7 @@ pub(crate) enum CaptureVarCause {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(borrowck_cannot_move_when_borrowed, code = "E0505")] #[diag(borrowck_cannot_move_when_borrowed, code = E0505)]
pub(crate) struct MoveBorrow<'a> { pub(crate) struct MoveBorrow<'a> {
pub place: &'a str, pub place: &'a str,
pub borrow_place: &'a str, pub borrow_place: &'a str,
@ -294,7 +294,7 @@ pub(crate) struct MoveBorrow<'a> {
} }
#[derive(Diagnostic)] #[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(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
pub ty: GenericArg<'tcx>, pub ty: GenericArg<'tcx>,
pub kind: &'a str, 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. /// our special inference variable there, we would mess that up.
region_bound_pairs: &'a RegionBoundPairs<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>, implicit_region_bound: ty::Region<'tcx>,
param_env: ty::ParamEnv<'tcx>, known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
locations: Locations, locations: Locations,
span: Span, span: Span,
category: ConstraintCategory<'tcx>, category: ConstraintCategory<'tcx>,
@ -47,7 +47,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
universal_regions: &'a UniversalRegions<'tcx>, universal_regions: &'a UniversalRegions<'tcx>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>, implicit_region_bound: ty::Region<'tcx>,
param_env: ty::ParamEnv<'tcx>, known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
locations: Locations, locations: Locations,
span: Span, span: Span,
category: ConstraintCategory<'tcx>, category: ConstraintCategory<'tcx>,
@ -59,7 +59,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
universal_regions, universal_regions,
region_bound_pairs, region_bound_pairs,
implicit_region_bound, implicit_region_bound,
param_env, known_type_outlives_obligations,
locations, locations,
span, span,
category, category,
@ -136,7 +136,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
// Extract out various useful fields we'll need below. // Extract out various useful fields we'll need below.
let ConstraintConversion { let ConstraintConversion {
tcx, region_bound_pairs, implicit_region_bound, param_env, .. tcx,
region_bound_pairs,
implicit_region_bound,
known_type_outlives_obligations,
..
} = *self; } = *self;
let ty::OutlivesPredicate(k1, r2) = predicate; let ty::OutlivesPredicate(k1, r2) = predicate;
@ -157,7 +161,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
tcx, tcx,
region_bound_pairs, region_bound_pairs,
Some(implicit_region_bound), Some(implicit_region_bound),
param_env, known_type_outlives_obligations,
) )
.type_must_outlive(origin, t1, r2, constraint_category); .type_must_outlive(origin, t1, r2, constraint_category);
} }

View File

@ -1,5 +1,6 @@
use rustc_data_structures::frozen::Frozen; use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder}; use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
use rustc_hir::def::DefKind;
use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives; use rustc_infer::infer::outlives;
use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::outlives::env::RegionBoundPairs;
@ -44,12 +45,14 @@ type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
pub(crate) struct CreateResult<'tcx> { pub(crate) struct CreateResult<'tcx> {
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
pub(crate) region_bound_pairs: RegionBoundPairs<'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) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
} }
pub(crate) fn create<'tcx>( pub(crate) fn create<'tcx>(
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
implicit_region_bound: ty::Region<'tcx>, implicit_region_bound: ty::Region<'tcx>,
universal_regions: &Rc<UniversalRegions<'tcx>>, universal_regions: &Rc<UniversalRegions<'tcx>>,
constraints: &mut MirTypeckRegionConstraints<'tcx>, constraints: &mut MirTypeckRegionConstraints<'tcx>,
@ -57,6 +60,7 @@ pub(crate) fn create<'tcx>(
UniversalRegionRelationsBuilder { UniversalRegionRelationsBuilder {
infcx, infcx,
param_env, param_env,
known_type_outlives_obligations,
implicit_region_bound, implicit_region_bound,
constraints, constraints,
universal_regions: universal_regions.clone(), universal_regions: universal_regions.clone(),
@ -174,6 +178,7 @@ impl UniversalRegionRelations<'_> {
struct UniversalRegionRelationsBuilder<'this, 'tcx> { struct UniversalRegionRelationsBuilder<'this, 'tcx> {
infcx: &'this InferCtxt<'tcx>, infcx: &'this InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
universal_regions: Rc<UniversalRegions<'tcx>>, universal_regions: Rc<UniversalRegions<'tcx>>,
implicit_region_bound: ty::Region<'tcx>, implicit_region_bound: ty::Region<'tcx>,
constraints: &'this mut MirTypeckRegionConstraints<'tcx>, constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
@ -195,9 +200,12 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
pub(crate) fn create(mut self) -> CreateResult<'tcx> { 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; let param_env = self.param_env;
self.add_outlives_bounds(outlives::explicit_outlives_bounds(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); 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 { for c in constraints {
self.push_region_constraints(c, span); self.push_region_constraints(c, span);
} }
@ -285,6 +313,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
outlives: self.outlives.freeze(), outlives: self.outlives.freeze(),
inverse_outlives: self.inverse_outlives.freeze(), inverse_outlives: self.inverse_outlives.freeze(),
}), }),
known_type_outlives_obligations: self.known_type_outlives_obligations,
region_bound_pairs: self.region_bound_pairs, region_bound_pairs: self.region_bound_pairs,
normalized_inputs_and_output, normalized_inputs_and_output,
} }
@ -299,7 +328,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
&self.universal_regions, &self.universal_regions,
&self.region_bound_pairs, &self.region_bound_pairs,
self.implicit_region_bound, self.implicit_region_bound,
self.param_env, self.known_type_outlives_obligations,
Locations::All(span), Locations::All(span),
span, span,
ConstraintCategory::Internal, ConstraintCategory::Internal,

View File

@ -7,6 +7,7 @@
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
//! contain revealed `impl Trait` values). //! contain revealed `impl Trait` values).
use itertools::Itertools;
use rustc_infer::infer::BoundRegionConversionTime; use rustc_infer::infer::BoundRegionConversionTime;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
@ -22,7 +23,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
#[instrument(skip(self, body), level = "debug")] #[instrument(skip(self, body), level = "debug")]
pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) { pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
let mir_def_id = body.source.def_id().expect_local(); 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; return;
} }
let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id); 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, user_provided_sig,
); );
for (&user_ty, arg_decl) in user_provided_sig.inputs().iter().zip( let is_coroutine_with_implicit_resume_ty = self.tcx().is_coroutine(mir_def_id.to_def_id())
// In MIR, closure args begin with an implicit `self`. Skip it! && user_provided_sig.inputs().is_empty();
body.args_iter().skip(1).map(|local| &body.local_decls[local]),
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( self.ascribe_user_type_skip_wf(
arg_decl.ty, 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() { for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
if argument_index + 1 >= body.local_decls.len() { if argument_index + 1 >= body.local_decls.len() {
self.tcx() self.tcx()
.sess .dcx()
.span_delayed_bug(body.span, "found more normalized_input_ty than local_decls"); .span_delayed_bug(body.span, "found more normalized_input_ty than local_decls");
break; break;
} }
@ -94,31 +101,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
); );
} }
debug!( if let Some(mir_yield_ty) = body.yield_ty() {
"equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}", let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
body.yield_ty(), self.equate_normalized_input_or_output(
universal_regions.yield_ty universal_regions.yield_ty.unwrap(),
); mir_yield_ty,
yield_span,
// 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), Some(ur_yield_ty)) = if let Some(mir_resume_ty) = body.resume_ty() {
(body.yield_ty(), universal_regions.yield_ty)
{
let yield_span = body.local_decls[RETURN_PLACE].source_info.span; 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. // 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_index::IndexVec;
use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::{Body, Local, Location}; use rustc_middle::mir::{Body, Local, Location};
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
use crate::def_use::{self, DefUse}; 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 /// A map that cross references each local with the locations where it
/// is defined (assigned), used, or dropped. Used during liveness /// is defined (assigned), used, or dropped. Used during liveness
@ -60,7 +60,7 @@ impl vll::LinkElem for Appearance {
impl LocalUseMap { impl LocalUseMap {
pub(crate) fn build( pub(crate) fn build(
live_locals: &[Local], live_locals: &[Local],
elements: &RegionValueElements, elements: &DenseLocationMap,
body: &Body<'_>, body: &Body<'_>,
) -> Self { ) -> Self {
let nones = IndexVec::from_elem(None, &body.local_decls); let nones = IndexVec::from_elem(None, &body.local_decls);
@ -103,7 +103,7 @@ impl LocalUseMap {
struct LocalUseMapBuild<'me> { struct LocalUseMapBuild<'me> {
local_use_map: &'me mut LocalUseMap, 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 // Vector used in `visit_local` to signal which `Local`s do we need
// def/use/drop information on, constructed from `live_locals` (that // def/use/drop information on, constructed from `live_locals` (that
@ -144,7 +144,7 @@ impl LocalUseMapBuild<'_> {
} }
fn insert( fn insert(
elements: &RegionValueElements, elements: &DenseLocationMap,
first_appearance: &mut Option<AppearanceIndex>, first_appearance: &mut Option<AppearanceIndex>,
appearances: &mut IndexVec<AppearanceIndex, Appearance>, appearances: &mut IndexVec<AppearanceIndex, Appearance>,
location: Location, 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_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt};
use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::move_paths::MoveData;
use rustc_mir_dataflow::points::DenseLocationMap;
use rustc_mir_dataflow::ResultsCursor; use rustc_mir_dataflow::ResultsCursor;
use std::rc::Rc; use std::rc::Rc;
@ -13,7 +14,7 @@ use crate::{
constraints::OutlivesConstraintSet, constraints::OutlivesConstraintSet,
facts::{AllFacts, AllFactsExt}, facts::{AllFacts, AllFactsExt},
location::LocationTable, location::LocationTable,
region_infer::values::{LivenessValues, RegionValueElements}, region_infer::values::LivenessValues,
universal_regions::UniversalRegions, universal_regions::UniversalRegions,
}; };
@ -34,7 +35,7 @@ mod trace;
pub(super) fn generate<'mir, 'tcx>( pub(super) fn generate<'mir, 'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>, typeck: &mut TypeChecker<'_, 'tcx>,
body: &Body<'tcx>, body: &Body<'tcx>,
elements: &Rc<RegionValueElements>, elements: &Rc<DenseLocationMap>,
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
move_data: &MoveData<'tcx>, move_data: &MoveData<'tcx>,
location_table: &LocationTable, location_table: &LocationTable,
@ -183,6 +184,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'cx, 'tcx> {
match ty_context { match ty_context {
TyContext::ReturnTy(SourceInfo { span, .. }) TyContext::ReturnTy(SourceInfo { span, .. })
| TyContext::YieldTy(SourceInfo { span, .. }) | TyContext::YieldTy(SourceInfo { span, .. })
| TyContext::ResumeTy(SourceInfo { span, .. })
| TyContext::UserTy(span) | TyContext::UserTy(span)
| TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => { | TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => {
span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context); 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::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::WithSuccessors; 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_index::interval::IntervalSet;
use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::for_liveness; use rustc_infer::infer::outlives::for_liveness;
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
use rustc_middle::traits::query::DropckOutlivesResult; use rustc_middle::traits::query::DropckOutlivesResult;
use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; 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 rustc_mir_dataflow::ResultsCursor;
use crate::{ use crate::{
region_infer::values::{self, LiveLoans, PointIndex, RegionValueElements}, region_infer::values::{self, LiveLoans},
type_check::liveness::local_use_map::LocalUseMap, type_check::liveness::local_use_map::LocalUseMap,
type_check::liveness::polonius, type_check::liveness::polonius,
type_check::NormalizeLocation, type_check::NormalizeLocation,
@ -41,7 +42,7 @@ use crate::{
pub(super) fn trace<'mir, 'tcx>( pub(super) fn trace<'mir, 'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>, typeck: &mut TypeChecker<'_, 'tcx>,
body: &Body<'tcx>, body: &Body<'tcx>,
elements: &Rc<RegionValueElements>, elements: &Rc<DenseLocationMap>,
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
move_data: &MoveData<'tcx>, move_data: &MoveData<'tcx>,
relevant_live_locals: Vec<Local>, relevant_live_locals: Vec<Local>,
@ -105,7 +106,7 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
typeck: &'me mut TypeChecker<'typeck, 'tcx>, typeck: &'me mut TypeChecker<'typeck, 'tcx>,
/// Defines the `PointIndex` mapping /// Defines the `PointIndex` mapping
elements: &'me RegionValueElements, elements: &'me DenseLocationMap,
/// MIR we are analyzing. /// MIR we are analyzing.
body: &'me Body<'tcx>, body: &'me Body<'tcx>,
@ -134,7 +135,7 @@ struct LivenessResults<'me, 'typeck, 'flow, 'tcx> {
cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>, cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>,
/// Set of points that define the current local. /// Set of points that define the current local.
defs: HybridBitSet<PointIndex>, defs: BitSet<PointIndex>,
/// Points where the current variable is "use live" -- meaning /// Points where the current variable is "use live" -- meaning
/// that there is a future "full use" that may use its value. /// 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(); let num_points = cx.elements.num_points();
LivenessResults { LivenessResults {
cx, cx,
defs: HybridBitSet::new_empty(num_points), defs: BitSet::new_empty(num_points),
use_live_at: IntervalSet::new(num_points), use_live_at: IntervalSet::new(num_points),
drop_live_at: IntervalSet::new(num_points), drop_live_at: IntervalSet::new(num_points),
drop_locations: vec![], drop_locations: vec![],
@ -570,7 +571,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
} }
fn make_all_regions_live( fn make_all_regions_live(
elements: &RegionValueElements, elements: &DenseLocationMap,
typeck: &mut TypeChecker<'_, 'tcx>, typeck: &mut TypeChecker<'_, 'tcx>,
value: impl TypeVisitable<TyCtxt<'tcx>>, value: impl TypeVisitable<TyCtxt<'tcx>>,
live_at: &IntervalSet<PointIndex>, live_at: &IntervalSet<PointIndex>,

View File

@ -35,7 +35,9 @@ use rustc_middle::ty::{
OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
}; };
use rustc_middle::ty::{GenericArgsRef, UserArgs}; use rustc_middle::ty::{GenericArgsRef, UserArgs};
use rustc_mir_dataflow::points::DenseLocationMap;
use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
@ -58,9 +60,7 @@ use crate::{
location::LocationTable, location::LocationTable,
member_constraints::MemberConstraintSet, member_constraints::MemberConstraintSet,
path_utils, path_utils,
region_infer::values::{ region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices},
LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
},
region_infer::TypeTest, region_infer::TypeTest,
type_check::free_region_relations::{CreateResult, UniversalRegionRelations}, type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
universal_regions::{DefiningTy, UniversalRegions}, universal_regions::{DefiningTy, UniversalRegions},
@ -133,7 +133,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
all_facts: &mut Option<AllFacts>, all_facts: &mut Option<AllFacts>,
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
move_data: &MoveData<'tcx>, move_data: &MoveData<'tcx>,
elements: &Rc<RegionValueElements>, elements: &Rc<DenseLocationMap>,
upvars: &[&ty::CapturedPlace<'tcx>], upvars: &[&ty::CapturedPlace<'tcx>],
use_polonius: bool, use_polonius: bool,
) -> MirTypeckResults<'tcx> { ) -> MirTypeckResults<'tcx> {
@ -141,7 +141,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
let mut constraints = MirTypeckRegionConstraints { let mut constraints = MirTypeckRegionConstraints {
placeholder_indices: PlaceholderIndices::default(), placeholder_indices: PlaceholderIndices::default(),
placeholder_index_to_region: IndexVec::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(), outlives_constraints: OutlivesConstraintSet::default(),
member_constraints: MemberConstraintSet::default(), member_constraints: MemberConstraintSet::default(),
type_tests: Vec::default(), type_tests: Vec::default(),
@ -152,9 +152,14 @@ pub(crate) fn type_check<'mir, 'tcx>(
universal_region_relations, universal_region_relations,
region_bound_pairs, region_bound_pairs,
normalized_inputs_and_output, normalized_inputs_and_output,
known_type_outlives_obligations,
} = free_region_relations::create( } = free_region_relations::create(
infcx, infcx,
param_env, 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, implicit_region_bound,
universal_regions, universal_regions,
&mut constraints, &mut constraints,
@ -176,6 +181,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
body, body,
param_env, param_env,
&region_bound_pairs, &region_bound_pairs,
known_type_outlives_obligations,
implicit_region_bound, implicit_region_bound,
&mut borrowck_context, &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); let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind()); trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind());
if hidden_type.has_non_region_infer() { 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, decl.hidden_type.span,
format!("could not resolve {:#?}", hidden_type.ty.kind()), 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 // We sometimes see MIR failures (notably predicate failures) due to
// the fact that we check rvalue sized predicates here. So use `span_delayed_bug` // the fact that we check rvalue sized predicates here. So use `span_delayed_bug`
// to avoid reporting bugs in those cases. // to avoid reporting bugs in those cases.
tcx.sess.dcx().span_delayed_bug(span, msg); tcx.dcx().span_delayed_bug(span, msg);
} }
enum FieldAccessError { enum FieldAccessError {
@ -406,6 +412,16 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
instantiated_predicates, instantiated_predicates,
locations, 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 all_facts = &mut None;
let mut constraints = Default::default(); let mut constraints = Default::default();
let mut liveness_constraints = 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 // Don't try to add borrow_region facts for the promoted MIR
let mut swap_constraints = |this: &mut Self| { 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) 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,
// 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
// then add a liveness constraint to the main MIR for this region // at the location provided as an argument to this method
// at the location provided as an argument to this method //
if liveness_constraints.is_live_anywhere(region) { // add_location doesn't care about ordering so not a problem for the live regions to be
self.cx // unordered.
.borrowck_context #[allow(rustc::potential_query_instability)]
.constraints for region in liveness_constraints.live_regions_unordered() {
.liveness_constraints self.cx
.add_location(region, location); .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 { let (variant, args) = match base_ty {
PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() { PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() {
ty::Adt(adt_def, args) => (adt_def.variant(variant_index), args), 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 mut variants = args.as_coroutine().state_tys(def_id, tcx);
let Some(mut variant) = variants.nth(variant_index.into()) else { let Some(mut variant) = variants.nth(variant_index.into()) else {
bug!( 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 // Only prefix fields (upvars and current state) are
// accessible without a variant index. // accessible without a variant index.
return match args.as_coroutine().prefix_tys().get(field.index()) { return match args.as_coroutine().prefix_tys().get(field.index()) {
@ -838,6 +856,7 @@ struct TypeChecker<'a, 'tcx> {
/// all of the promoted items. /// all of the promoted items.
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>,
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
implicit_region_bound: ty::Region<'tcx>, implicit_region_bound: ty::Region<'tcx>,
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
@ -988,6 +1007,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
body: &'a Body<'tcx>, body: &'a Body<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>,
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
implicit_region_bound: ty::Region<'tcx>, implicit_region_bound: ty::Region<'tcx>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
) -> Self { ) -> Self {
@ -998,6 +1018,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
user_type_annotations: &body.user_type_annotations, user_type_annotations: &body.user_type_annotations,
param_env, param_env,
region_bound_pairs, region_bound_pairs,
known_type_outlives_obligations,
implicit_region_bound, implicit_region_bound,
borrowck_context, borrowck_context,
reported_errors: Default::default(), reported_errors: Default::default(),
@ -1067,7 +1088,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
); );
if result.is_err() { if result.is_err() {
self.infcx.tcx.sess.span_delayed_bug( self.infcx.dcx().span_delayed_bug(
self.body.span, self.body.span,
"failed re-defining predefined opaques in mir typeck", "failed re-defining predefined opaques in mir typeck",
); );
@ -1087,10 +1108,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn check_user_type_annotations(&mut self) { fn check_user_type_annotations(&mut self) {
debug!(?self.user_type_annotations); debug!(?self.user_type_annotations);
let tcx = self.tcx();
for user_annotation in self.user_type_annotations { for user_annotation in self.user_type_annotations {
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty); 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.borrowck_context.universal_regions,
self.region_bound_pairs, self.region_bound_pairs,
self.implicit_region_bound, self.implicit_region_bound,
self.param_env, self.known_type_outlives_obligations,
locations, locations,
locations.span(self.body), locations.span(self.body),
category, category,
@ -1183,6 +1211,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Ok(()) 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> { fn tcx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx self.infcx.tcx
} }
@ -1359,7 +1417,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
TerminatorKind::Call { func, args, destination, call_source, target, .. } => { TerminatorKind::Call { func, args, destination, call_source, target, .. } => {
self.check_operand(func, term_location); self.check_operand(func, term_location);
for arg in args { for arg in args {
self.check_operand(arg, term_location); self.check_operand(&arg.node, term_location);
} }
let func_ty = func.ty(body, tcx); 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); self.check_operand(value, term_location);
let value_ty = value.ty(body, tcx);
match body.yield_ty() { match body.yield_ty() {
None => span_mirbug!(self, term, "yield in non-coroutine"), None => span_mirbug!(self, term, "yield in non-coroutine"),
Some(ty) => { Some(ty) => {
let value_ty = value.ty(body, tcx);
if let Err(terr) = self.sub_types( if let Err(terr) = self.sub_types(
value_ty, value_ty,
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>, term: &Terminator<'tcx>,
func: &Operand<'tcx>, func: &Operand<'tcx>,
sig: &ty::FnSig<'tcx>, sig: &ty::FnSig<'tcx>,
args: &[Operand<'tcx>], args: &[Spanned<Operand<'tcx>>],
term_location: Location, term_location: Location,
call_source: CallSource, call_source: CallSource,
) { ) {
@ -1571,9 +1651,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if self.tcx().is_intrinsic(def_id) { if self.tcx().is_intrinsic(def_id) {
match self.tcx().item_name(def_id) { match self.tcx().item_name(def_id) {
sym::simd_shuffle => { sym::simd_shuffle => {
if !matches!(args[2], Operand::Constant(_)) { if !matches!(args[2], Spanned { node: Operand::Constant(_), .. }) {
self.tcx() self.tcx()
.sess .dcx()
.emit_err(SimdShuffleLastConst { span: term.source_info.span }); .emit_err(SimdShuffleLastConst { span: term.source_info.span });
} }
} }
@ -1584,7 +1664,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
debug!(?func_ty); debug!(?func_ty);
for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() { 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 op_arg_ty = self.normalize(op_arg_ty, term_location);
let category = if call_source.from_hir_call() { 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 // While this is located in `nll::typeck` this error is not
// an NLL error, it's a required check to prevent creation // an NLL error, it's a required check to prevent creation
// of unsized rvalues in a call expression. // 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; // It doesn't make sense to look at a field beyond the prefix;
// these require a variant index, and are not initialized in // these require a variant index, and are not initialized in
// aggregate rvalues. // aggregate rvalues.
@ -1817,7 +1897,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let def_id = uv.def; let def_id = uv.def;
if tcx.def_kind(def_id) == DefKind::InlineConst { if tcx.def_kind(def_id) == DefKind::InlineConst {
let def_id = def_id.expect_local(); 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( self.normalize_and_prove_instantiated_predicates(
def_id.to_def_id(), def_id.to_def_id(),
predicates, predicates,
@ -2392,7 +2477,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
AggregateKind::Array(_) => None, AggregateKind::Array(_) => None,
AggregateKind::Tuple => None, AggregateKind::Tuple => None,
AggregateKind::Closure(_, _) => 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 // desugaring. A closure gets desugared to a struct, and
// these extra requirements are basically like where // these extra requirements are basically like where
// clauses on the struct. // clauses on the struct.
AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args, _) => { AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => (
(def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location)) def_id,
} self.prove_closure_bounds(
tcx,
def_id.expect_local(),
args,
location.to_locations(),
),
),
AggregateKind::Array(_) | AggregateKind::Tuple => { AggregateKind::Array(_) | AggregateKind::Tuple => {
(CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty()) (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty())
@ -2641,7 +2732,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def_id: LocalDefId, def_id: LocalDefId,
args: GenericArgsRef<'tcx>, args: GenericArgsRef<'tcx>,
location: Location, locations: Locations,
) -> ty::InstantiatedPredicates<'tcx> { ) -> ty::InstantiatedPredicates<'tcx> {
if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements { if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements {
constraint_conversion::ConstraintConversion::new( constraint_conversion::ConstraintConversion::new(
@ -2649,8 +2740,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.borrowck_context.universal_regions, self.borrowck_context.universal_regions,
self.region_bound_pairs, self.region_bound_pairs,
self.implicit_region_bound, self.implicit_region_bound,
self.param_env, self.known_type_outlives_obligations,
location.to_locations(), locations,
DUMMY_SP, // irrelevant; will be overridden. DUMMY_SP, // irrelevant; will be overridden.
ConstraintCategory::Boring, // same as above. ConstraintCategory::Boring, // same as above.
self.borrowck_context.constraints, self.borrowck_context.constraints,
@ -2676,7 +2767,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if let Err(_) = self.eq_args( if let Err(_) = self.eq_args(
typeck_root_args, typeck_root_args,
parent_args, parent_args,
location.to_locations(), locations,
ConstraintCategory::BoringNoLocation, ConstraintCategory::BoringNoLocation,
) { ) {
span_mirbug!( span_mirbug!(

View File

@ -14,7 +14,6 @@
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Diagnostic; use rustc_errors::Diagnostic;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_hir::BodyOwnerKind; use rustc_hir::BodyOwnerKind;
@ -77,6 +76,8 @@ pub struct UniversalRegions<'tcx> {
pub unnormalized_input_tys: &'tcx [Ty<'tcx>], pub unnormalized_input_tys: &'tcx [Ty<'tcx>],
pub yield_ty: Option<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 /// 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 /// The MIR is a coroutine. The signature is that coroutines take
/// no parameters and return the result of /// no parameters and return the result of
/// `ClosureArgs::coroutine_return_ty`. /// `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 /// 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. /// 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>> { pub fn upvar_tys(self) -> &'tcx ty::List<Ty<'tcx>> {
match self { match self {
DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(), 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(..) => { DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
ty::List::empty() ty::List::empty()
} }
@ -354,7 +355,7 @@ impl<'tcx> UniversalRegions<'tcx> {
err.note(format!("late-bound region is {:?}", self.to_region_vid(r))); 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!( let v = with_no_trimmed_paths!(
args[tcx.generics_of(def_id).parent_count..] args[tcx.generics_of(def_id).parent_count..]
.iter() .iter()
@ -526,9 +527,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
debug!("build: extern regions = {}..{}", first_extern_index, first_local_index); debug!("build: extern regions = {}..{}", first_extern_index, first_local_index);
debug!("build: local regions = {}..{}", first_local_index, num_universals); debug!("build: local regions = {}..{}", first_local_index, num_universals);
let yield_ty = match defining_ty { let (resume_ty, yield_ty) = match defining_ty {
DefiningTy::Coroutine(_, args, _) => Some(args.as_coroutine().yield_ty()), DefiningTy::Coroutine(_, args) => {
_ => None, let tys = args.as_coroutine();
(Some(tys.resume_ty()), Some(tys.yield_ty()))
}
_ => (None, None),
}; };
UniversalRegions { UniversalRegions {
@ -542,6 +546,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
unnormalized_output_ty: *unnormalized_output_ty, unnormalized_output_ty: *unnormalized_output_ty,
unnormalized_input_tys, unnormalized_input_tys,
yield_ty, yield_ty,
resume_ty,
} }
} }
@ -562,9 +567,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
match *defining_ty.kind() { match *defining_ty.kind() {
ty::Closure(def_id, args) => DefiningTy::Closure(def_id, args), ty::Closure(def_id, args) => DefiningTy::Closure(def_id, args),
ty::Coroutine(def_id, args, movability) => { ty::Coroutine(def_id, args) => DefiningTy::Coroutine(def_id, args),
DefiningTy::Coroutine(def_id, args, movability)
}
ty::FnDef(def_id, args) => DefiningTy::FnDef(def_id, args), ty::FnDef(def_id, args) => DefiningTy::FnDef(def_id, args),
_ => span_bug!( _ => span_bug!(
tcx.def_span(self.mir_def), 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 identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
let fr_args = match defining_ty { let fr_args = match defining_ty {
DefiningTy::Closure(_, args) DefiningTy::Closure(_, args)
| DefiningTy::Coroutine(_, args, _) | DefiningTy::Coroutine(_, args)
| DefiningTy::InlineConst(_, args) => { | DefiningTy::InlineConst(_, args) => {
// In the case of closures, we rely on the fact that // In the case of closures, we rely on the fact that
// the first N elements in the ClosureArgs are // the first N elements in the ClosureArgs are
@ -665,7 +668,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
kind: ty::BrEnv, kind: ty::BrEnv,
}; };
let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); 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 // The "inputs" of the closure in the
// signature appear as a tuple. The MIR side // 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); assert_eq!(self.mir_def.to_def_id(), def_id);
let resume_ty = args.as_coroutine().resume_ty(); let resume_ty = args.as_coroutine().resume_ty();
let output = args.as_coroutine().return_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 = let inputs_and_output =
self.infcx.tcx.mk_type_list(&[coroutine_ty, resume_ty, output]); self.infcx.tcx.mk_type_list(&[coroutine_ty, resume_ty, output]);
ty::Binder::dummy(inputs_and_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)) (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
} else { } else {
ecx.sess.dcx().emit_err(errors::AllocErrorMustBeFn { span: item.span() }); ecx.dcx().emit_err(errors::AllocErrorMustBeFn { span: item.span() });
return vec![orig_item]; return vec![orig_item];
}; };

View File

@ -422,7 +422,7 @@ fn parse_reg<'a>(
ast::InlineAsmRegOrRegClass::Reg(symbol) ast::InlineAsmRegOrRegClass::Reg(symbol)
} }
_ => { _ => {
return Err(p.sess.create_err(errors::ExpectedRegisterClassOrExplicitRegister { return Err(p.dcx().create_err(errors::ExpectedRegisterClassOrExplicitRegister {
span: p.token.span, 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) { match expr_to_spanned_string(ecx, template_expr, msg) {
Ok(template_part) => template_part, Ok(template_part) => template_part,
Err(err) => { Err(err) => {
if let Some((mut err, _)) = err { if let Some((err, _)) = err {
err.emit(); err.emit();
} }
return None; 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 = parser.errors.remove(0);
let err_sp = template_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); 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 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"); e.span_label(err_sp, err.label + " in asm template string");
if let Some(note) = err.note { if let Some(note) = err.note {
e.note(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) || args.reg_args.contains(idx)
{ {
let msg = format!("invalid reference to argument at index {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"); err.span_label(span, "from here");
let positional_args = args.operands.len() let positional_args = args.operands.len()
@ -625,12 +625,13 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
None => { None => {
let msg = format!("there is no argument named `{name}`"); let msg = format!("there is no argument named `{name}`");
let span = arg.position_span; let span = arg.position_span;
ecx.struct_span_err( ecx.dcx()
template_span .struct_span_err(
.from_inner(InnerSpan::new(span.start, span.end)), template_span
msg, .from_inner(InnerSpan::new(span.start, span.end)),
) msg,
.emit(); )
.emit();
None None
} }
} }
@ -645,7 +646,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
.ty_span .ty_span
.map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end))) .map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end)))
.unwrap_or(template_sp); .unwrap_or(template_sp);
ecx.emit_err(errors::AsmModifierInvalid { span }); ecx.dcx().emit_err(errors::AsmModifierInvalid { span });
modifier = None; modifier = None;
} }
@ -692,16 +693,17 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
0 => {} 0 => {}
1 => { 1 => {
let (sp, msg) = unused_operands.into_iter().next().unwrap(); let (sp, msg) = unused_operands.into_iter().next().unwrap();
let mut err = ecx.struct_span_err(sp, msg); ecx.dcx()
err.span_label(sp, msg); .struct_span_err(sp, msg)
err.help(format!( .with_span_label(sp, msg)
"if this argument is intentionally unused, \ .with_help(format!(
consider using it in an asm comment: `\"/*{help_str} */\"`" "if this argument is intentionally unused, \
)); consider using it in an asm comment: `\"/*{help_str} */\"`"
err.emit(); ))
.emit();
} }
_ => { _ => {
let mut err = ecx.struct_span_err( let mut err = ecx.dcx().struct_span_err(
unused_operands.iter().map(|&(sp, _)| sp).collect::<Vec<Span>>(), unused_operands.iter().map(|&(sp, _)| sp).collect::<Vec<Span>>(),
"multiple unused asm arguments", "multiple unused asm arguments",
); );
@ -746,7 +748,7 @@ pub(super) fn expand_asm<'cx>(
}; };
MacEager::expr(expr) MacEager::expr(expr)
} }
Err(mut err) => { Err(err) => {
err.emit(); err.emit();
DummyResult::any(sp) DummyResult::any(sp)
} }
@ -778,7 +780,7 @@ pub(super) fn expand_global_asm<'cx>(
DummyResult::any(sp) DummyResult::any(sp)
} }
} }
Err(mut err) => { Err(err) => {
err.emit(); err.emit();
DummyResult::any(sp) DummyResult::any(sp)
} }

View File

@ -22,7 +22,7 @@ pub fn expand_assert<'cx>(
) -> Box<dyn MacResult + 'cx> { ) -> Box<dyn MacResult + 'cx> {
let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) { let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) {
Ok(assert) => assert, Ok(assert) => assert,
Err(mut err) => { Err(err) => {
err.emit(); err.emit();
return DummyResult::any(span); 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); let mut parser = cx.new_parser_from_tts(stream);
if parser.token == token::Eof { 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()?; 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. // Emit an error about semicolon and suggest removing it.
if parser.token == token::Semi { 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(); parser.bump();
} }
@ -141,7 +141,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes
let custom_message = let custom_message =
if let token::Literal(token::Lit { kind: token::Str, .. }) = parser.token.kind { if let token::Literal(token::Lit { kind: token::Str, .. }) = parser.token.kind {
let comma = parser.prev_token.span.shrink_to_hi(); 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) parse_custom_message(&mut parser)
} else if parser.eat(&token::Comma) { } else if parser.eat(&token::Comma) {

View File

@ -303,7 +303,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
| ExprKind::Continue(_) | ExprKind::Continue(_)
| ExprKind::Err | ExprKind::Err
| ExprKind::Field(_, _) | ExprKind::Field(_, _)
| ExprKind::ForLoop(_, _, _, _) | ExprKind::ForLoop { .. }
| ExprKind::FormatArgs(_) | ExprKind::FormatArgs(_)
| ExprKind::IncludedBytes(..) | ExprKind::IncludedBytes(..)
| ExprKind::InlineAsm(_) | ExprKind::InlineAsm(_)

View File

@ -22,13 +22,13 @@ pub fn expand_cfg(
Ok(cfg) => { Ok(cfg) => {
let matches_cfg = attr::cfg_matches( let matches_cfg = attr::cfg_matches(
&cfg, &cfg,
&cx.sess.parse_sess, &cx.sess,
cx.current_expansion.lint_node_id, cx.current_expansion.lint_node_id,
Some(cx.ecfg.features), Some(cx.ecfg.features),
); );
MacEager::expr(cx.expr_bool(sp, matches_cfg)) MacEager::expr(cx.expr_bool(sp, matches_cfg))
} }
Err(mut err) => { Err(err) => {
err.emit(); err.emit();
DummyResult::any(sp) 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); let mut p = cx.new_parser_from_tts(tts);
if p.token == token::Eof { 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()?; 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); let _ = p.eat(&token::Comma);
if !p.eat(&token::Eof) { if !p.eat(&token::Eof) {
return Err(cx.create_err(errors::OneCfgPattern { span })); return Err(cx.dcx().create_err(errors::OneCfgPattern { span }));
} }
Ok(cfg) 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() { match mi.meta_item_list() {
None => {} None => {}
Some([]) => { Some([]) => {
ecx.emit_err(UnspecifiedPath(mi.span)); ecx.dcx().emit_err(UnspecifiedPath(mi.span));
} }
Some([_, .., l]) => { Some([_, .., l]) => {
ecx.emit_err(MultiplePaths(l.span())); ecx.dcx().emit_err(MultiplePaths(l.span()));
} }
Some([nmi]) => match nmi.meta_item() { Some([nmi]) => match nmi.meta_item() {
None => { None => {
ecx.emit_err(LiteralPath(nmi.span())); ecx.dcx().emit_err(LiteralPath(nmi.span()));
} }
Some(mi) => { Some(mi) => {
if !mi.is_word() { if !mi.is_word() {
ecx.emit_err(HasArguments(mi.span)); ecx.dcx().emit_err(HasArguments(mi.span));
} }
return Some(&mi.path); return Some(&mi.path);
} }
@ -61,7 +61,7 @@ impl MultiItemModifier for Expander {
Ok(true) => ExpandResult::Ready(vec![item]), Ok(true) => ExpandResult::Ready(vec![item]),
Ok(false) => ExpandResult::Ready(Vec::new()), Ok(false) => ExpandResult::Ready(Vec::new()),
Err(Indeterminate) if ecx.force_mode => { Err(Indeterminate) if ecx.force_mode => {
ecx.emit_err(errors::CfgAccessibleIndeterminate { span }); ecx.dcx().emit_err(errors::CfgAccessibleIndeterminate { span });
ExpandResult::Ready(vec![item]) ExpandResult::Ready(vec![item])
} }
Err(Indeterminate) => ExpandResult::Retry(item), Err(Indeterminate) => ExpandResult::Retry(item),

View File

@ -200,7 +200,7 @@ impl CfgEval<'_, '_> {
parser.capture_cfg = true; parser.capture_cfg = true;
match parse_annotatable_with(&mut parser) { match parse_annotatable_with(&mut parser) {
Ok(a) => annotatable = a, Ok(a) => annotatable = a,
Err(mut err) => { Err(err) => {
err.emit(); err.emit();
return Some(annotatable); 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 start_span = parser.token.span;
let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) { let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) {
Ok(ai) => ai, Ok(ai) => ai,
Err(mut err) => { Err(err) => {
err.emit(); err.emit();
continue; continue;
} }

View File

@ -18,7 +18,7 @@ pub fn expand_compile_error<'cx>(
reason = "diagnostic message is specified by user" reason = "diagnostic message is specified by user"
)] )]
#[expect(rustc::untranslatable_diagnostic, 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) DummyResult::any(sp)
} }

View File

@ -33,11 +33,11 @@ pub fn expand_concat(
accumulator.push_str(&b.to_string()); accumulator.push_str(&b.to_string());
} }
Ok(ast::LitKind::CStr(..)) => { Ok(ast::LitKind::CStr(..)) => {
cx.emit_err(errors::ConcatCStrLit { span: e.span }); cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span });
has_errors = true; has_errors = true;
} }
Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => { 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; has_errors = true;
} }
Ok(ast::LitKind::Err) => { Ok(ast::LitKind::Err) => {
@ -63,7 +63,7 @@ pub fn expand_concat(
} }
} }
ast::ExprKind::IncludedBytes(..) => { ast::ExprKind::IncludedBytes(..) => {
cx.emit_err(errors::ConcatBytestr { span: e.span }); cx.dcx().emit_err(errors::ConcatBytestr { span: e.span });
} }
ast::ExprKind::Err => { ast::ExprKind::Err => {
has_errors = true; has_errors = true;
@ -75,7 +75,7 @@ pub fn expand_concat(
} }
if !missing_literal.is_empty() { 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); return DummyResult::any(sp);
} else if has_errors { } else if has_errors {
return DummyResult::any(sp); return DummyResult::any(sp);

View File

@ -17,16 +17,17 @@ fn invalid_type_err(
ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob, ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob,
}; };
let snippet = cx.sess.source_map().span_to_snippet(span).ok(); let snippet = cx.sess.source_map().span_to_snippet(span).ok();
let dcx = cx.dcx();
match ast::LitKind::from_token_lit(token_lit) { match ast::LitKind::from_token_lit(token_lit) {
Ok(ast::LitKind::CStr(_, _)) => { Ok(ast::LitKind::CStr(_, _)) => {
// FIXME(c_str_literals): should concatenation of C string literals // Avoid ambiguity in handling of terminal `NUL` by refusing to
// include the null bytes in the end? // concatenate C string literals as bytes.
cx.emit_err(errors::ConcatCStrLit { span: span }); dcx.emit_err(errors::ConcatCStrLit { span: span });
} }
Ok(ast::LitKind::Char(_)) => { Ok(ast::LitKind::Char(_)) => {
let sugg = let sugg =
snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet }); 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(_, _)) => { Ok(ast::LitKind::Str(_, _)) => {
// suggestion would be invalid if we are nested // suggestion would be invalid if we are nested
@ -35,29 +36,29 @@ fn invalid_type_err(
} else { } else {
None None
}; };
cx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }); dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg });
} }
Ok(ast::LitKind::Float(_, _)) => { 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(_)) => { 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::Err) => {}
Ok(ast::LitKind::Int(_, _)) if !is_nested => { Ok(ast::LitKind::Int(_, _)) if !is_nested => {
let sugg = let sugg =
snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet }); 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( Ok(ast::LitKind::Int(
val, val,
ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
)) => { )) => {
assert!(val > u8::MAX.into()); // must be an error assert!(val.get() > u8::MAX.into()); // must be an error
cx.emit_err(ConcatBytesOob { span }); dcx.emit_err(ConcatBytesOob { span });
} }
Ok(ast::LitKind::Int(_, _)) => { Ok(ast::LitKind::Int(_, _)) => {
cx.emit_err(ConcatBytesNonU8 { span }); dcx.emit_err(ConcatBytesNonU8 { span });
} }
Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(), Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(),
Err(err) => { Err(err) => {
@ -72,10 +73,11 @@ fn handle_array_element(
missing_literals: &mut Vec<rustc_span::Span>, missing_literals: &mut Vec<rustc_span::Span>,
expr: &P<rustc_ast::Expr>, expr: &P<rustc_ast::Expr>,
) -> Option<u8> { ) -> Option<u8> {
let dcx = cx.dcx();
match expr.kind { match expr.kind {
ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => { ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => {
if !*has_errors { 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; *has_errors = true;
None None
@ -84,12 +86,12 @@ fn handle_array_element(
Ok(ast::LitKind::Int( Ok(ast::LitKind::Int(
val, val,
ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), 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::Byte(val)) => Some(val),
Ok(ast::LitKind::ByteStr(..)) => { Ok(ast::LitKind::ByteStr(..)) => {
if !*has_errors { 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; *has_errors = true;
None None
@ -104,7 +106,7 @@ fn handle_array_element(
}, },
ast::ExprKind::IncludedBytes(..) => { ast::ExprKind::IncludedBytes(..) => {
if !*has_errors { 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; *has_errors = true;
None None
@ -146,12 +148,12 @@ pub fn expand_concat_bytes(
if let Some(elem) = if let Some(elem) =
handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) 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); accumulator.push(elem);
} }
} }
} else { } 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) { &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() { 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)); return base::MacEager::expr(DummyResult::raw_expr(sp, true));
} else if has_errors { } else if has_errors {
return base::MacEager::expr(DummyResult::raw_expr(sp, true)); return base::MacEager::expr(DummyResult::raw_expr(sp, true));

View File

@ -14,7 +14,7 @@ pub fn expand_concat_idents<'cx>(
tts: TokenStream, tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> { ) -> Box<dyn base::MacResult + 'cx> {
if tts.is_empty() { if tts.is_empty() {
cx.emit_err(errors::ConcatIdentsMissingArgs { span: sp }); cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp });
return DummyResult::any(sp); return DummyResult::any(sp);
} }
@ -24,7 +24,7 @@ pub fn expand_concat_idents<'cx>(
match e { match e {
TokenTree::Token(Token { kind: token::Comma, .. }, _) => {} 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); 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); return DummyResult::any(sp);
} }
} }

View File

@ -120,7 +120,7 @@ fn report_bad_target(
let bad_target = let bad_target =
!matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..))); !matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..)));
if bad_target { 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(()) Ok(())
} }
@ -134,7 +134,7 @@ fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) {
} }
_ => errors::BadDeriveLitHelp::Other, _ => 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) { 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 { match meta.kind {
MetaItemKind::Word => {} MetaItemKind::Word => {}
MetaItemKind::List(..) => { MetaItemKind::List(..) => {
sess.emit_err(errors::DerivePathArgsList { span }); sess.dcx().emit_err(errors::DerivePathArgsList { span });
} }
MetaItemKind::NameValue(..) => { 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) 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 { let trait_def = TraitDef {
@ -144,7 +144,7 @@ fn cs_clone_simple(
process_variant(&variant.data); process_variant(&variant.data);
} }
} }
_ => cx.span_bug( _ => cx.dcx().span_bug(
trait_span, trait_span,
format!("unexpected substructure in simple `derive({name})`"), format!("unexpected substructure in simple `derive({name})`"),
), ),
@ -180,10 +180,10 @@ fn cs_clone(
vdata = &variant.data; vdata = &variant.data;
} }
EnumTag(..) | AllFieldlessEnum(..) => { 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(..) => { 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() .iter()
.map(|field| { .map(|field| {
let Some(ident) = field.name else { let Some(ident) = field.name else {
cx.span_bug( cx.dcx().span_bug(
trait_span, trait_span,
format!("unnamed field in normal struct in `derive({name})`",), 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 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 { let trait_def = TraitDef {
span, span,
path: path_std!(cmp::Eq), path: path_std!(cmp::Eq),
@ -99,7 +86,7 @@ fn cs_total_eq_assert(
process_variant(&variant.data); 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) 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 { |cx, fold| match fold {
CsFold::Single(field) => { CsFold::Single(field) => {
let [other_expr] = &field.other_selflike_exprs[..] else { 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()]; let args = thin_vec![field.self_expr.clone(), other_expr.clone()];
cx.expr_call_global(field.span, cmp_path.clone(), args) 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 { |cx, fold| match fold {
CsFold::Single(field) => { CsFold::Single(field) => {
let [other_expr] = &field.other_selflike_exprs[..] else { 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 // 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 { |cx, fold| match fold {
CsFold::Single(field) => { CsFold::Single(field) => {
let [other_expr] = &field.other_selflike_exprs[..] else { 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()]; let args = thin_vec![field.self_expr.clone(), other_expr.clone()];
cx.expr_call_global(field.span, partial_cmp_path.clone(), args) 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), EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr), AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr),
EnumTag(..) | StaticStruct(..) | StaticEnum(..) => { 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) BlockOrExpr::new_expr(expr)
} }

View File

@ -41,7 +41,7 @@ pub fn expand_deriving_default(
default_struct_substructure(cx, trait_span, substr, fields) default_struct_substructure(cx, trait_span, substr, fields)
} }
StaticEnum(enum_def, _) => default_enum_substructure(cx, trait_span, enum_def), 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 let suggs = possible_defaults
.map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident }) .map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident })
.collect(); .collect();
cx.emit_err(errors::NoDefaultVariant { span: trait_span, suggs }); cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, suggs });
return Err(()); return Err(());
} }
@ -140,7 +140,7 @@ fn extract_default_variant<'a>(
.then_some(errors::MultipleDefaultsSugg { spans, ident: variant.ident }) .then_some(errors::MultipleDefaultsSugg { spans, ident: variant.ident })
}) })
.collect(); .collect();
cx.emit_err(errors::MultipleDefaults { cx.dcx().emit_err(errors::MultipleDefaults {
span: trait_span, span: trait_span,
first: first.span, first: first.span,
additional: rest.iter().map(|v| v.span).collect(), additional: rest.iter().map(|v| v.span).collect(),
@ -151,12 +151,12 @@ fn extract_default_variant<'a>(
}; };
if !matches!(variant.data, VariantData::Unit(..)) { 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(()); return Err(());
} }
if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) { 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, span: variant.ident.span,
non_exhaustive: non_exhaustive_attr.span, non_exhaustive: non_exhaustive_attr.span,
}); });
@ -176,14 +176,14 @@ fn validate_default_attribute(
let attr = match attrs.as_slice() { let attr = match attrs.as_slice() {
[attr] => attr, [attr] => attr,
[] => cx.bug( [] => cx.dcx().bug(
"this method must only be called with a variant that has a `#[default]` attribute", "this method must only be called with a variant that has a `#[default]` attribute",
), ),
[first, rest @ ..] => { [first, rest @ ..] => {
let sugg = errors::MultipleDefaultAttrsSugg { let sugg = errors::MultipleDefaultAttrsSugg {
spans: rest.iter().map(|attr| attr.span).collect(), spans: rest.iter().map(|attr| attr.span).collect(),
}; };
cx.emit_err(errors::MultipleDefaultAttrs { cx.dcx().emit_err(errors::MultipleDefaultAttrs {
span: default_variant.ident.span, span: default_variant.ident.span,
first: first.span, first: first.span,
first_rest: rest[0].span, first_rest: rest[0].span,
@ -196,7 +196,7 @@ fn validate_default_attribute(
} }
}; };
if !attr.is_word() { if !attr.is_word() {
cx.emit_err(errors::DefaultHasArg { span: attr.span }); cx.dcx().emit_err(errors::DefaultHasArg { span: attr.span });
return Err(()); return Err(());
} }
@ -210,7 +210,7 @@ struct DetectNonVariantDefaultAttr<'a, 'b> {
impl<'a, 'b> rustc_ast::visit::Visitor<'a> for 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) { fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) {
if attr.has_name(kw::Default) { 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); rustc_ast::visit::walk_attribute(self, attr);

View File

@ -296,6 +296,6 @@ fn encodable_substructure(
BlockOrExpr::new_mixed(thin_vec![me], Some(expr)) 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) { 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, is_packed,
) )
} else { } else {
cx.emit_err(errors::DeriveUnion { span: mitem.span }); cx.dcx().emit_err(errors::DeriveUnion { span: mitem.span });
return; return;
} }
} }
@ -974,7 +974,7 @@ impl<'a> MethodDef<'a> {
match ty { match ty {
// Selflike (`&Self`) arguments only occur in non-static methods. // Selflike (`&Self`) arguments only occur in non-static methods.
Ref(box Self_, _) if !self.is_static() => selflike_args.push(arg_expr), 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), _ => nonselflike_args.push(arg_expr),
} }
} }
@ -1441,9 +1441,9 @@ impl<'a> TraitDef<'a> {
let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..)); let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
match (just_spans.is_empty(), named_idents.is_empty()) { match (just_spans.is_empty(), named_idents.is_empty()) {
(false, false) => { (false, false) => cx
cx.span_bug(self.span, "a struct with named and unnamed fields in generic `derive`") .dcx()
} .span_bug(self.span, "a struct with named and unnamed fields in generic `derive`"),
// named fields // named fields
(_, false) => Named(named_idents), (_, false) => Named(named_idents),
// unnamed fields // unnamed fields
@ -1489,7 +1489,7 @@ impl<'a> TraitDef<'a> {
let field_pats = pieces_iter let field_pats = pieces_iter
.map(|(sp, ident, pat)| { .map(|(sp, ident, pat)| {
if ident.is_none() { if ident.is_none() {
cx.span_bug( cx.dcx().span_bug(
sp, sp,
"a braced struct with unnamed fields in `derive`", "a braced struct with unnamed fields in `derive`",
); );
@ -1707,7 +1707,9 @@ where
tag_check_expr tag_check_expr
} }
} }
StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"), StaticEnum(..) | StaticStruct(..) => {
AllFieldlessEnum(..) => cx.span_bug(trait_span, "fieldless enum in `derive`"), 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) cx.path_all(span, false, vec![self_ty], params)
} }
Path(p) => p.to_path(cx, span, self_ty, generics), Path(p) => p.to_path(cx, span, self_ty, generics),
Ref(..) => cx.span_bug(span, "ref in a path in generic `derive`"), Ref(..) => cx.dcx().span_bug(span, "ref in a path in generic `derive`"),
Unit => cx.span_bug(span, "unit 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<'_>, substr: &Substructure<'_>,
) -> BlockOrExpr { ) -> BlockOrExpr {
let [state_expr] = substr.nonselflike_args else { 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 call_hash = |span, expr| {
let hash_path = { let hash_path = {
@ -75,7 +75,7 @@ fn hash_substructure(
let stmts = thin_vec![call_hash(tag_field.span, tag_field.self_expr.clone())]; let stmts = thin_vec![call_hash(tag_field.span, tag_field.self_expr.clone())];
(stmts, match_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) 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) { if let Some(value) = cx.sess.opts.logical_env.get(var) {
return Some(Symbol::intern(value)); 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. // from rustc's environment.
env::var(var).ok().as_deref().map(Symbol::intern) env::var(var).ok().as_deref().map(Symbol::intern)
} }
@ -66,7 +66,7 @@ pub fn expand_env<'cx>(
) -> Box<dyn base::MacResult + 'cx> { ) -> Box<dyn base::MacResult + 'cx> {
let mut exprs = match get_exprs_from_tts(cx, tts) { let mut exprs = match get_exprs_from_tts(cx, tts) {
Some(exprs) if exprs.is_empty() || exprs.len() > 2 => { 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); return DummyResult::any(sp);
} }
None => 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 { 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()) { } else if is_cargo_env_var(var.as_str()) {
cx.emit_err(errors::EnvNotDefined::CargoEnvVar { cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar {
span, span,
var: *symbol, var: *symbol,
var_expr: var_expr.ast_deref(), var_expr: var_expr.ast_deref(),
}); });
} else { } else {
cx.emit_err(errors::EnvNotDefined::CustomEnvVar { cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar {
span, span,
var: *symbol, var: *symbol,
var_expr: var_expr.ast_deref(), var_expr: var_expr.ast_deref(),

View File

@ -1,6 +1,6 @@
use rustc_errors::{ use rustc_errors::{
AddToDiagnostic, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan, codes::*, AddToDiagnostic, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic,
SingleLabelManySpans, Level, MultiSpan, SingleLabelManySpans,
}; };
use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{symbol::Ident, Span, Symbol}; use rustc_span::{symbol::Ident, Span, Symbol};
@ -269,7 +269,7 @@ pub(crate) struct ConcatIdentsIdentArgs {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(builtin_macros_bad_derive_target, code = "E0774")] #[diag(builtin_macros_bad_derive_target, code = E0774)]
pub(crate) struct BadDeriveTarget { pub(crate) struct BadDeriveTarget {
#[primary_span] #[primary_span]
#[label] #[label]
@ -283,7 +283,7 @@ pub(crate) struct BadDeriveTarget {
pub(crate) struct TestsNotSupport {} pub(crate) struct TestsNotSupport {}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(builtin_macros_unexpected_lit, code = "E0777")] #[diag(builtin_macros_unexpected_lit, code = E0777)]
pub(crate) struct BadDeriveLit { pub(crate) struct BadDeriveLit {
#[primary_span] #[primary_span]
#[label] #[label]
@ -446,15 +446,15 @@ pub(crate) struct EnvNotDefinedWithUserMessage {
} }
// Hand-written implementation to support custom user messages. // 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] #[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( #[expect(
rustc::untranslatable_diagnostic, rustc::untranslatable_diagnostic,
reason = "cannot translate user-provided messages" reason = "cannot translate user-provided messages"
)] )]
let mut diag = dcx.struct_err(self.msg_from_user.to_string()); let mut diag = DiagnosticBuilder::new(dcx, level, self.msg_from_user.to_string());
diag.set_span(self.span); diag.span(self.span);
diag diag
} }
} }
@ -618,7 +618,7 @@ impl AddToDiagnostic for FormatUnusedArg {
rustc_errors::SubdiagnosticMessage, rustc_errors::SubdiagnosticMessage,
) -> 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()); let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
diag.span_label(self.span, msg); diag.span_label(self.span, msg);
} }
@ -801,22 +801,25 @@ pub(crate) struct AsmClobberNoReg {
pub(crate) clobbers: Vec<Span>, pub(crate) clobbers: Vec<Span>,
} }
impl<'a> IntoDiagnostic<'a> for AsmClobberNoReg { impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg {
fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
let mut diag = dcx.struct_err(crate::fluent_generated::builtin_macros_asm_clobber_no_reg);
diag.set_span(self.spans.clone());
// eager translation as `span_labels` takes `AsRef<str>` // eager translation as `span_labels` takes `AsRef<str>`
let lbl1 = dcx.eagerly_translate_to_string( let lbl1 = dcx.eagerly_translate_to_string(
crate::fluent_generated::builtin_macros_asm_clobber_abi, crate::fluent_generated::builtin_macros_asm_clobber_abi,
[].into_iter(), [].into_iter(),
); );
diag.span_labels(self.clobbers, &lbl1);
let lbl2 = dcx.eagerly_translate_to_string( let lbl2 = dcx.eagerly_translate_to_string(
crate::fluent_generated::builtin_macros_asm_clobber_outputs, crate::fluent_generated::builtin_macros_asm_clobber_outputs,
[].into_iter(), [].into_iter(),
); );
diag.span_labels(self.spans, &lbl2); DiagnosticBuilder::new(
diag 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, FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait,
}; };
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{ use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan, PResult, SingleLabelManySpans};
Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, PResult, SingleLabelManySpans,
};
use rustc_expand::base::{self, *}; use rustc_expand::base::{self, *};
use rustc_parse_format as parse; use rustc_parse_format as parse;
use rustc_span::symbol::{Ident, Symbol}; 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); let mut p = ecx.new_parser_from_tts(tts);
if p.token == token::Eof { 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; 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) { match p.expect(&token::Comma) {
Err(mut err) => { Err(err) => {
match token::TokenKind::Comma.similar_tokens() { match token::TokenKind::Comma.similar_tokens() {
Some(tks) if tks.contains(&p.token.kind) => { Some(tks) if tks.contains(&p.token.kind) => {
// If a similar token is found, then it may be a typo. We // 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)?; p.expect(&token::Eq)?;
let expr = p.parse_expr()?; let expr = p.parse_expr()?;
if let Some((_, prev)) = args.by_name(ident.name) { if let Some((_, prev)) = args.by_name(ident.name) {
ecx.emit_err(errors::FormatDuplicateArg { ecx.dcx().emit_err(errors::FormatDuplicateArg {
span: ident.span, span: ident.span,
prev: prev.kind.ident().unwrap().span, prev: prev.kind.ident().unwrap().span,
duplicate: ident.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()?; let expr = p.parse_expr()?;
if !args.named_args().is_empty() { if !args.named_args().is_empty() {
ecx.emit_err(errors::PositionalAfterNamed { return Err(ecx.dcx().create_err(errors::PositionalAfterNamed {
span: expr.span, span: expr.span,
args: args args: args
.named_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))) .filter_map(|a| a.kind.ident().map(|ident| (a, ident)))
.map(|(arg, n)| n.span.to(arg.expr.span)) .map(|(arg, n)| n.span.to(arg.expr.span))
.collect(), .collect(),
}); }));
} }
args.add(FormatArgument { kind: FormatArgumentKind::Normal, expr }); 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(()); return Err(());
} }
@ -315,6 +313,8 @@ fn make_format_args(
} }
use ArgRef::*; use ArgRef::*;
let mut unnamed_arg_after_named_arg = false;
let mut lookup_arg = |arg: ArgRef<'_>, let mut lookup_arg = |arg: ArgRef<'_>,
span: Option<Span>, span: Option<Span>,
used_as: PositionUsedAs, used_as: PositionUsedAs,
@ -353,7 +353,8 @@ fn make_format_args(
} else { } else {
// For the moment capturing variables from format strings expanded from macros is // For the moment capturing variables from format strings expanded from macros is
// disabled (see RFC #2795) // 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) DummyResult::raw_expr(span, true)
}; };
Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr })) Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr }))
@ -512,7 +513,8 @@ fn make_format_args(
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if !unused.is_empty() { let has_unused = !unused.is_empty();
if has_unused {
// If there's a lot of unused arguments, // If there's a lot of unused arguments,
// let's check if this format arguments looks like another syntax (printf / shell). // let's check if this format arguments looks like another syntax (printf / shell).
let detect_foreign_fmt = unused.len() > args.explicit_args().len() / 2; 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 // 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. // 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 { for &(index, span, used_as) in &numeric_refences_to_named_arg {
let (position_sp_to_replace, position_sp_for_msg) = match used_as { let (position_sp_to_replace, position_sp_for_msg) = match used_as {
Placeholder(pspan) => (span, pspan), Placeholder(pspan) => (span, pspan),
@ -587,7 +589,7 @@ fn invalid_placeholder_type_error(
} else { } else {
vec![] 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( fn report_missing_placeholders(
@ -602,12 +604,12 @@ fn report_missing_placeholders(
fmt_span: Span, fmt_span: Span,
) { ) {
let mut diag = if let &[(span, named)] = &unused[..] { let mut diag = if let &[(span, named)] = &unused[..] {
ecx.create_err(errors::FormatUnusedArg { span, named }) ecx.dcx().create_err(errors::FormatUnusedArg { span, named })
} else { } else {
let unused_labels = let unused_labels =
unused.iter().map(|&(span, named)| errors::FormatUnusedArg { span, named }).collect(); unused.iter().map(|&(span, named)| errors::FormatUnusedArg { span, named }).collect();
let unused_spans = unused.iter().map(|&(span, _)| span).collect(); let unused_spans = unused.iter().map(|&(span, _)| span).collect();
ecx.create_err(errors::FormatUnusedArgs { ecx.dcx().create_err(errors::FormatUnusedArgs {
fmt: fmt_span, fmt: fmt_span,
unused: unused_spans, unused: unused_spans,
unused_labels, unused_labels,
@ -632,8 +634,7 @@ fn report_missing_placeholders(
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if !placeholders.is_empty() { 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(); diag.cancel();
new_diag.emit(); new_diag.emit();
return; return;
@ -726,7 +727,7 @@ fn report_redundant_format_arguments<'a>(
args: &FormatArguments, args: &FormatArguments,
used: &[bool], used: &[bool],
placeholders: Vec<(Span, &str)>, placeholders: Vec<(Span, &str)>,
) -> Option<DiagnosticBuilder<'a, ErrorGuaranteed>> { ) -> Option<DiagnosticBuilder<'a>> {
let mut fmt_arg_indices = vec![]; let mut fmt_arg_indices = vec![];
let mut args_spans = vec![]; let mut args_spans = vec![];
let mut fmt_spans = vec![]; let mut fmt_spans = vec![];
@ -778,7 +779,7 @@ fn report_redundant_format_arguments<'a>(
None None
}; };
return Some(ecx.create_err(errors::FormatRedundantArgs { return Some(ecx.dcx().create_err(errors::FormatRedundantArgs {
n: args_spans.len(), n: args_spans.len(),
span: MultiSpan::from(args_spans), span: MultiSpan::from(args_spans),
note: multispan, note: multispan,
@ -878,14 +879,13 @@ fn report_invalid_references(
} else { } else {
MultiSpan::from_spans(spans) MultiSpan::from_spans(spans)
}; };
e = ecx.create_err(errors::FormatPositionalMismatch { e = ecx.dcx().create_err(errors::FormatPositionalMismatch {
span, span,
n: num_placeholders, n: num_placeholders,
desc: num_args_desc, desc: num_args_desc,
highlight: SingleLabelManySpans { highlight: SingleLabelManySpans {
spans: args.explicit_args().iter().map(|arg| arg.expr.span).collect(), spans: args.explicit_args().iter().map(|arg| arg.expr.span).collect(),
label: "", label: "",
kind: rustc_errors::LabelKind::Label,
}, },
}); });
// Point out `{:.*}` placeholders: those take an extra argument. // 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(", ") head = indexes.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(", ")
) )
}; };
e = ecx.struct_span_err( e = ecx.dcx().struct_span_err(
span, span,
format!("invalid reference to positional {arg_list} ({num_args_desc})"), 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)) MacEager::expr(DummyResult::raw_expr(sp, true))
} }
} }
Err(mut err) => { Err(err) => {
err.emit(); err.emit();
DummyResult::any(sp) DummyResult::any(sp)
} }

View File

@ -34,7 +34,7 @@ pub fn expand(
{ {
(item, true, ecx.with_def_site_ctxt(ty.span)) (item, true, ecx.with_def_site_ctxt(ty.span))
} else { } else {
ecx.sess.dcx().emit_err(errors::AllocMustStatics { span: item.span() }); ecx.dcx().emit_err(errors::AllocMustStatics { span: item.span() });
return vec![orig_item]; return vec![orig_item];
}; };

View File

@ -5,16 +5,14 @@
#![feature(rustdoc_internals)] #![feature(rustdoc_internals)]
#![doc(rust_logo)] #![doc(rust_logo)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(array_windows)] #![feature(assert_matches)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(decl_macro)] #![feature(decl_macro)]
#![feature(if_let_guard)] #![feature(if_let_guard)]
#![feature(is_sorted)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(lint_reasons)] #![feature(lint_reasons)]
#![feature(proc_macro_internals)] #![feature(proc_macro_internals)]
#![feature(proc_macro_quote)] #![feature(proc_macro_quote)]
#![recursion_limit = "256"]
extern crate proc_macro; extern crate proc_macro;

View File

@ -194,7 +194,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
self.dcx self.dcx
.struct_span_err(attr.span, msg) .struct_span_err(attr.span, msg)
.span_label(prev_attr.span, "previous attribute here") .with_span_label(prev_attr.span, "previous attribute here")
.emit(); .emit();
return; return;

View File

@ -107,9 +107,9 @@ pub fn expand_include<'cx>(
return DummyResult::any(sp); return DummyResult::any(sp);
}; };
// The file will be added to the code map by the parser // 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, Ok(f) => f,
Err(mut err) => { Err(err) => {
err.emit(); err.emit();
return DummyResult::any(sp); return DummyResult::any(sp);
} }
@ -146,7 +146,7 @@ pub fn expand_include<'cx>(
let mut ret = SmallVec::new(); let mut ret = SmallVec::new();
loop { loop {
match self.p.parse_item(ForceCollect::No) { match self.p.parse_item(ForceCollect::No) {
Err(mut err) => { Err(err) => {
err.emit(); err.emit();
break; break;
} }
@ -155,7 +155,7 @@ pub fn expand_include<'cx>(
if self.p.token != token::Eof { if self.p.token != token::Eof {
let token = pprust::token_to_string(&self.p.token); let token = pprust::token_to_string(&self.p.token);
let msg = format!("expected item, found `{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; break;
@ -179,9 +179,9 @@ pub fn expand_include_str(
let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_str!") else { let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_str!") else {
return DummyResult::any(sp); 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, Ok(f) => f,
Err(mut err) => { Err(err) => {
err.emit(); err.emit();
return DummyResult::any(sp); return DummyResult::any(sp);
} }
@ -193,12 +193,12 @@ pub fn expand_include_str(
base::MacEager::expr(cx.expr_str(sp, interned_src)) base::MacEager::expr(cx.expr_str(sp, interned_src))
} }
Err(_) => { 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) DummyResult::any(sp)
} }
}, },
Err(e) => { 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) 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 { let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_bytes!") else {
return DummyResult::any(sp); 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, Ok(f) => f,
Err(mut err) => { Err(err) => {
err.emit(); err.emit();
return DummyResult::any(sp); return DummyResult::any(sp);
} }
@ -226,7 +226,7 @@ pub fn expand_include_bytes(
base::MacEager::expr(expr) base::MacEager::expr(expr)
} }
Err(e) => { 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) 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::ptr::P;
use rustc_ast::{self as ast, attr, GenericParamKind}; use rustc_ast::{self as ast, attr, GenericParamKind};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_errors::Applicability; use rustc_errors::{Applicability, DiagnosticBuilder, Level};
use rustc_expand::base::*; use rustc_expand::base::*;
use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span}; use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span};
use std::assert_matches::assert_matches;
use std::iter; use std::iter;
use thin_vec::{thin_vec, ThinVec}; 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![]; return vec![];
} }
}; };
@ -182,6 +183,16 @@ pub fn expand_test_or_bench(
// creates $name: $expr // creates $name: $expr
let field = |name, expr| cx.field_imm(sp, Ident::from_str_and_span(name, sp), 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 { let test_fn = if is_bench {
// A simple ident for a lambda // A simple ident for a lambda
let b = Ident::from_str_and_span("b", attr_sp); let b = Ident::from_str_and_span("b", attr_sp);
@ -190,8 +201,9 @@ pub fn expand_test_or_bench(
sp, sp,
cx.expr_path(test_path("StaticBenchFn")), cx.expr_path(test_path("StaticBenchFn")),
thin_vec![ thin_vec![
// #[coverage(off)]
// |b| self::test::assert_test_result( // |b| self::test::assert_test_result(
cx.lambda1( coverage_off(cx.lambda1(
sp, sp,
cx.expr_call( cx.expr_call(
sp, sp,
@ -206,7 +218,7 @@ pub fn expand_test_or_bench(
], ],
), ),
b, b,
), // ) )), // )
], ],
) )
} else { } else {
@ -214,8 +226,9 @@ pub fn expand_test_or_bench(
sp, sp,
cx.expr_path(test_path("StaticTestFn")), cx.expr_path(test_path("StaticTestFn")),
thin_vec![ thin_vec![
// #[coverage(off)]
// || { // || {
cx.lambda0( coverage_off(cx.lambda0(
sp, sp,
// test::assert_test_result( // test::assert_test_result(
cx.expr_call( 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>) { 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 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 // These were a warning before #92959 and need to continue being that to avoid breaking
// stable user code (#94508). // stable user code (#94508).
Some(ast::ItemKind::MacCall(_)) => dcx.struct_span_warn(attr_sp, msg), Some(ast::ItemKind::MacCall(_)) => Level::Warning,
// `.forget_guarantee()` needed to get these two arms to match types. Because of how _ => Level::Error,
// 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(),
}; };
let mut err = DiagnosticBuilder::<()>::new(dcx, level, msg);
err.span(attr_sp);
if let Some(item) = item { if let Some(item) = item {
err.span_label( err.span_label(
item.span, 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") 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")
.span_suggestion(attr_sp, .with_span_suggestion(attr_sp,
"replace with conditional compilation to make the item only exist when tests are being run", "replace with conditional compilation to make the item only exist when tests are being run",
"#[cfg(test)]", "#[cfg(test)]",
Applicability::MaybeIncorrect) Applicability::MaybeIncorrect)
@ -466,8 +478,6 @@ fn should_ignore_message(i: &ast::Item) -> Option<Symbol> {
fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
match attr::find_by_name(&i.attrs, sym::should_panic) { match attr::find_by_name(&i.attrs, sym::should_panic) {
Some(attr) => { Some(attr) => {
let dcx = cx.sess.dcx();
match attr.meta_item_list() { match attr.meta_item_list() {
// Handle #[should_panic(expected = "foo")] // Handle #[should_panic(expected = "foo")]
Some(list) => { 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.meta_item())
.and_then(|mi| mi.value_str()); .and_then(|mi| mi.value_str());
if list.len() != 1 || msg.is_none() { if list.len() != 1 || msg.is_none() {
dcx.struct_span_warn( cx.dcx()
attr.span, .struct_span_warn(
"argument must be of the form: \ attr.span,
"argument must be of the form: \
`expected = \"error message\"`", `expected = \"error message\"`",
) )
.note( .with_note(
"errors in this attribute were erroneously \ "errors in this attribute were erroneously \
allowed and will become a hard error in a \ allowed and will become a hard error in a \
future release", future release",
) )
.emit(); .emit();
ShouldPanic::Yes(None) ShouldPanic::Yes(None)
} else { } else {
ShouldPanic::Yes(msg) ShouldPanic::Yes(msg)
@ -535,7 +546,7 @@ fn check_test_signature(
f: &ast::Fn, f: &ast::Fn,
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic); 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 { if let ast::Unsafe::Yes(span) = f.sig.header.unsafety {
return Err(dcx.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" })); 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 // N.B., inadequate check, but we're running
// well before resolve, can't get too deep. // well before resolve, can't get too deep.
if f.sig.decl.inputs.len() != 1 { 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(()) Ok(())
} }

View File

@ -21,7 +21,7 @@ pub fn expand_trace_macros(
}; };
err |= cursor.next().is_some(); err |= cursor.next().is_some();
if err { if err {
cx.emit_err(errors::TraceMacros { span: sp }); cx.dcx().emit_err(errors::TraceMacros { span: sp });
} else { } else {
cx.set_trace_macros(value); cx.set_trace_macros(value);
} }

View File

@ -12,7 +12,7 @@ pub fn expand_type_ascribe(
) -> Box<dyn base::MacResult + 'static> { ) -> Box<dyn base::MacResult + 'static> {
let (expr, ty) = match parse_ascribe(cx, tts) { let (expr, ty) = match parse_ascribe(cx, tts) {
Ok(parsed) => parsed, Ok(parsed) => parsed,
Err(mut err) => { Err(err) => {
err.emit(); err.emit();
return DummyResult::any(span); return DummyResult::any(span);
} }

View File

@ -33,14 +33,14 @@ jobs:
TARGET_TRIPLE: x86_64-pc-windows-gnu TARGET_TRIPLE: x86_64-pc-windows-gnu
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: CPU features - name: CPU features
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
run: cat /proc/cpuinfo run: cat /proc/cpuinfo
- name: Cache cargo target dir - name: Cache cargo target dir
uses: actions/cache@v3 uses: actions/cache@v4
with: with:
path: build/cg_clif path: build/cg_clif
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} 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